Registry modules should feel like they came from one SaaS system. These conventions keep source modules composable.
Default table fields should be consistent:
idownerIdororganizationIdwhen user/workspace scopedcreatedAtupdatedAtwhen mutabledeletedAtwhen soft deletion is supportedcreatedBywhen operator attribution mattersstatusmetadatasourcefor provider/import originexternalIdfor provider-owned identifiers
Use plain lifecycle names that can be shared across modules:
draftpendingactivepausedarchivedfailedcompletedcancelled
Provider-specific status values should be mapped behind adapter code before they reach source-owned product modules.
Events should include:
typeactorIdorganizationIdtargetTypetargetIdsourcemetadatacreatedAt
Use namespaced event types such as api_key.created, webhook.delivery_failed, billing.invoice_paid, and support.ticket_escalated.
Money values should be stored as integer minor units with a currency code. Credit ledgers should use signed integer amounts, reason codes, actor attribution, and reconciliation metadata.
Tenant-scoped modules must make the tenant boundary explicit in schema, queries, route handlers, and tests. Cross-tenant admin flows should live behind operator permissions and audit events.