ADR-0005: Modules as packages bound by one contract and unlocked by entitlements
Every module, first-party or third-party, exports a ModuleManifest; the registry is the single source of what loads, tables live only in packages/database, and entitlements gate access.
ADR-0005: Modules as packages bound by one contract and unlocked by entitlements
- Date: 2026-09-18
- Status: Proposed (seed — awaiting the owner's approval)
- Deciders: the owner, Claude (seed)
- Tags:
domainstrategy
Context
To prevent fragmentation there must be exactly one way to add a feature, and the Marketplace itself must be a natural extension of the internal modules.
Decision
Every module (first-party or third-party) exports a ModuleManifest (packages/core/src/module-contract.ts) that declares: identity, requirements, entitlements, routes, settings schema, and events. The job, webhook, Copilot-tool, sector-hook and marketplace fields were removed in ADR-0010, which narrowed the contract to what a loaded module actually uses.
modules/registry(@repo/module-registry) is the single source of what gets loaded.- Tables are defined in
packages/databaseonly; no module owns a private schema. - An entitlement unlocks a module; both the plan and an add-on are sources of entitlements.
Consequences
- Positive — adding a module means adding a package without touching the core; the Marketplace works by the same mechanism.
- Negative — the strictness may feel excessive for a small team at the start.
- Revenue impact (SAR / month, confidence) — R4 (Marketplace) is only possible with this contract (≈ 18,000 at 1,000 merchants, low confidence).
Rejected alternatives
- Features built directly into the core: reintroduces fragmentation and blocks the Marketplace.
- Plugins in a different language or runtime: premature security complexity.
References
ADR-0004: Custom domains via Cloudflare for SaaS, dashboard on the core domain
Tenant storefronts are served on custom hostnames through Cloudflare for SaaS by the planned storefront app; the dashboard stays isolated on app.example.com.
ADR-0006: Simplified invoicing in the core, full accounting as an add-on
The core generates and stores a ZATCA simplified invoice for every payment; full accounting is a Marketplace add-on delivered by an embedded partner first.