# Schema Ownership Map (Platform Foundation)

Status: draft (Phase A artifact, PF-MAP-SCHEMA)
Owner: Platform Architecture
Last updated: 2026-06-01

## Purpose

Make table ownership explicit before report-only schema and import-boundary
guards are introduced.

This map does not rename tables. Existing table names are retained during the
production-readiness phase. New production tables should use the owner-visible
prefixes defined in `Platform_Code_And_Deployment_Architecture_v1.md`
(`platform_*`, `gpuaas_*`, `appplatform_*`) unless there is a documented
compatibility reason not to.

## Source docs reviewed

- `doc/architecture/db_schema_v1.sql`
- `doc/architecture/ERD.md`
- `doc/architecture/Seed_Data_Spec.md`
- `doc/architecture/platform-foundation/Platform_Shared_Services_Model_v2.md`
- `doc/architecture/platform-foundation/Platform_Code_And_Deployment_Architecture_v1.md`
- `doc/architecture/platform-foundation/ownership-maps/package-ownership.md`

## Ownership rules

1. A package queries only tables owned by its domain.
2. Cross-domain reads use APIs, explicit read models, or events.
3. Shared read models are owned by the domain that publishes them.
4. Redis/read-cache keys are performance artifacts, not ownership boundaries.
5. Existing legacy tables can stay physically shared while guards report direct
   cross-domain access and new schema follows owner-visible naming.
6. Financial, audit, outbox, policy, credential, and evidence tables are
   platform-owned even when product flows are the first writers.

## Table families

| Table family | Tables | Current owner | Target owner | Guard rule |
|---|---|---|---|---|
| Organization, project, membership | `organizations`, `projects`, `tenant_memberships`, `project_memberships`, `user_project_defaults` | IAM / tenancy in `packages/platform/auth`, `packages/platform/iam`, and `cmd/api` | Platform IAM / Access | Product packages read through IAM/access APIs or read models, not direct joins |
| User identity and federation | `users`, `user_identity_links`, `account_sessions`, `tenant_identity_providers`, `tenant_federation_domain_bindings`, `auth_federation_states` | IAM | Platform IAM / Access | Direct writes stay in IAM facade; products consume principal/project context |
| Role and authorization bindings | `role_definitions`, `role_definition_versions`, `platform_role_bindings`, `tenant_role_bindings`, `project_role_bindings` | IAM / authz helpers | Platform IAM / Access | Authorization decisions go through IAM/authz facade; no product-owned RBAC tables |
| User access material | `user_ssh_public_keys`, `platform_iam_user_posix_identities` | GPUaaS access runtime plus IAM | Split: identity metadata in Platform IAM, node login projection in GPUaaS terminal/provisioning | Guard flags direct use from billing/app runtime; terminal/provisioning may consume via explicit contract |
| Service accounts and credentials | `service_accounts`, `service_account_credentials` | App/runtime and IAM-adjacent API code | Platform IAM / Secrets | App Platform requests scoped service accounts through platform contract |
| Platform access credentials | `access_credentials`, `access_credential_bindings` | Ops/security runtime metadata | Platform Secrets / PKI | Credential custody metadata is platform-owned; products reference credential IDs only |
| SKU and capacity catalog | `sku_catalog`, `node_family_versions`, `provider_capacity_inventory`, `provider_resources`, `os_images` | Inventory/catalog | GPUaaS inventory | Billing and UI use product-published read models or registry entries |
| MAAS site and deploy policy | `maas_sites`, `maas_site_policies`, `maas_site_profiles`, `maas_power_credential_overrides`, `maas_roce_assignments`, `maas_discovery_candidate_reviews` | MAAS/provisioning | GPUaaS provisioning / MAAS | Platform Secrets owns credential custody; product owns site policy and node lifecycle semantics |
| Node lifecycle and state | `nodes`, `node_image_cache`, `node_resource_slots`, `node_onboardings`, `node_onboarding_events`, `node_decommissions`, `node_decommission_events`, `node_maas_state`, `node_agent_lifecycles`, `node_tasks` | Provisioning/node-agent | GPUaaS node lifecycle / provisioning | Status/Ops consumes events/read models; no platform package mutates node state directly |
| Allocation and placement | `allocations`, `allocation_ssh_public_keys`, `allocation_access_grants`, `allocation_resource_claims`, `allocation_runtime_bundles` | Provisioning/terminal/runtime | GPUaaS provisioning and terminal | Billing consumes usage events/read models; terminal consumes allocation session contract |
| App catalog and app entitlements | `app_catalog`, `app_versions`, `project_app_entitlements` | App Platform seed/runtime code | App Platform catalog / SDK | Backend seed assumptions should move toward SDK-visible manifests and validators |
| App runtime instances | `app_instances`, `shared_app_runtimes`, `shared_app_runtime_attachments`, `shared_app_runtime_workers`, `shared_app_runtime_worker_operations`, `shared_runtime_operator_credentials`, `app_instance_proxy_routes`, `app_instance_members`, `app_instance_member_operations` | App runtime controllers | App Platform runtime | Platform IAM, artifacts, billing, and audit are composed through platform contracts |
| App artifacts and publish flow | `app_artifacts`, `app_artifact_publish_intents` | App Platform runtime/artifact scripts | App Platform artifacts over Platform Artifacts | Artifact trust state is platform-owned; app-specific publish intent is product-owned |
| Usage and rating | `usage_records`, `rated_usage_lines`, `billing_fx_rate_snapshots`, `pricing_plans`, `pricing_plan_versions`, `subscriptions` | Billing worker/service | Platform Billing / Metering | Products emit usage intent/events; billing owns rating and plan tables |
| Ledger and finance | `ledger_entries`, `refund_requests`, `stripe_events`, `payment_sessions`, `payment_disputes`, `billing_provider_customers`, `billing_accounts`, `billing_reconciliation_runs`, `billing_tax_profiles`, `invoice_headers`, `invoice_lines`, `financial_restrictions` | Billing/payments | Platform Billing / Payments | Immutable ledger rule is blocking; products never write finance tables directly |
| Budgets | `budget_policies`, `budget_events` | Billing/admin | Platform Billing / Entitlements | Products consume budget state through billing/entitlement read models |
| Audit and operator acknowledgement | `platform_audit_logs`, `platform_status_admin_ack_suppressions`, `gpuaas_provisioning_attention_reviews` | API/admin/provisioning | Platform Audit / Evidence with product-specific review records | Privileged mutations write audit through platform audit facade; review records remain product-owned if they encode product workflow |
| Idempotency | `platform_api_idempotency_keys` | API middleware/handlers | Platform API foundation | Shared platform primitive; product handlers use standard idempotency wrapper |
| Outbox | `platform_outbox_events` | Shared outbox relay | Shared outbox infrastructure with event ownership by producing domain | Outbox table is shared infrastructure; event subject and payload ownership stay with producing domain |
| Policy | `platform_policy_definitions`, `platform_policy_values`, `platform_policy_change_events` | `packages/shared/policy` and seed data | Platform Policy / Entitlements | Authority moves from shared client to platform policy; products request evaluated policy |
| Commit/release contracts | `commit_contracts` | Release/platform-control | Platform Evidence / StatusOps | Used as evidence input for release readiness; do not couple to product packages |
| Storage | `platform_storage_buckets`, `platform_storage_objects`, `platform_storage_grants`, `platform_storage_credential_sessions`, `platform_storage_attachments` | Storage service | GPUaaS storage initially; revisit when a second product consumes storage | Platform Secrets owns credentials; product owns object/storage semantics until generalized |

## Current-to-target naming

New schema should use these prefixes when adding durable production tables:

| Target owner | Preferred prefix examples |
|---|---|
| Platform IAM / Access | `platform_iam_*`, `platform_access_*` |
| Platform Billing / Payments | `platform_billing_*`, `platform_payment_*` |
| Platform Audit / Evidence | `platform_audit_*`, `platform_evidence_*` |
| Platform Status/Ops | `platform_status_*`, `platform_incident_*`, `platform_release_*` |
| Platform Registry / Artifacts | `platform_registry_*`, `platform_artifact_*` |
| Platform Secrets / PKI | `platform_secret_*`, `platform_pki_*` |
| Platform Policy / Entitlements | `platform_policy_*`, `platform_entitlement_*` |
| GPUaaS inventory/provisioning | `gpuaas_inventory_*`, `gpuaas_node_*`, `gpuaas_allocation_*` |
| GPUaaS terminal/access runtime | `gpuaas_terminal_*`, `gpuaas_session_*` |
| App Platform catalog/runtime | `appplatform_catalog_*`, `appplatform_runtime_*`, `appplatform_sdk_*` |

Existing unprefixed tables are not renamed by Phase A. The guard should treat
the ownership map, not the literal name, as authoritative for legacy tables.

## Guard inputs

Report-only schema guard should flag:

- product packages querying platform-owned tables directly;
- platform packages querying product-owned tables directly;
- joins across table families outside explicit read-model code;
- writes to `ledger_entries` outside Platform Billing/Payments;
- writes to `platform_audit_logs` outside the platform audit facade once it exists;
- direct `platform_outbox_events` publishing outside the shared outbox path;
- new tables without an owner-visible prefix or a documented exception.

Allowed transitional exceptions:

- `cmd/api` may read/write multiple domains while route handlers are being
  thinned, but route files should name their owning domain.
- Retired `packages/services/*` imports are not allowed after L3 service
  retirement; findings should be treated as fix-now import-boundary drift.
- `packages/shared/policy` may read `policy_*` tables until
  `packages/platform/policy` owns the authority.
- product provisioning flows may write product review records such as
  `gpuaas_provisioning_attention_reviews`, but platform audit rows still go through
  the audit contract.

## Open questions

1. Whether `storage_*` graduates to a shared platform storage service when App
   Platform or Token Factory needs first-class object storage.
2. Whether `user_ssh_public_keys` remains IAM-owned or becomes a GPUaaS access
   projection once the stable POSIX identity and terminal contracts are settled.
3. Whether `gpuaas_provisioning_attention_reviews` is a product review table only or
   the first instance of a shared operator-review/evidence pattern.
4. Whether `commit_contracts` should be replaced or wrapped by the first
   platform release-evidence bundle schema.
