System Design
The whole platform in one place: one package, fourteen core modules across nine domains, the contract spine, the adapter ports, the async seams.
Introduction
One published package, @openora/core. Fourteen core modules across nine domains, plus one gated add-on. The contract spine, the plugin host, twenty-four adapter ports, three async seams, and how a consumer overlays proprietary code on top.
The numbers below come from docs/catalog.json: 15 registered modules (14 core, 1 add-on), 24 adapter ports, 49 domain events, 115 HTTP routes including health.
The whole system
Distribution model
@openora/core ships under one fixed version - no cross-domain version skew. A consumer installs the one package; its subpaths expose every module. The runtime contract is composed only in the consumer's createApp() call, via composeContract - that is what keeps every subset independently usable.
Ports and adapters
AUDIT_WRITER is a sealed token - it can be bound once, by its owning module, and never rebound by an overlay. It is the only sealed identity with a live implementation today; the rest of the sealed list is a set of documented regulatory placeholders.
Money and event lifecycle
Reference: domain, modules, tables, routes
Route counts come from docs/catalog.json - 115 routes in total, health included.
| Domain | Modules | Tables | Routes |
| ----------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------- | ------ |
| @openora/core/iam | iam (admin roles, perms, invites) | admin_role / admin_role_assignment / admin_role_permission / admin_invitation | 16 |
| @openora/core/audit | audit (append-only log) | audit_log | 2 |
| @openora/core/admin-console | backoffice read API | owns none - reads via ADMIN_USER_DIRECTORY + ADMIN_WALLET_REPORTING | 6 |
| @openora/core/pam | identity, profile, player-note, tag, player-management | user / session / account / twoFactor / verification, player, player_note, tag | 31 |
| @openora/core/compliance | compliance (RG, KYC, geo) | geo_rule, user_limit | 15 |
| @openora/core/wallet | wallet | wallet, wallet_transaction, auto_withdrawal_rule | 11 |
| @openora/core/casino | gaming, lobby | Game / GameRound, LobbyCategory / FeaturedSlot | 9 |
| @openora/core/engagement | chat, notifications | ChatRoom / ChatMessage, notification | 14 |
| @openora/core/cms | cms | page / banner | 10 |
player-management is the gated add-on inside pam; it loads only when listed in the OSS_ADDONS allowlist, and accounts for 7 of that domain's 31 routes.
Cross-domain edges
Every edge below is lint-enforced by two independent gates: fast import linting on each edit, and a whole-graph dependency check that also catches transitive edges, barrel laundering, and dynamic imports.
| From to To | Channel |
| --------------------------- | -------------------------------------------------------------- |
| iam to identity | dependsOn (load order) |
| gaming to wallet | WALLET_COMMANDS synchronous command port (same tx, atomic) |
| player-management to profile | read-only @openora/core/pam/schema |
| lobby to gaming | read-only @openora/core/casino/schema |
| any to any | domain events via EventBus (49 topics) - never money |
Twenty-four adapter ports and three async seams - MESSAGE_BROKER, JOB_QUEUE, REALTIME_TRANSPORT - plus the transactional OUTBOX carry everything else. Money and needed-now reads stay synchronous and transactional; nothing else imports another module's internals.