Concept
Every company on SmartPRO has exactly one workspace. All data is scoped to a workspace โ employees, contracts, payroll, attendance, and settings are never shared across companies.
Key tables
| Table | Purpose |
|---|---|
companies |
One row per tenant โ the company is the workspace; holds subscription_status (legacy sync column) |
company_members |
Maps users to companies with a role |
company_subscriptions |
Source of truth for subscription state |
There is no separate workspaces table โ the tenant/workspace boundary is the companies row, and all data is scoped by company_id.
Subscription status
companies.subscription_status (legacy) and company_subscriptions must stay in sync. The banner and enforcement logic read the legacy column; a sync trigger and backfill migration (0161) keep them aligned.
If they diverge:
1. Run the backfill: UPDATE companies c JOIN company_subscriptions cs ON cs.company_id = c.id SET c.subscription_status = cs.status
2. Verify the sync trigger is active
Session scoping
Every tRPC request carries a session with companyId. Procedures call requireWorkspaceMembership(ctx) to assert the user belongs to the workspace, then scope all queries with WHERE company_id = ctx.companyId.
Never query cross-company without an explicit platform_admin check.
Pre-company state
New users who haven't joined or created a company land on the PreCompanyDashboard โ they can create a workspace or accept an invite. The AcceptInvitePage handles invite tokens.