Code Structure And Layer Model designed
This page explains how the codebase is supposed to be read and extended. The goal is simple: engineers should know where a change belongs before they start editing.
The Three Core Code Layers
Layer rule
sharedis technical plumbing.platformowns reusable business authority.productsown customer-facing domain semantics.
What Lives In Each Layer
packages/shared
Use this layer for boring technical primitives:
- error envelopes;
- middleware;
- event helpers;
- outbox primitives;
- DB helpers;
- PKI interfaces;
- generated transport artifacts;
- storage/path/read-cache utilities.
Do not put product policy, billing rules, IAM semantics, or registry logic here.
packages/platform
Use this layer for reusable platform authority:
- IAM / access;
- billing / metering / payments;
- audit / evidence;
- status / ops posture;
- notification;
- registry / artifacts;
- secrets / PKI coordination;
- policy / entitlements.
If a second product should consume the capability without copying business logic, it probably belongs here.
packages/products
Use this layer for product-owned domain behavior:
- GPU inventory and SKUs;
- allocations and provisioning;
- terminal runtime behavior;
- product storage surfaces;
- app catalog and runtime;
- Token Factory product behavior.
Products compose platform services. They do not own the platform's reusable IAM, billing, audit, or policy truth.
Repo Shape
cmd/ entrypoints and thin route/binary wiring
packages/shared/ technical primitives only
packages/platform/ shared platform business domains
packages/products/ product-owned business domains
doc/api/ contract-first REST and event authority
doc/architecture/ deeper design packets and ownership maps
scripts/ci/ portable validation gates
scripts/ops/ operational harnesses and controlled runbook helpers
packages/web/ Next.js product UI
packages/docs/ Docusaurus documentation portal
Binary And Runtime Layers
| Layer | Current shape | What belongs there |
|---|---|---|
| Public control plane | cmd/api | Public/admin HTTP routes, auth/session validation, thin handler wiring |
| Background workers | cmd/billing-worker, cmd/provisioning-worker, cmd/webhook-worker, cmd/notification-relay, cmd/outbox-relay | Asynchronous domain reactions and scheduled work |
| Edge runtime support | cmd/terminal-gateway | Dedicated runtime path for terminal sessions |
| Node runtime | cmd/node-agent | Pull-based host-side execution under typed task contracts |
| User/operator CLI | cmd/gpuaas-cli | Contract-first control client, not hidden admin backdoor |
Route Ownership Model
Route files in cmd/api are still the public API shell, but business logic
should move into the owning domain package.
Examples:
routes_platform_*for reusable platform capabilities;routes_gpuaas_*for GPUaaS product behavior;routes_appplatform_*for app platform behavior;routes_tokenfactory_*for Token Factory behavior.
Rule
cmd/api should become thinner over time. It is wiring and HTTP surface, not
the long-term owner of domain behavior.
Data Ownership Model
Schema ownership follows the same split:
- IAM/access tables are platform-owned;
- billing/ledger tables are platform-owned;
- allocation/node/runtime tables are GPUaaS-owned;
- app runtime/catalog tables are app-platform-owned.
If two domains need the same data, the answer is read models, APIs, or events. The answer is not casual cross-domain joins.
How To Decide Where A Change Belongs
| If the change is about... | Start in... | Why |
|---|---|---|
| Auth, membership, service accounts, scopes, tenant/project authority | packages/platform/iam | shared access authority |
| Ledger, metering, payment state, financial attribution | packages/platform/billing or packages/platform/payments | reusable money system |
| Audit trail, evidence bundles, release posture | packages/platform/audit, packages/platform/evidence, packages/platform/statusops | reusable control-plane governance |
| GPU capacity, allocations, terminal, node lifecycle | packages/products/gpuaas/* | product-owned runtime behavior |
| App manifests, app instances, SDK/runtime adapters | packages/products/appplatform/* | product-owned app surface |
| General middleware, error helpers, outbox, events | packages/shared/* | technical primitive, not business owner |
What This Means For Engineers
Before editing code, an engineer should be able to answer:
- Which contract changes first?
- Which route family owns the surface?
- Which package owns the business decision?
- Which table family owns the data?
- Which worker or async path consumes the change?
If those answers point to more than one owner, the change probably needs a platform/product boundary decision first.
Common Mistakes To Avoid
- putting policy or IAM semantics in
shared; - letting product code query platform-owned tables directly;
- hiding business logic inside
cmd/apihandlers; - adding a new product-specific copy of billing, audit, or notification logic;
- treating deployment separation as the first architecture move instead of ownership separation.
Deployment View
The near-term target is still a modular monolith plus workers, not forced microservices.
The architecture rule is:
separate ownership before separating deployment.
That keeps the repo easy to reshape while contracts, guards, and read models are still stabilizing.