# M4 Target Schema Models, Keys, and Relationships Status: Draft for architecture workshop Date: 2026-02-25 Owner: Technical Lead ## 1) Purpose This document is the model-level view for slide creation: 1. Key fields per model (`PK`, `FK`, unique keys). 2. How models relate to each other. 3. A first-principles structure for scale across tenant, business, vendor, and workforce flows. ## 2) Identity and access models ### 2.1 Model keys | Model | Primary key | Foreign keys | Important unique keys | |---|---|---|---| | `users` | `id` | - | `email` (optional unique) | | `tenants` | `id` | - | `slug` | | `tenant_memberships` | `id` | `tenant_id -> tenants.id`, `user_id -> users.id` | `(tenant_id, user_id)` | | `business_memberships` | `id` | `tenant_id -> tenants.id`, `business_id -> businesses.id`, `user_id -> users.id` | `(business_id, user_id)` | | `vendor_memberships` | `id` | `tenant_id -> tenants.id`, `vendor_id -> vendors.id`, `user_id -> users.id` | `(vendor_id, user_id)` | | `roles` | `id` | `tenant_id -> tenants.id` | `(tenant_id, name)` | | `permissions` | `id` | - | `code` | | `role_bindings` | `id` | `tenant_id -> tenants.id`, `role_id -> roles.id`, `user_id -> users.id` | `(tenant_id, role_id, user_id, scope_type, scope_id)` | ### 2.2 Diagram ```mermaid erDiagram USERS ||--o{ TENANT_MEMBERSHIPS : has TENANTS ||--o{ TENANT_MEMBERSHIPS : has USERS ||--o{ BUSINESS_MEMBERSHIPS : has BUSINESSES ||--o{ BUSINESS_MEMBERSHIPS : has TENANTS ||--o{ BUSINESS_MEMBERSHIPS : scopes USERS ||--o{ VENDOR_MEMBERSHIPS : has VENDORS ||--o{ VENDOR_MEMBERSHIPS : has TENANTS ||--o{ VENDOR_MEMBERSHIPS : scopes TENANTS ||--o{ ROLES : defines ROLES ||--o{ ROLE_BINDINGS : used_by USERS ||--o{ ROLE_BINDINGS : receives TENANTS ||--o{ ROLE_BINDINGS : scopes ``` ``` ## 3) Organization and stakeholder models ### 3.1 Model keys | Model | Primary key | Foreign keys | Important unique keys | |---|---|---|---| | `businesses` | `id` | `tenant_id -> tenants.id` | `(tenant_id, business_name)` | | `vendors` | `id` | `tenant_id -> tenants.id` | `(tenant_id, company_name)` | | `teams` | `id` | `tenant_id -> tenants.id` | `(tenant_id, team_name)` | | `team_hubs` | `id` | `team_id -> teams.id` | `(team_id, hub_name)` | | `team_hud_departments` | `id` | `team_hub_id -> team_hubs.id` | `(team_hub_id, name)` | | `stakeholder_types` | `id` | - | `code` | | `stakeholder_profiles` | `id` | `tenant_id -> tenants.id`, `stakeholder_type_id -> stakeholder_types.id` | `(tenant_id, stakeholder_type_id, name)` | | `stakeholder_links` | `id` | `tenant_id -> tenants.id`, `from_profile_id -> stakeholder_profiles.id`, `to_profile_id -> stakeholder_profiles.id` | `(tenant_id, from_profile_id, to_profile_id, relation_type)` | ### 3.2 Diagram ```mermaid erDiagram TENANTS ||--o{ BUSINESSES : owns TENANTS ||--o{ VENDORS : owns TENANTS ||--o{ TEAMS : owns TEAMS ||--o{ TEAM_HUBS : has TEAM_HUBS ||--o{ TEAM_HUD_DEPARTMENTS : has STAKEHOLDER_TYPES ||--o{ STAKEHOLDER_PROFILES : classifies TENANTS ||--o{ STAKEHOLDER_PROFILES : owns STAKEHOLDER_PROFILES ||--o{ STAKEHOLDER_LINKS : from STAKEHOLDER_PROFILES ||--o{ STAKEHOLDER_LINKS : to TENANTS ||--o{ STAKEHOLDER_LINKS : scopes ``` ``` ## 4) Workforce, orders, and assignments ### 4.1 Model keys | Model | Primary key | Foreign keys | Important unique keys | |---|---|---|---| | `staffs` | `id` | `tenant_id -> tenants.id`, `user_id -> users.id` | `(tenant_id, user_id)` (nullable until activation if needed) | | `staff_roles` | `id` | `staff_id -> staffs.id`, `role_id -> roles.id` | `(staff_id, role_id)` | | `workforce` | `id` | `tenant_id -> tenants.id`, `vendor_id -> vendors.id`, `staff_id -> staffs.id` | active `(vendor_id, staff_id)` | | `orders` | `id` | `tenant_id -> tenants.id`, `business_id -> businesses.id`, `vendor_id -> vendors.id` | `(tenant_id, external_ref)` optional | | `order_schedule_rules` | `id` | `order_id -> orders.id` | `(order_id, rule_type, effective_from)` | | `shifts` | `id` | `tenant_id -> tenants.id`, `order_id -> orders.id` | `(order_id, start_time, end_time)` | | `shift_roles` | `id` | `shift_id -> shifts.id`, `role_id -> roles.id` | `(shift_id, role_id)` | | `shift_managers` | `id` | `shift_id -> shifts.id`, `team_member_id -> team_members.id` | `(shift_id, team_member_id)` | | `applications` | `id` | `tenant_id -> tenants.id`, `shift_id -> shifts.id`, `role_id -> roles.id`, `staff_id -> staffs.id` | `(shift_id, role_id, staff_id)` | | `assignments` | `id` | `tenant_id -> tenants.id`, `shift_role_id -> shift_roles.id`, `workforce_id -> workforce.id` | `(shift_role_id, workforce_id)` active | ### 4.2 Diagram ```mermaid erDiagram TENANTS ||--o{ STAFFS : owns USERS ||--o| STAFFS : identity STAFFS ||--o{ STAFF_ROLES : has ROLES ||--o{ STAFF_ROLES : classifies TENANTS ||--o{ ORDERS : scopes BUSINESSES ||--o{ ORDERS : requests VENDORS ||--o{ ORDERS : fulfills ORDERS ||--o{ ORDER_SCHEDULE_RULES : configures ORDERS ||--o{ SHIFTS : expands_to SHIFTS ||--o{ SHIFT_ROLES : requires ROLES ||--o{ SHIFT_ROLES : typed_as SHIFTS ||--o{ SHIFT_MANAGERS : has VENDORS ||--o{ WORKFORCE : contracts STAFFS ||--o{ WORKFORCE : linked SHIFT_ROLES ||--o{ APPLICATIONS : receives STAFFS ||--o{ APPLICATIONS : applies SHIFT_ROLES ||--o{ ASSIGNMENTS : allocates WORKFORCE ||--o{ ASSIGNMENTS : executes ``` ``` ## 5) Attendance and offense governance ### 5.1 Model keys | Model | Primary key | Foreign keys | Important unique keys | |---|---|---|---| | `attendance_events` | `id` | `tenant_id -> tenants.id`, `assignment_id -> assignments.id` | `(assignment_id, source_event_id)` | | `attendance_sessions` | `id` | `tenant_id -> tenants.id`, `assignment_id -> assignments.id` | one open session per assignment | | `timesheets` | `id` | `tenant_id -> tenants.id`, `assignment_id -> assignments.id`, `staff_id -> staffs.id` | `(assignment_id)` | | `timesheet_adjustments` | `id` | `timesheet_id -> timesheets.id`, `actor_user_id -> users.id` | - | | `offense_policies` | `id` | `tenant_id -> tenants.id`, `business_id -> businesses.id` nullable | `(tenant_id, name, business_id)` | | `offense_rules` | `id` | `policy_id -> offense_policies.id` | `(policy_id, trigger_type, threshold_count)` | | `offense_events` | `id` | `tenant_id -> tenants.id`, `staff_id -> staffs.id`, `assignment_id -> assignments.id` nullable, `rule_id -> offense_rules.id` nullable | `(staff_id, occurred_at, offense_type)` | | `enforcement_actions` | `id` | `offense_event_id -> offense_events.id`, `actor_user_id -> users.id` | - | ### 5.2 Diagram ```mermaid erDiagram ASSIGNMENTS ||--o{ ATTENDANCE_EVENTS : emits ASSIGNMENTS ||--o{ ATTENDANCE_SESSIONS : opens ASSIGNMENTS ||--o{ TIMESHEETS : settles TIMESHEETS ||--o{ TIMESHEET_ADJUSTMENTS : adjusts USERS ||--o{ TIMESHEET_ADJUSTMENTS : made_by TENANTS ||--o{ OFFENSE_POLICIES : defines BUSINESSES ||--o{ OFFENSE_POLICIES : overrides OFFENSE_POLICIES ||--o{ OFFENSE_RULES : contains STAFFS ||--o{ OFFENSE_EVENTS : incurs OFFENSE_RULES ||--o{ OFFENSE_EVENTS : triggered_by OFFENSE_EVENTS ||--o{ ENFORCEMENT_ACTIONS : causes USERS ||--o{ ENFORCEMENT_ACTIONS : applied_by ``` ``` ## 6) Compliance and verification ### 6.1 Model keys | Model | Primary key | Foreign keys | Important unique keys | |---|---|---|---| | `documents` | `id` | `tenant_id -> tenants.id` | `(tenant_id, document_type, name)` | | `staff_documents` | `id` | `staff_id -> staffs.id`, `document_id -> documents.id` | `(staff_id, document_id)` | | `certificates` | `id` | `staff_id -> staffs.id` | `(staff_id, certificate_number)` optional | | `compliance_requirements` | `id` | `tenant_id -> tenants.id`, `business_id -> businesses.id` nullable, `role_id -> roles.id` nullable | `(tenant_id, requirement_type, business_id, role_id)` | | `verification_jobs` | `id` | `tenant_id -> tenants.id`, `staff_id -> staffs.id`, `document_id -> documents.id` nullable | `(tenant_id, idempotency_key)` | | `verification_reviews` | `id` | `verification_job_id -> verification_jobs.id`, `reviewer_user_id -> users.id` | - | | `verification_events` | `id` | `verification_job_id -> verification_jobs.id` | - | ### 6.2 Diagram ```mermaid erDiagram STAFFS ||--o{ STAFF_DOCUMENTS : uploads DOCUMENTS ||--o{ STAFF_DOCUMENTS : references STAFFS ||--o{ CERTIFICATES : has TENANTS ||--o{ COMPLIANCE_REQUIREMENTS : defines BUSINESSES ||--o{ COMPLIANCE_REQUIREMENTS : overrides ROLES ||--o{ COMPLIANCE_REQUIREMENTS : role_scope STAFFS ||--o{ VERIFICATION_JOBS : subject VERIFICATION_JOBS ||--o{ VERIFICATION_REVIEWS : reviewed VERIFICATION_JOBS ||--o{ VERIFICATION_EVENTS : logs USERS ||--o{ VERIFICATION_REVIEWS : reviewer ``` ``` ## 7) Finance and settlement ### 7.1 Model keys | Model | Primary key | Foreign keys | Important unique keys | |---|---|---|---| | `invoices` | `id` | `tenant_id -> tenants.id`, `order_id -> orders.id`, `business_id -> businesses.id`, `vendor_id -> vendors.id` | `(tenant_id, invoice_number)` | | `invoice_line_items` | `id` | `invoice_id -> invoices.id`, `assignment_id -> assignments.id` nullable | `(invoice_id, line_number)` | | `invoice_status_history` | `id` | `invoice_id -> invoices.id`, `actor_user_id -> users.id` | - | | `payment_runs` | `id` | `tenant_id -> tenants.id` | `(tenant_id, run_reference)` | | `payment_allocations` | `id` | `payment_run_id -> payment_runs.id`, `invoice_id -> invoices.id` | `(payment_run_id, invoice_id)` | | `remittance_documents` | `id` | `payment_run_id -> payment_runs.id` | `(payment_run_id, document_url)` | | `account_token_refs` | `id` | `tenant_id -> tenants.id`, `owner_business_id -> businesses.id` nullable, `owner_vendor_id -> vendors.id` nullable | one primary per owner | ### 7.2 Diagram ```mermaid erDiagram ORDERS ||--o{ INVOICES : billed BUSINESSES ||--o{ INVOICES : billed_to VENDORS ||--o{ INVOICES : billed_from INVOICES ||--o{ INVOICE_LINE_ITEMS : contains INVOICES ||--o{ INVOICE_STATUS_HISTORY : transitions USERS ||--o{ INVOICE_STATUS_HISTORY : changed_by PAYMENT_RUNS ||--o{ PAYMENT_ALLOCATIONS : allocates INVOICES ||--o{ PAYMENT_ALLOCATIONS : receives PAYMENT_RUNS ||--o{ REMITTANCE_DOCUMENTS : publishes TENANTS ||--o{ ACCOUNT_TOKEN_REFS : scopes BUSINESSES ||--o{ ACCOUNT_TOKEN_REFS : business_owner VENDORS ||--o{ ACCOUNT_TOKEN_REFS : vendor_owner ``` ``` ## 8) Audit and reliability ### 8.1 Model keys | Model | Primary key | Foreign keys | Important unique keys | |---|---|---|---| | `domain_events` | `id` | `tenant_id -> tenants.id`, `actor_user_id -> users.id` | `(tenant_id, aggregate_type, aggregate_id, sequence)` | | `idempotency_keys` | `id` | `tenant_id -> tenants.id`, `actor_user_id -> users.id` | `(tenant_id, actor_user_id, route, key)` | | `activity_logs` | `id` | `tenant_id -> tenants.id`, `user_id -> users.id` | `(tenant_id, created_at, id)` | ### 8.2 Diagram ```mermaid erDiagram TENANTS ||--o{ DOMAIN_EVENTS : scopes USERS ||--o{ DOMAIN_EVENTS : actor TENANTS ||--o{ IDEMPOTENCY_KEYS : scopes USERS ||--o{ IDEMPOTENCY_KEYS : actor TENANTS ||--o{ ACTIVITY_LOGS : scopes USERS ||--o{ ACTIVITY_LOGS : actor ``` ``` ## 9) Practical note for current system Current schema already has: 1. `businesses.userId` (single business owner user). 2. `vendors.userId` (single vendor owner user). 3. `team_members` (multi-user workaround). Target schema improves this by adding explicit: 1. `business_memberships` 2. `vendor_memberships` This is the key upgrade for clean client/vendor user partitioning.