@voyant-travel/legal, a headless module with Drizzle schema, validation, services, and Hono routes for both admin and public surfaces.
Key concepts
These terms come from the glossary. Legal owns the documents and rule sets behind them.- Contract. A signed legal document instance bound to a Booking, Quote Version, Program, Product, supplier or channel relationship, or explicit provider reference.
- Contract Template. A reusable contract form with variable placeholders, rendered per instance.
- Signature. A record of a Contract being signed (signer, method, IP, timestamp).
- Policy. A scoped rule set (cancellation, payment, terms and conditions, guarantee, commission); versioned.
- Policy Version. An immutable snapshot of a Policy’s rules, either
publishedorretired. - Policy Acceptance. A recorded confirmation that a Person or Booking accepted a specific Policy Version.
- PII. Personally Identifiable Information. Reads and writes to PII fields are audit-logged.
Accept, Issue, and Sign are distinct. A customer accepts a Policy Version or a Quote Version; you issue a Contract to produce the artifact; a signer adds a Signature. Accepting required terms is not the same as a fully executed contract.
What it owns
Legal owns two barrels, contracts and policies, each with its own schema, service, validation, and routes.Contracts
The contract entities (with TypeID prefixes) are contracts (cont), contract templates (ctpl) with variable schemas and optional channel scope, contract template versions (ctpv, immutable snapshots), contract signatures (ctsi), contract number series (ctns) with auto-increment, and contract attachments (ctat) for rendered PDFs and appendices.
The contract lifecycle is enforced by the contract service:
stageHistory and, when an event bus is configured, emits a deliberately minimal domain event (contract.issued, contract.sent, contract.signed, contract.executed, or contract.voided). Event payloads carry contract ids, relationship ids, stage names, and timestamps only. Rendered bodies, variables, metadata, and signature details stay out of the event payload.
Default storefront templates
A contract template can be markedisDefault: true. At most one default may exist for a given (scope, channelId, language) selector. A default with channelId: null is the global fallback for that scope and language; a channel-specific default wins when callers pass a channelId. Storefronts resolve the active customer-safe template through the default-template routes, which check requested and fallback languages in order, prefer channel-specific defaults, ignore inactive templates, and only fall back to the newest active matching template when no explicit default exists.
Document operations
The contract routes expose stable operations for storefront previews and stored document handling: render-preview routes (by id or by slug) that accept{ variables } and return only the rendered text, an attach-document route that uploads a multipart file through the configured documentStorage and persists a contract attachment, and a regenerate-pdf route that replaces the canonical generated document artifact through the configured generator. Public preview routes require the template to be active.
Policies
The policy entities are policies (pol) by kind, policy versions (plvr, immutable snapshots with a publish and retire lifecycle), policy rules (plrl, structured rules per version such as cancellation windows and percentages), policy assignments (plas, scope-based assignment to products, channels, or markets), and policy acceptances (plac, acceptance records per booking, order, or person).
A policy is assigned by scope and evaluated structurally, so a Cancellation Policy is an ordered rule set defining refund percentages by cutoff window, not free text. A Policy Acceptance binds a specific, immutable Policy Version to a Person or Booking, which is what makes consent auditable later.
Working with it
Register the module:Links to other modules
- Bookings and Quotes. A Contract binds to a Booking, Quote Version, or Program, and a Policy Acceptance binds to a Booking or Person. Legal stays decoupled and references these through links and ids.
- Distribution. Templates and policies can be scoped to a channel, so storefront default-template resolution and policy assignment respect channel context.
- Finance. A cancellation Policy’s refund windows inform what finance refunds or credits; legal owns the rule set, finance owns the money. See Finance.
- Notifications. The booking document bundle sends the latest customer-facing contract attachment alongside invoice and proforma renditions. See Notifications.
React package
@voyant-travel/legal-react provides hooks, a client, query keys, reusable UI, and admin surfaces for contracts and policies.
./hooks, ./client, ./query-keys, ./ui, ./admin, and ./components/*) so an app can drop in the contract editor, signing surfaces, and the policy rule editor without reimplementing the data layer.
Next steps
Finance
Invoices, credit notes, and the refund math behind cancellation policies.
Notifications
Deliver contracts and policy documents over multiple channels.
Modules
The full catalog of domain modules and how they link.
Glossary
The legal and compliance vocabulary, including PII handling.