One deployable, many modules
Voyant is assembled from domain modules — catalog, commerce, inventory, operations, bookings, finance, and the rest. They are components of one resident Node application, not separately deployed services. A module owns four things:- Its data model — the tables holding the canonical state of its domain.
- Its services — the domain logic that enforces that domain’s rules.
- Its routes — thin HTTP handlers that validate, call a service, and shape a response.
- Its background work — the subscribers and jobs its behavior requires.
-contracts package (the wire types shared by server and client) and a -react package (hooks and components built on those contracts). That is why the SDK types match the API exactly: both sides import the same contract.
Why cross-domain reads look the way they do
Inside a module you get ordinary relational modeling: real foreign keys, constraints, relations. Across modules you do not. A booking does not carry a foreign key into the CRM’s tables; it carries a plain id, and the association is declared as a link. Reads stitch across modules in application code through the query graph rather than through joins. This is why the API returns ids where you might expect embedded objects, and why some reads are composed rather than single queries. The reason is packaging: a hard cross-package foreign key would force every deployment to install both sides.Where the seams are
Four seams, in the order you should reach for them:
Automations are not a seam. They run on your infrastructure, calling the API and reacting to webhooks.
Composition happens at build time
A deployment is a versioned, declarative package graph resolved at build time and lowered to one application. The project declares only its differences from the standard product; everything else comes from the versioned distribution. Provider bindings resolve at boot inside that fixed graph. The practical consequence: upgrading is a version bump plus migrations, not a code merge. See Configuration.Architecture
The runtime, the request lifecycle, and the tenancy model.
Build on Voyant
The part you actually work with.