# API overview :::info[TODO] Describe the API conventions: base URL, authentication, filtering, sorting, paging, relations and errors. The full endpoint reference will be generated from the Vox OpenAPI document. Tell Claude where the OpenAPI JSON is served, or add it to the repo, and it will be wired in. ::: List entities Get one entity --- # Changelog Vox is in development and not yet used in production. :::info[TODO] Add one section per release, newest first, using `templates/changelog-entry.md`. ::: --- # Calculations :::info[TODO] Explain calculated properties, how Vox tracks dependencies and recalculates when something changes, and `RecalculateAt`. ::: --- # Languages, markets and channels :::info[TODO] Explain how values vary by context (for example a name per language), and how entities belong to contexts (for example the products in the web shop). ::: ## Calculated context memberships Vox determines candidate contexts separately for every entity/context type pair. If inheriting relation paths exist, only the contexts reached through those relations are candidates. If a membership calculation exists without a relation path, every stored entity of the context type is a candidate. There can be one `IVoxContextMembershipCalculation` for each pair. This makes it possible to use relations for one context and calculations alone for another. For example, products can have explicit web/app channel relations while their market memberships are inferred from price and inventory data: ```csharp public class ProductMarketMembership : IVoxContextMembershipCalculation { public Task IsMemberAsync( Product product, Market market, IVoxCalculationContext context, CancellationToken cancellationToken) { return Task.FromResult( product.PriceMarketIds.Contains(market.Id) && product.InventoryMarketIds.Contains(market.Id)); } } ``` Because `Product` has no inheriting relation path to `Market`, Vox tests every stored market. Creating, updating or deleting a market triggers these calculated-only memberships again. If a Product-to-Market path is later added, Vox automatically switches the pair to relation-derived candidates and the same calculation narrows that candidate set. The next example assumes a relation-derived product/market membership and keeps it only while the product is published. `RecalculateAt` records the boundaries at which the answer may change; Vox schedules durable recalculations even when the current result did not change. ```csharp public class PublishedProductMarketMembership(TimeProvider timeProvider) : IVoxContextMembershipCalculation { public Task IsMemberAsync( Product product, Market market, IVoxCalculationContext context, CancellationToken cancellationToken) { if (product.PublishedFrom is { } publishedFrom) { context.RecalculateAt(publishedFrom); } if (product.PublishedTo is { } publishedTo) { context.RecalculateAt(publishedTo); } var now = timeProvider.GetUtcNow().UtcDateTime; return Task.FromResult( (product.PublishedFrom == null || product.PublishedFrom <= now) && (product.PublishedTo == null || now < product.PublishedTo)); } } ``` Membership calculations can also depend on the stored memberships of related entities. The batch read records a dependency for every supplied entity, including those with no current membership, so creating or removing a membership later triggers the calculation again. ```csharp public class BundleMarketMembership : IVoxContextMembershipCalculation { public async Task IsMemberAsync( Bundle bundle, Market market, IVoxCalculationContext context, CancellationToken cancellationToken) { var products = await context.LoadRelatedAsync(bundle, cancellationToken); var marketIdsByProduct = await context.GetContextIdsAsync(products, cancellationToken); return products.Any(product => marketIdsByProduct[product.Id].Contains(market.Id)); } } ``` `RecalculateAt` is available to ordinary calculated-property calculations as well. Local `DateTime` values are converted to UTC, unspecified values are treated as UTC, past instants are ignored, and only the earliest future instant requested by a run is retained. --- # Entities and relations :::info[TODO] Explain entity types, fields, relations and inheriting relation paths. Show how an entity type is described in code. ::: --- # Events and subscriptions :::info[TODO] Explain events, subscriptions and filters, and the transports: webhooks, message queues (RabbitMQ) and streams. ::: --- # History and audit :::info[TODO] Explain versions, the audit log and how to read history through the API and admin UI. ::: --- # Owned and mirrored data :::info[TODO] Explain owned data (changed through actions, with checks against overwrites) and mirrored data (imported as it changes, in the source system's format). Show one entity with parts from several sources, each with its own owner. ::: --- # Users, roles and permissions :::info[TODO] Explain built-in users vs. an external identity provider, roles, and permissions per field, language and channel. ::: --- # Run the demo `src/engine/Vox.Demo` is a small shop built on Vox: products aggregated from a PIM and an ERP, prices and stock, categories in several languages, campaigns, stores, and users with different roles. Run it and open the admin UI at `https://localhost:7301/vox/admin/`, signing in as `admin@example.com` with the password `vox-demo-admin`. ```bash dotnet run --project src/engine/Vox.Demo ``` The admin UI is in `src/admin-ui`, and the engine is in `src/engine`. :::info[TODO] Add what to try in the demo: a short tour of the admin UI, an API call and an event. ::: --- # Your first entity type :::info[TODO] Walk through describing one entity type (for example `Product`) in code, and what Vox gives you for it: storage, API endpoints, admin UI, history and events. End with links to the concept pages. ::: --- # Add Vox to your application :::info[TODO] Describe how to add Vox to an existing .NET application: - Prerequisites (.NET version, database) - Which NuGet packages to install, and from which feed - How to register Vox in `Program.cs` - How to open the admin UI and check that it runs Use `` for the numbered steps. See `templates/guide.md`. ::: --- # Build a UI with AI on top of Vox :::info[TODO] Write this guide using `templates/guide.md`. Goal: let an AI tool build the UI while Vox provides the data layer. ::: --- # Add a business rule as a calculation :::info[TODO] Write this guide using `templates/guide.md`. Goal: move a rule out of a CMS or PIM and into a Vox calculation. ::: --- # Import data from another system :::info[TODO] Write this guide using `templates/guide.md`. Goal: mirror data from a PIM, ERP or other source system into Vox. ::: --- # Prototype without code :::info[TODO] Write this guide using `templates/guide.md`. Goal: add entity types and fields while the system runs, then move the model to code. ::: --- # Introduction It can own your business data, mirror data that other systems own, or do both. Whatever the source, the data is available to everything that needs it, through APIs and events. Run the demo shop and add Vox to your own application. Entities, owned and mirrored data, calculations, contexts and events. Step-by-step instructions for common tasks. Endpoints for every entity type. ## What Vox does Vox is a .NET engine that you host as part of your own application. You describe your entities, such as products, categories, prices, stores and campaigns, and Vox takes care of what every entity needs: - **Storage, an API and an admin UI** for every entity type, with filtering, sorting, relations and search. - **Data it owns and data it mirrors**, side by side. Data that Vox owns is changed through actions, with checks that stop two people from overwriting each other's changes. Data that other systems own is imported as it changes, in the format the other system already uses. - **One entity from several sources.** A product can get its texts from the PIM, its prices from the ERP and its availability from a calculation in Vox. Each part has its own owner. - **Business logic as calculations.** For example, whether a product can be sold in a market, based on the product, its categories, the prices, the stock and the market itself. Vox keeps track of what each calculation depends on, and recalculates when any of it changes. - **Events and subscriptions.** Other systems are told what changed, through webhooks, message queues or streams, filtered to what each one needs. - **Languages, markets and channels.** Values can vary by context, such as a name per language, and entities can belong to contexts, such as the products in the web shop. - **History and audit.** Who changed what and when, version by version. - **Users, roles and permissions.** Vox can hold the users itself, or let them sign in with your existing identity provider. Permissions go down to which fields a role may edit, in which languages or channels. - **Prototyping without code.** Entity types and fields can be added while the system is running, so people who don't write code can shape a new app together. Once the app takes shape, the model is moved to code. Vox is built on Nexus, which runs its imports, calculations and events as queues and jobs that can be followed, retried and run again. ## Learn more - [Why Vox exists](./why-vox.md) - [Who Vox is for](./who-its-for.md) --- # Configuration :::info[TODO] List every configuration option in a table: name, type, default and description. ::: --- # Hosting :::info[TODO] Describe hosting requirements and a recommended setup. Vox is not a hosted service; it runs in your own application against your own database. ::: --- # Storage and infrastructure :::info[TODO] Describe the supported building blocks (Entity Framework, Elasticsearch, Redis, RabbitMQ): what each is for, when it is needed and how to configure it. ::: --- # Who Vox is for - **Developers and architects** who need a data layer for a new app, a new integration, or a system they're building themselves, and don't want to rebuild storage, APIs, imports and events every time. - **People building with AI**, who want the AI to focus on the UI and the experience on top of data that's already shared, structured and connected. - **Product owners and business people** who prototype a new app in a shared environment, or who manage the data that Vox owns in its admin UI. - **Analysts** who want business data, including the calculated parts, in one place for reports and BI. ## What Vox isn't Vox is the data layer. Many things can be built on top of it, but it isn't those things itself: - **Not a CMS, a PIM or a storefront out of the box.** You can build those on top of Vox, but Vox doesn't come with the editing experience or the shop. - **Not a backend for a specific front end.** Vox stops at the entity. Shaping data for a particular app, such as a product page with its categories and prices in one response, is the job of the application that serves it. - **Not an integration platform.** Vox takes in imports and sends out changes, but it doesn't orchestrate or transform other systems' data on their behalf. - **Not a search engine.** It can use Elasticsearch for its queries, and can feed search, but searching for the shop is a separate concern. - **Not a no-code platform for production.** Changing the model while the system runs is for prototyping. The model in code is what counts. - **Not a hosted service.** Vox runs in your own .NET application, against your own database. --- # Why Vox exists Business data tends to end up locked inside the systems that happen to handle it. A few situations Vox is meant to fix: **Business logic trapped in a proprietary system.** A company builds its rules into its CMS or PIM, such as which products can be sold where or what's shown in which channel. Those rules then depend on the system, so replacing it becomes a large project. With Vox, the data from the CMS or PIM flows into Vox. The business logic lives in Vox as calculations that can also draw on data from other systems, such as prices from the ERP or stock from the warehouse. The CMS and PIM go back to doing what they're good at, and can be replaced without taking the business logic with them. **An AI-built app that had to be rebuilt.** A company used an AI tool to build a system it needed. It worked, but it had its own storage and its own integrations, completely outside the company's existing data and processes, so it had to be rebuilt from scratch. With Vox, the AI could have built a good UI on top of a data layer that's already part of the company. The internal developers would then only have to finish the last 20%, the models and the integrations, instead of starting over. **Building your own PIM.** With AI, building your own PIM, or other software for e-commerce and retail, is suddenly realistic. But building everything from scratch still isn't a good idea. Vox provides many of the fundamentals such a system needs: entities and relations, data from several sources in one place, values that vary by language or market, validation, history, permissions, an API, events and an admin UI. You build the parts that make your system yours. ## Where it's going The goal is a data layer that a commerce or retail business can put at the centre of its systems, so that: - **Data is never locked in.** Each system does what it's good at, and the data and the business logic around it live in a place everyone can reach. - **New things are quick to build.** A new app, an internal tool or a UI built with AI starts from data and rules that already exist, instead of from an empty database. - **Prototypes don't have to be thrown away.** Something that starts as a prototype, shaped by the people who need it, can grow into a production system without being rewritten. - **Systems can be replaced.** Changing the PIM, the ERP or the CMS shouldn't mean rebuilding the business around it. - **The data is easy to use well.** It's available, documented and up to date, for apps, for integrations, and for the reports that the business runs on. Vox is meant to get you started quickly and then step aside. The defaults are there so you don't have to build them, and each part can be replaced with your own as your needs grow, one piece at a time.