From fd3aec51827ffc9382f48f659aa0f72bc3ace0c7 Mon Sep 17 00:00:00 2001 From: zouantchaw <44246692+zouantchaw@users.noreply.github.com> Date: Wed, 25 Feb 2026 20:02:56 -0500 Subject: [PATCH] docs(m4): add model keys and relationship diagrams catalog --- CHANGELOG.md | 1 + .../m4-target-schema-models-and-keys.md | 264 ++++++++++++++++++ 2 files changed, 265 insertions(+) create mode 100644 docs/MILESTONES/M4/planning/m4-target-schema-models-and-keys.md diff --git a/CHANGELOG.md b/CHANGELOG.md index dd7db650..b3b40911 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,3 +27,4 @@ | 2026-02-25 | 0.1.22 | Updated core actor scenarios with explicit business and vendor user partitioning via membership tables. | | 2026-02-25 | 0.1.23 | Updated schema blueprint and reconciliation docs to add `business_memberships` and `vendor_memberships` as first-class data actors. | | 2026-02-25 | 0.1.24 | Removed stale `m4-discrepencies.md` document from M4 planning docs cleanup. | +| 2026-02-25 | 0.1.25 | Added target schema model catalog with keys and domain relationship diagrams for slide/workshop use. | diff --git a/docs/MILESTONES/M4/planning/m4-target-schema-models-and-keys.md b/docs/MILESTONES/M4/planning/m4-target-schema-models-and-keys.md new file mode 100644 index 00000000..ebfb3dc8 --- /dev/null +++ b/docs/MILESTONES/M4/planning/m4-target-schema-models-and-keys.md @@ -0,0 +1,264 @@ +# 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.