12 KiB
12 KiB
M4 Target Schema Blueprint (Command-Ready)
Status: Draft for team alignment
Date: 2026-02-24
Owner: Technical Lead
1) Goal
Define the target database shape we want before command-backend implementation, so critical flows are atomic, secure, and scalable.
1.1 Stakeholder and tenancy model
This product should be designed as a multi-tenant platform.
- Tenant:
- One staffing company account (example: Legendary Event Staffing and Entertainment).
- Business:
- A customer/client account owned by a tenant.
- User:
- A human identity (auth account) that can belong to one or more tenants.
- Staff:
- A workforce profile linked to a user identity and tenant-scoped operations.
Practical meaning:
- The same platform can serve multiple staffing companies safely.
- Data isolation is by
tenant_id, not only by business/vendor IDs. - Not every record starts as a full active user:
- invite-first or pending onboarding records are valid,
- then bound to
user_idwhen activation is completed.
flowchart LR
U["User identity"] --> M["Tenant membership"]
M --> T["Tenant staffing company"]
T --> B["Business client"]
T --> V["Vendor partner"]
B --> O["Orders and shifts"]
V --> O
2) First-principles rules
- Every critical write must be server-mediated and transactional.
- Tenant boundaries must be explicit in data and queries.
- Money and rates must use exact numeric types, not floating point.
- Data needed for constraints should be relational, not hidden in JSON blobs.
- Every high-risk state transition must be auditable and replayable.
3) Current anti-patterns we are removing
- Direct client mutation of core entities.
- Broad
USER-auth CRUD without strict tenant scoping. - Financial values as
Float. - Core workflow state embedded in generic
Any/jsonbfields. - Missing uniqueness/index constraints on high-traffic paths.
4) Target modular schema
4.1 Identity and Access
Tables:
users(source identity, profile, auth linkage)tenant_memberships(new; membership + base access per tenant)team_members(membership + scope per team)roles(new)permissions(new)role_bindings(new; who has which role in which scope)
Rules:
- Unique tenant membership:
(tenant_id, user_id). - Unique team membership:
(team_id, user_id). - Access checks resolve through tenant membership first, then optional team/hub scope.
4.2 Organization and Tenant
Tables:
tenants(new canonical boundary: business/vendor ownership root)businessesvendorsteamsteam_hubshubs
Rules:
- Every command-critical row references
tenant_id. - All list queries must include tenant predicate.
4.8 RBAC rollout strategy (deferred enforcement)
RBAC should be introduced in phases and not enforced everywhere immediately.
Phase A: Auth-first (now)
- Require valid auth token.
- Resolve tenant context.
- Allow current work to continue while logging actor + tenant + action.
Phase B: Shadow RBAC
- Evaluate permissions (
allow/deny) in backend. - Log decisions but do not block most requests yet.
- Start with warnings and dashboards for denied actions.
Phase C: Enforced RBAC on command writes
- Enforce RBAC on
/commands/*only. - Keep low-risk read flows in transition mode.
Phase D: Enforced RBAC on high-risk reads
- Enforce tenant and role checks on sensitive read connectors.
- Remove remaining broad user-level access.
flowchart LR
A["Auth only"] --> B["Shadow RBAC logging"]
B --> C["Enforce RBAC on command writes"]
C --> D["Enforce RBAC on sensitive reads"]
4.3 Scheduling and Orders
Tables:
ordersorder_schedule_rules(new; replaces schedule JSON fields)shiftsshift_rolesshift_role_requirements(optional extension for policy rules)shift_managers(new; replacesmanagers: [Any!])
Rules:
- No denormalized
assignedStafforshiftsJSON inorders. - Time constraints:
start_time < end_time. - Capacity constraints:
assigned <= count,filled <= workers_needed. - Canonical status names (single spelling across schema).
4.4 Staffing and Matching
Tables:
staffsstaff_rolesworkforceapplicationsassignments
Rules:
- One active workforce relation per
(vendor_id, staff_id). - One application per
(shift_id, role_id, staff_id)unless versioned intentionally. - Assignment state transitions only through command APIs.
4.5 Compliance and Verification
Tables:
documentsstaff_documentscertificatesverification_jobsverification_reviewsverification_events
Rules:
- Verification is asynchronous and append-only for events.
- Manual review is explicit and tracked.
- Government ID and certification provider references are persisted.
4.6 Financial and Payout
Tables:
invoicesinvoice_templatesrecent_paymentsaccounts(refactor to tokenized provider references)
Rules:
- Replace monetary
Floatwith exact numeric (DECIMAL(12,2)or integer cents). - Do not expose raw account/routing values in query connectors.
- Add one-primary-account constraint per owner.
4.7 Audit and Reliability
Tables:
domain_events(new)idempotency_keys(already started in command API SQL)activity_logs
Rules:
- Every command write emits a domain event.
- Idempotency scope:
(actor_uid, route, idempotency_key).
5) Target core model (conceptual)
erDiagram
TENANT ||--o{ BUSINESS : owns
TENANT ||--o{ VENDOR : owns
TENANT ||--o{ TEAM : owns
TEAM ||--o{ TEAM_MEMBER : has
USER ||--o{ TEAM_MEMBER : belongs_to
BUSINESS ||--o{ ORDER : requests
VENDOR ||--o{ ORDER : fulfills
ORDER ||--o{ ORDER_SCHEDULE_RULE : has
ORDER ||--o{ SHIFT : expands_to
SHIFT ||--o{ SHIFT_ROLE : requires
SHIFT ||--o{ SHIFT_MANAGER : has
USER ||--o{ STAFF : identity
STAFF ||--o{ STAFF_ROLE : skills
VENDOR ||--o{ WORKFORCE : contracts
STAFF ||--o{ WORKFORCE : linked
SHIFT_ROLE ||--o{ APPLICATION : receives
STAFF ||--o{ APPLICATION : applies
SHIFT_ROLE ||--o{ ASSIGNMENT : allocates
WORKFORCE ||--o{ ASSIGNMENT : executes
STAFF ||--o{ CERTIFICATE : has
STAFF ||--o{ STAFF_DOCUMENT : uploads
DOCUMENT ||--o{ STAFF_DOCUMENT : references
STAFF ||--o{ VERIFICATION_JOB : subject
VERIFICATION_JOB ||--o{ VERIFICATION_REVIEW : reviewed_by
VERIFICATION_JOB ||--o{ VERIFICATION_EVENT : logs
ORDER ||--o{ INVOICE : billed_by
INVOICE ||--o{ RECENT_PAYMENT : settles
TENANT ||--o{ ACCOUNT_TOKEN_REF : payout_method
ORDER ||--o{ DOMAIN_EVENT : emits
SHIFT ||--o{ DOMAIN_EVENT : emits
ASSIGNMENT ||--o{ DOMAIN_EVENT : emits
6) Command write boundary on this schema
flowchart LR
A["Frontend app"] --> B["Command API"]
B --> C["Policy + validation"]
C --> D["Single database transaction"]
D --> E["orders, shifts, shift_roles, applications, assignments"]
D --> F["domain_events + idempotency_keys"]
E --> G["Read models and reports"]
7) Minimum constraints and indexes to add before command build
7.1 Constraints
shift_roles: checkassigned >= 0 AND assigned <= count.shifts: checkstart_time < end_time.applications: unique(shift_id, role_id, staff_id).workforce: unique active(vendor_id, staff_id).team_members: unique(team_id, user_id).accounts(or token ref table): unique primary per owner.
7.2 Indexes
orders (tenant_id, status, date).shifts (order_id, date, status).shift_roles (shift_id, role_id, start_time).applications (shift_id, role_id, status, created_at).assignments (workforce_id, shift_id, role_id, status).verification_jobs (subject_id, type, status, created_at).invoices (business_id, vendor_id, status, due_date).
8) Data type normalization
- Monetary:
Float -> DECIMAL(12,2)(or integer cents). - Generic JSON fields in core scheduling: split into relational tables.
- Timestamps: store UTC and enforce server-generated creation/update fields.
9) Security boundary in schema/connectors
- Remove broad list queries for sensitive entities unless tenant-scoped.
- Strip sensitive fields from connector query payloads (bank/routing).
- Keep high-risk mutations behind command API; Data Connect remains read-first for client.
10) Migration phases (schema-first)
flowchart TD
P0["Phase 0: Safety patch
- lock sensitive fields
- enforce tenant-scoped queries
- freeze new direct write connectors"] --> P1["Phase 1: Core constraints
- add unique/check constraints
- add indexes
- normalize money types"]
P1 --> P2["Phase 2: Tenant and RBAC base tables
- add tenants and tenant_memberships
- add roles permissions role_bindings
- run RBAC in shadow mode"]
P2 --> P3["Phase 3: Scheduling normalization
- remove order JSON workflow fields
- add order_schedule_rules and shift_managers"]
P3 --> P4["Phase 4: Command rollout
- command writes on hardened schema
- emit domain events + idempotency
- enforce RBAC for command routes"]
P4 --> P5["Phase 5: Read migration + cleanup
- migrate frontend reads as needed
- enforce RBAC for sensitive reads
- retire deprecated connectors"]
11) Definition of ready for command backend
- P0 and P1 complete in
dev. - Tenant scoping verified in connector tests.
- Sensitive field exposure removed.
- Core transaction invariants enforced by schema constraints.
- Command API contracts mapped to new normalized tables.
- RBAC is in shadow mode with decision logs in place (not hard-blocking yet).
12) Full current model relationship map (all models)
flowchart LR
Account["Account"]
ActivityLog["ActivityLog"]
Application["Application"]
Assignment["Assignment"]
AttireOption["AttireOption"]
BenefitsData["BenefitsData"]
Business["Business"]
Category["Category"]
Certificate["Certificate"]
ClientFeedback["ClientFeedback"]
Conversation["Conversation"]
Course["Course"]
CustomRateCard["CustomRateCard"]
Document["Document"]
EmergencyContact["EmergencyContact"]
FaqData["FaqData"]
Hub["Hub"]
Invoice["Invoice"]
InvoiceTemplate["InvoiceTemplate"]
Level["Level"]
MemberTask["MemberTask"]
Message["Message"]
Order["Order"]
RecentPayment["RecentPayment"]
Role["Role"]
RoleCategory["RoleCategory"]
Shift["Shift"]
ShiftRole["ShiftRole"]
Staff["Staff"]
StaffAvailability["StaffAvailability"]
StaffAvailabilityStats["StaffAvailabilityStats"]
StaffCourse["StaffCourse"]
StaffDocument["StaffDocument"]
StaffRole["StaffRole"]
Task["Task"]
TaskComment["TaskComment"]
TaxForm["TaxForm"]
Team["Team"]
TeamHub["TeamHub"]
TeamHudDepartment["TeamHudDepartment"]
TeamMember["TeamMember"]
User["User"]
UserConversation["UserConversation"]
Vendor["Vendor"]
VendorBenefitPlan["VendorBenefitPlan"]
VendorRate["VendorRate"]
Workforce["Workforce"]
Application --> Shift
Application --> ShiftRole
Application --> Staff
Assignment --> ShiftRole
Assignment --> Workforce
BenefitsData --> Staff
BenefitsData --> VendorBenefitPlan
Certificate --> Staff
ClientFeedback --> Business
ClientFeedback --> Vendor
Course --> Category
Invoice --> Business
Invoice --> Order
Invoice --> Vendor
InvoiceTemplate --> Business
InvoiceTemplate --> Order
InvoiceTemplate --> Vendor
MemberTask --> Task
MemberTask --> TeamMember
Message --> User
Order --> Business
Order --> TeamHub
Order --> Vendor
RecentPayment --> Application
RecentPayment --> Invoice
Shift --> Order
ShiftRole --> Role
ShiftRole --> Shift
StaffAvailability --> Staff
StaffAvailabilityStats --> Staff
StaffDocument --> Document
StaffRole --> Role
StaffRole --> Staff
TaskComment --> TeamMember
TeamHub --> Team
TeamHudDepartment --> TeamHub
TeamMember --> Team
TeamMember --> TeamHub
TeamMember --> User
UserConversation --> Conversation
UserConversation --> User
VendorBenefitPlan --> Vendor
VendorRate --> Vendor
Workforce --> Staff
Workforce --> Vendor