IntegrateWise App-Category Entity Domain Model — Canonical Schema
Governing Rule — 2026-07-28
The Spine is not organized by department. It is organized by what entities ARE (app_category = source), what business function they belong to (business_domain = classification), and when in the startup lifecycle they matter (lifecycle_stage = routing key).
1. Three-Layer Classification
Every canonical entity carries three classification tags beyond its spine identity fields:
app_category— the connector/source classification. Determines which integration writes to which entity domain.business_domain— the RBAC classification. Determines who can see/write the entity and which projection rules apply.lifecycle_stage— the routing key. Determines which signals fire, which playbooks activate, and which projections get rebuilt.
Full classification address = (app_category, business_domain, lifecycle_stage).
1.1 App Category Registry
Source layer: the type of tool the entity originates from. Every connector is classified into exactly one primary app category.
| app_category_id | key | name | description |
|---|---|---|---|
ac_crm | crm | CRM | Customer relationship and sales system of record. |
ac_marketing_automation | marketing_automation | Marketing Automation | Campaign, audience and attribution source. |
ac_revenue_operations | revenue_operations | Revenue Operations | Forecast, routing, territory and sales-intelligence source. |
ac_support_helpdesk | support_helpdesk | Support / Helpdesk | Support case, service and SLA source. |
ac_finance_billing | finance_billing | Finance / Billing | Invoice, payment, subscription and spend source. |
ac_hris_people | hris_people | HRIS / People | Workforce and people-operations source. |
ac_recruiting_ats | recruiting_ats | Recruiting / ATS | Recruiting and hiring source. |
ac_product_analytics | product_analytics | Product Analytics | Product-usage and adoption source. |
ac_project_issue_tracking | project_issue_tracking | Project / Issue Tracking | Planning, delivery and issue source. |
ac_devops_cicd | devops_cicd | DevOps / CI-CD | Code, build, deployment and release source. |
ac_observability_monitoring | observability_monitoring | Observability / Monitoring | Alert, incident and reliability source. |
ac_legal_contract | legal_contract | Legal / Contract | Agreement and compliance source. |
ac_it_identity | it_identity | IT / Identity | Identity, device, access and security-control source. |
ac_communications_email | communications_email | Communications - Email | Email communication source. |
ac_communications_chat | communications_chat | Communications - Chat | Chat communication source. |
ac_communications_video | communications_video | Communications - Video | Meeting, call and recording source. |
ac_knowledge_docs | knowledge_docs | Knowledge / Docs | Document, note and knowledge source. |
ac_executive_board | executive_board | Executive / Board | Board, investor and company-planning source. |
ac_marketplace_platform | marketplace_platform | Marketplace / Platform | Integration and platform-runtime source. |
ac_integratewise_native | integratewise_native | IntegrateWise Native | Human-created or governed IntegrateWise record. |
1.2 Business Domain Registry
Classification layer: the RBAC domain every entity belongs to. Determines visibility, field restrictions, and projection rules.
| business_domain_id | key | name | sensitivity |
|---|---|---|---|
bd_revenue | revenue | Revenue | restricted |
bd_people | people | People | confidential |
bd_product | product | Product | internal |
bd_operations | operations | Operations | internal |
bd_finance | finance | Finance | confidential |
bd_legal | legal | Legal | confidential |
bd_communications | communications | Communications | restricted |
bd_knowledge | knowledge | Knowledge | internal |
bd_platform | platform | Platform | restricted |
1.3 Lifecycle Stage Registry
Routing layer: where the tenant/user/entity is in the operational lifecycle.
| lifecycle_stage | meaning | active entities / tables |
|---|---|---|
formation | Tenant onboarding, connectors being installed, no live data yet | tenants, users, roles, connector_catalog, connector_installations |
activation | First connectors live, data flowing in, first accounts/contacts/deals created | + accounts, contacts, deals, signals (ingestion) |
operation | Daily run-rate. Pipeline active. Memory accumulating. Playbooks firing. | + tasks, activities, invoices, budgets, playbooks, memory_items |
scale | Multi-team RBAC expanding, canvas templates customized per role | + teams, team_members, approval_chains, canvas_overrides, org_memory |
governance | Audit, compliance, promotion queue at volume, retention enforced | + audit_log, promotion_queue, retention_policies |
Stages are additive, not replacing.
2. App-Category → Entity Domain Routes
Each route defines how an app category maps to a canonical entity type and table, its business domain, lifecycle stage, and event emissions.
| route_id | app_category | entity_type | canonical_table | business_domain | default_lifecycle_stage | event_types |
|---|---|---|---|---|---|---|
acr_crm_account | crm | account | spine_accounts | revenue | operate | account.created, account.updated |
acr_crm_lead | crm | lead | spine_leads | revenue | sense | lead.created, lead.qualified |
acr_crm_opportunity | crm | opportunity | spine_opportunities | revenue | decide | opportunity.stage_changed, deal.won, deal.lost |
acr_marketing_campaign | marketing_automation | campaign | spine_campaigns | revenue | build | campaign.launched, lead.scored, attribution.recorded |
acr_revops_workflow | revenue_operations | workflow | spine_workflows | revenue | operate | forecast.published, territory.assigned, quota.set |
acr_support_ticket | support_helpdesk | ticket | spine_tickets | operations | operate | ticket.created, ticket.escalated, ticket.resolved, sla.breached |
acr_finance_invoice | finance_billing | invoice | spine_invoices | finance | operate | invoice.created, payment.received, payment.failed |
acr_finance_subscription | finance_billing | subscription | spine_subscriptions | finance | operate | subscription.renewed |
acr_people_person | hris_people | person | spine_persons | people | operate | employee.hired, employee.departed |
acr_people_team | hris_people | team | spine_teams | people | operate | employee.onboarded, review.completed, leave.approved |
acr_ats_person | recruiting_ats | person | spine_persons | people | sense | candidate.applied, interview.scheduled, offer.extended, hire.completed |
acr_product_feature | project_issue_tracking | feature | spine_features | product | build | issue.created, feature.shipped, bug.resolved |
acr_product_sprint | project_issue_tracking | sprint | spine_sprints | product | build | sprint.started, milestone.hit |
acr_analytics_signal | product_analytics | signal | spine_signals | product | learn | feature.used, session.started, adoption_tier.changed |
acr_devops_release | devops_cicd | release | spine_releases | product | release | commit.pushed, pr.merged, build.passed, deployment.succeeded |
acr_observability_incident | observability_monitoring | incident | spine_incidents | product | operate | alert.fired, incident.declared, slo.breached, rca.completed |
acr_legal_contract | legal_contract | contract | spine_contracts | legal | decide | contract.drafted, contract.sent, contract.signed, obligation.due |
acr_identity_asset | it_identity | asset | spine_assets | operations | operate | user.provisioned, access.granted, certificate.expiring, vulnerability.detected |
acr_email_conversation | communications_email | conversation | spine_conversations | communications | sense | email.received, email.sent, thread.classified, action.extracted |
acr_chat_conversation | communications_chat | conversation | spine_conversations | communications | sense | message.sent, mention.detected, sentiment.scored |
acr_video_meeting | communications_video | meeting | spine_meetings | communications | operate | meeting.held, recording.processed, transcript.ready, action_items.extracted |
acr_knowledge_document | knowledge_docs | document | knowledge_documents | knowledge | learn | document.created, article.published, document.shared, chunk.embedded |
acr_board_objective | executive_board | objective | spine_objectives | operations | decide | goal.set, board_item.added, update.sent, funding_round.opened |
acr_platform_connector | marketplace_platform | connector | spine_connector_catalog | platform | operate | connector.installed, capability.invoked, automation.triggered, mcp_tool.called |
3. Canonical Spine Identity Fields (Every Table)
These fields are immutable spine addresses. Always OMITTED from projections.
spine_network_id TEXT PRIMARY KEY— format:{prefix}_{ulid}, globally unique, cross-tenant stableaccount_id TEXT NOT NULL— tenant this record belongs tocreated_at TIMESTAMPTZ NOT NULL DEFAULT now()updated_at TIMESTAMPTZ NOT NULL DEFAULT now()version INTEGER NOT NULL DEFAULT 1— incremented on every canonical writeorigin TEXT NOT NULL—human | twin | pipeline | systempromotion_id TEXT— thepromotion_queue.queue_idthat wrote this version; null for system-originlifecycle_stage TEXT NOT NULL—formation | activation | operation | scale | governanceapp_category TEXT NOT NULLbusiness_domain TEXT NOT NULL
4. Canonical Table Registry
4.1 Formation Stage Tables
tenants
CREATE TABLE tenants (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL UNIQUE,
slug TEXT NOT NULL UNIQUE,
display_name TEXT NOT NULL,
plan TEXT NOT NULL DEFAULT 'free',
lifecycle_stage TEXT NOT NULL DEFAULT 'formation',
onboarding_status TEXT NOT NULL DEFAULT 'pending',
primary_domain TEXT,
timezone TEXT NOT NULL DEFAULT 'UTC',
locale TEXT NOT NULL DEFAULT 'en',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL DEFAULT 'system',
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'platform',
business_domain TEXT NOT NULL DEFAULT 'identity'
);
users
CREATE TABLE users (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
external_id TEXT NOT NULL,
email TEXT NOT NULL,
display_name TEXT NOT NULL,
avatar_url TEXT,
role_id TEXT NOT NULL REFERENCES roles(spine_network_id),
employment_type TEXT NOT NULL DEFAULT 'full_time',
work_lifecycle_stage TEXT NOT NULL DEFAULT 'onboarding',
last_active_at TIMESTAMPTZ,
lifecycle_stage TEXT NOT NULL DEFAULT 'formation',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL DEFAULT 'system',
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'platform',
business_domain TEXT NOT NULL DEFAULT 'identity',
UNIQUE(account_id, email)
);
roles
CREATE TABLE roles (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
slug TEXT NOT NULL,
display_name TEXT NOT NULL,
is_system_role BOOLEAN NOT NULL DEFAULT false,
parent_role_id TEXT REFERENCES roles(spine_network_id),
permissions JSONB NOT NULL DEFAULT '[]',
domain_access JSONB NOT NULL DEFAULT '{}', -- {domain: "full"|"partial"|"none"}
lifecycle_stage TEXT NOT NULL DEFAULT 'formation',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL DEFAULT 'system',
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'platform',
business_domain TEXT NOT NULL DEFAULT 'identity',
UNIQUE(account_id, slug)
);
connector_catalog
CREATE TABLE connector_catalog (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL DEFAULT 'platform',
slug TEXT NOT NULL UNIQUE,
display_name TEXT NOT NULL,
app_category TEXT NOT NULL,
business_domain TEXT NOT NULL,
logo_url TEXT,
auth_type TEXT NOT NULL, -- oauth2 | api_key | webhook | mcp
mcp_endpoint TEXT,
manifest_version TEXT NOT NULL DEFAULT '1.0',
is_active BOOLEAN NOT NULL DEFAULT true,
lifecycle_stage TEXT NOT NULL DEFAULT 'formation',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL DEFAULT 'system',
promotion_id TEXT
);
connector_installations
CREATE TABLE connector_installations (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
connector_id TEXT NOT NULL REFERENCES connector_catalog(spine_network_id),
installed_by TEXT NOT NULL REFERENCES users(spine_network_id),
status TEXT NOT NULL DEFAULT 'pending',
auth_credential_ref TEXT, -- vault reference only, never plaintext
config JSONB NOT NULL DEFAULT '{}',
last_sync_at TIMESTAMPTZ,
last_error TEXT,
sync_frequency TEXT NOT NULL DEFAULT '15m',
lifecycle_stage TEXT NOT NULL DEFAULT 'formation',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL DEFAULT 'system',
promotion_id TEXT,
app_category TEXT NOT NULL,
business_domain TEXT NOT NULL,
UNIQUE(account_id, connector_id)
);
4.2 Activation Stage Tables
accounts
CREATE TABLE accounts (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
name TEXT NOT NULL,
domain TEXT,
industry TEXT,
employee_count INTEGER,
annual_revenue NUMERIC(18,2),
health_score NUMERIC(4,3), -- 0-1, computed by pipeline
tier TEXT, -- strategic | growth | standard | at_risk
owner_id TEXT REFERENCES users(spine_network_id),
lifecycle_stage TEXT NOT NULL DEFAULT 'activation',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL,
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'crm',
business_domain TEXT NOT NULL DEFAULT 'revenue'
);
contacts
CREATE TABLE contacts (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
external_account_id TEXT REFERENCES accounts(spine_network_id),
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
email TEXT,
phone TEXT,
title TEXT,
department TEXT,
linkedin_url TEXT,
contact_type TEXT NOT NULL DEFAULT 'external',
lifecycle_stage TEXT NOT NULL DEFAULT 'activation',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL,
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'crm',
business_domain TEXT NOT NULL DEFAULT 'people'
);
deals
CREATE TABLE deals (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
name TEXT NOT NULL,
external_account_id TEXT REFERENCES accounts(spine_network_id),
primary_contact_id TEXT REFERENCES contacts(spine_network_id),
owner_id TEXT REFERENCES users(spine_network_id),
stage TEXT NOT NULL DEFAULT 'prospecting',
value NUMERIC(18,2),
currency TEXT NOT NULL DEFAULT 'USD',
close_date DATE,
probability NUMERIC(4,3),
deal_type TEXT,
lost_reason TEXT,
lifecycle_stage TEXT NOT NULL DEFAULT 'activation',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL,
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'crm',
business_domain TEXT NOT NULL DEFAULT 'revenue'
);
4.3 Operation Stage Tables
tasks
CREATE TABLE tasks (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
title TEXT NOT NULL,
description TEXT,
assignee_id TEXT REFERENCES users(spine_network_id),
created_by TEXT REFERENCES users(spine_network_id),
related_entity_id TEXT,
related_entity_type TEXT,
status TEXT NOT NULL DEFAULT 'open',
priority TEXT NOT NULL DEFAULT 'normal',
due_date DATE,
completed_at TIMESTAMPTZ,
lifecycle_stage TEXT NOT NULL DEFAULT 'operation',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL,
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'project_management',
business_domain TEXT NOT NULL DEFAULT 'operations'
);
activities
CREATE TABLE activities (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
activity_type TEXT NOT NULL,
subject TEXT NOT NULL,
body TEXT,
performed_by TEXT REFERENCES users(spine_network_id),
related_entity_id TEXT,
related_entity_type TEXT, -- call | email | meeting | note | demo | proposal
participants TEXT[],
duration_seconds INTEGER,
occurred_at TIMESTAMPTZ NOT NULL,
lifecycle_stage TEXT NOT NULL DEFAULT 'operation',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL,
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'communication',
business_domain TEXT NOT NULL DEFAULT 'revenue'
);
signals
CREATE TABLE signals (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
signal_type TEXT NOT NULL,
subject_entity_id TEXT NOT NULL,
subject_entity_type TEXT NOT NULL,
payload JSONB NOT NULL DEFAULT '{}',
confidence NUMERIC(4,3) NOT NULL DEFAULT 1.0,
source TEXT NOT NULL,
fired_at TIMESTAMPTZ NOT NULL DEFAULT now(),
consumed_by TEXT[],
lifecycle_stage TEXT NOT NULL DEFAULT 'operation',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL DEFAULT 'pipeline',
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'pipeline',
business_domain TEXT NOT NULL DEFAULT 'operations'
);
invoices
CREATE TABLE invoices (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
external_account_id TEXT REFERENCES accounts(spine_network_id),
invoice_number TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'draft',
amount NUMERIC(18,2) NOT NULL,
currency TEXT NOT NULL DEFAULT 'USD',
due_date DATE,
paid_at TIMESTAMPTZ,
line_items JSONB NOT NULL DEFAULT '[]',
lifecycle_stage TEXT NOT NULL DEFAULT 'operation',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL,
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'billing',
business_domain TEXT NOT NULL DEFAULT 'finance'
);
playbooks
CREATE TABLE playbooks (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
name TEXT NOT NULL,
trigger_signal TEXT NOT NULL,
conditions JSONB NOT NULL DEFAULT '[]',
actions JSONB NOT NULL DEFAULT '[]',
is_active BOOLEAN NOT NULL DEFAULT true,
run_count INTEGER NOT NULL DEFAULT 0,
last_run_at TIMESTAMPTZ,
lifecycle_stage TEXT NOT NULL DEFAULT 'operation',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL DEFAULT 'human',
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'platform',
business_domain TEXT NOT NULL DEFAULT 'operations'
);
memory_items
CREATE TABLE memory_items (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
scope TEXT NOT NULL, -- personal | organizational | agent | operational
memory_type TEXT NOT NULL, -- observation | decision | context | fact | signal | continuity_checkpoint
subject_refs TEXT[] NOT NULL,
content TEXT,
content_jsonb JSONB,
user_id TEXT REFERENCES users(spine_network_id),
session_id TEXT,
origin TEXT NOT NULL,
confidence NUMERIC(4,3),
retention_policy TEXT NOT NULL DEFAULT '30d',
expires_at TIMESTAMPTZ,
promotion_eligible BOOLEAN NOT NULL DEFAULT false,
promotion_status TEXT NOT NULL DEFAULT 'none', -- none | proposed | approved | committed | rejected
lifecycle_stage TEXT NOT NULL DEFAULT 'operation',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'platform',
business_domain TEXT NOT NULL DEFAULT 'operations'
);
4.4 Scale Stage Tables
teams
CREATE TABLE teams (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
name TEXT NOT NULL,
team_type TEXT NOT NULL DEFAULT 'functional',
lead_user_id TEXT REFERENCES users(spine_network_id),
parent_team_id TEXT REFERENCES teams(spine_network_id),
domain_focus TEXT[],
lifecycle_stage TEXT NOT NULL DEFAULT 'scale',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL DEFAULT 'human',
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'platform',
business_domain TEXT NOT NULL DEFAULT 'identity'
);
team_members
CREATE TABLE team_members (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
team_id TEXT NOT NULL REFERENCES teams(spine_network_id),
user_id TEXT NOT NULL REFERENCES users(spine_network_id),
team_role TEXT NOT NULL DEFAULT 'member',
lifecycle_stage TEXT NOT NULL DEFAULT 'scale',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL DEFAULT 'human',
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'platform',
business_domain TEXT NOT NULL DEFAULT 'identity',
UNIQUE(team_id, user_id)
);
approval_chains
CREATE TABLE approval_chains (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
capability TEXT NOT NULL,
approver_role_id TEXT NOT NULL REFERENCES roles(spine_network_id),
escalation_role_id TEXT REFERENCES roles(spine_network_id),
escalation_after_hours INTEGER NOT NULL DEFAULT 24,
is_active BOOLEAN NOT NULL DEFAULT true,
lifecycle_stage TEXT NOT NULL DEFAULT 'scale',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL DEFAULT 'human',
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'platform',
business_domain TEXT NOT NULL DEFAULT 'identity',
UNIQUE(account_id, capability)
);
canvas_overrides
CREATE TABLE canvas_overrides (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
projection_key TEXT NOT NULL,
template_level TEXT NOT NULL, -- tenant | user
user_id TEXT REFERENCES users(spine_network_id),
overrides JSONB NOT NULL DEFAULT '{}',
is_active BOOLEAN NOT NULL DEFAULT true,
lifecycle_stage TEXT NOT NULL DEFAULT 'scale',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL DEFAULT 'human',
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'platform',
business_domain TEXT NOT NULL DEFAULT 'operations'
);
4.5 Governance Stage Tables
audit_log
CREATE TABLE audit_log (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
actor_id TEXT,
action TEXT NOT NULL, -- create | update | promote | approve | reject
target_entity_id TEXT NOT NULL,
target_entity_type TEXT NOT NULL,
before_version INTEGER,
after_version INTEGER,
diff JSONB,
promotion_id TEXT,
ip_address TEXT,
user_agent TEXT,
occurred_at TIMESTAMPTZ NOT NULL DEFAULT now(),
lifecycle_stage TEXT NOT NULL DEFAULT 'governance',
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL,
app_category TEXT NOT NULL DEFAULT 'platform',
business_domain TEXT NOT NULL DEFAULT 'governance'
);
retention_policies
CREATE TABLE retention_policies (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
entity_type TEXT NOT NULL,
business_domain TEXT NOT NULL,
retention_days INTEGER NOT NULL, -- -1 = permanent
archive_after_days INTEGER,
delete_after_days INTEGER,
applies_to_scopes TEXT[] NOT NULL DEFAULT ARRAY['personal','organizational','agent'],
lifecycle_stage TEXT NOT NULL DEFAULT 'governance',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL DEFAULT 'system',
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'platform',
business_domain TEXT NOT NULL DEFAULT 'governance',
UNIQUE(account_id, entity_type)
);
promotion_queue
CREATE TABLE promotion_queue (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
memory_item_id TEXT NOT NULL REFERENCES memory_items(spine_network_id),
memory_scope TEXT NOT NULL,
memory_type TEXT NOT NULL,
subject_refs TEXT[] NOT NULL,
canonical_domain TEXT NOT NULL,
canonical_entity_type TEXT NOT NULL,
proposed_by TEXT NOT NULL,
proposed_at TIMESTAMPTZ NOT NULL DEFAULT now(),
confidence NUMERIC(4,3),
origin TEXT NOT NULL,
promotion_status TEXT NOT NULL DEFAULT 'proposed', -- proposed | approved | committed | rejected
reviewed_by TEXT,
reviewed_at TIMESTAMPTZ,
rejection_reason TEXT,
committed_at TIMESTAMPTZ,
canonical_record_id TEXT,
canonical_version INTEGER,
lifecycle_stage TEXT NOT NULL DEFAULT 'governance',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
app_category TEXT NOT NULL DEFAULT 'platform',
business_domain TEXT NOT NULL DEFAULT 'governance'
);
5. Memory Architecture
Four distinct memory scopes with different contracts, write authorities, lifetimes, and promotion paths.
| Scope | Persisted In | Keyed By | TTL / Lifecycle | Who Can Write | Who Can Read | Promotable |
|---|---|---|---|---|---|---|
| Personal | Durable Objects + KV | user_id + memory_type + subject_snid | 30 days | User direct; Twin proposes with user approval | User only | Yes |
| Organizational | Postgres / D1 | tenant_id + entity_snid + memory_type | Permanent | Twin proposed + human approved; human with write RBAC | All users with read RBAC on domain + agents in session context | Yes |
| Agent | Durable Objects | session_id + entity_snid + (account_id + user_id) | Session only | Twin agent only during session | Twin agent for that session only; user sees output, not raw agent memory | Yes |
| Operational | KV / Redis | account_id + entity_type + projection_key | 7 days | System pipeline only | Projection Engine internal only; no direct human read | False |
Every memory item carries:
scope:personal | organizational | agent | operationalmemory_type:observation | decision | context | fact | signal | continuity_checkpointsubject_refs: entity SNIDscontent: text or JSONB payloadorigin:human | twin | pipeline | systemconfidence: 0-1 for AI-originretention_policy:session | 7d | 30d | 90d | permanentpromotion_eligible: booleanpromotion_status:none | proposed | approved | committed | rejected
6. Promotion Queue Lifecycle
The only path from memory to canonical truth.
MEMORY ITEM (any scope)
-> promotion_eligible = true
-> [PROPOSED]
Auto-propose: agent scope, confidence >= 0.85, entity exists
Manual-propose: human flags any memory item
-> [REVIEW GATE]
Auto-approve: system-origin facts, pipeline signals confidence = 1.0
Human-approve: Twin observations, decisions, org memory, confidence < 0.85
-> [APPROVED] -> COMMIT WORKER -> Canonical DB append-only write -> promotion_status = committed
-> [REJECTED] -> promotion_status = rejected, reason logged, memory retained
promotion_queue table fields:
queue_id TEXT PRIMARY KEY— format:pq_{ulid}memory_item_id TEXT NOT NULL REFERENCES memory_items(spine_network_id)memory_scope TEXT NOT NULLmemory_type TEXT NOT NULLsubject_refs TEXT[] NOT NULLcanonical_domain TEXT NOT NULLcanonical_entity_type TEXT NOT NULLproposed_by TEXT NOT NULLproposed_at TIMESTAMPTZ NOT NULL DEFAULT now()confidence NUMERIC(4,3)origin TEXT NOT NULLpromotion_status TEXT NOT NULL DEFAULT 'proposed'reviewed_by TEXTreviewed_at TIMESTAMPTZrejection_reason TEXTcommitted_at TIMESTAMPTZcanonical_record_id TEXTcanonical_version INTEGER
7. Connector Extension Schema
7.1 connector_extensions
Sidecar table for connector-specific fields without polluting canonical schema.
CREATE TABLE connector_extensions (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
canonical_entity_id TEXT NOT NULL,
canonical_entity_type TEXT NOT NULL,
connector_id TEXT NOT NULL REFERENCES connector_catalog(spine_network_id),
installation_id TEXT NOT NULL REFERENCES connector_installations(spine_network_id),
source_record_id TEXT NOT NULL,
source_record_url TEXT,
extension_data JSONB NOT NULL DEFAULT '{}',
schema_version TEXT NOT NULL DEFAULT '1.0',
last_synced_at TIMESTAMPTZ NOT NULL DEFAULT now(),
sync_hash TEXT,
lifecycle_stage TEXT NOT NULL DEFAULT 'activation',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL DEFAULT 'pipeline',
promotion_id TEXT,
app_category TEXT NOT NULL,
business_domain TEXT NOT NULL,
UNIQUE(canonical_entity_id, connector_id)
);
7.2 connector_extension_schemas
CREATE TABLE connector_extension_schemas (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL DEFAULT 'platform',
connector_id TEXT NOT NULL REFERENCES connector_catalog(spine_network_id),
manifest_version TEXT NOT NULL,
entity_type TEXT NOT NULL,
fields JSONB NOT NULL DEFAULT '[]',
is_active BOOLEAN NOT NULL DEFAULT true,
lifecycle_stage TEXT NOT NULL DEFAULT 'activation',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL DEFAULT 'system',
promotion_id TEXT,
app_category TEXT NOT NULL,
business_domain TEXT NOT NULL,
UNIQUE(connector_id, manifest_version, entity_type)
);
7.3 connector_extension_registry
CREATE TABLE connector_extension_registry (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
installation_id TEXT NOT NULL REFERENCES connector_installations(spine_network_id),
connector_id TEXT NOT NULL REFERENCES connector_catalog(spine_network_id),
entity_type TEXT NOT NULL,
extension_count INTEGER NOT NULL DEFAULT 0,
last_extension_at TIMESTAMPTZ,
schema_version TEXT NOT NULL,
lifecycle_stage TEXT NOT NULL DEFAULT 'activation',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL DEFAULT 'system',
promotion_id TEXT,
app_category TEXT NOT NULL,
business_domain TEXT NOT NULL,
UNIQUE(account_id, installation_id, entity_type)
);
7.4 Extension Merge Rules
- RBAC governs extension field visibility via
rbac_visiblearrays in the connector manifest. - Extension fields are namespaced:
salesforce.lead_source,hubspot.hs_lead_status. - Canonical fields always win on conflict.
- Merge happens at projection time: canonical + permitted namespaced extension fields + field-level RBAC.
7.5 User Work Lifecycle Stage
users.work_lifecycle_stage dimension:
onboarding— simplified canvas, personal memory initialized but emptyactive— full canvas, personal memory accumulating, Twin activecontext_switching— canvas rebuilding, previous projection archived, personal memory tagged withrole_changeoffboarding— read-only canvas, no write actions, memory promoted/archived per retention policy, Twin sessions closedinactive— no canvas, auth blocked, memory retained per retention policy
Written by platform at key events: invite accepted, first connector configured, role change detected, offboarding initiated, account suspended.
8. Adaptive Workbench Tuner Schema
8.1 workbench_signals
CREATE TABLE workbench_signals (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
user_id TEXT NOT NULL REFERENCES users(spine_network_id),
session_id TEXT NOT NULL,
signal_type TEXT NOT NULL,
projection_key TEXT NOT NULL,
block_id TEXT,
column_id TEXT,
entity_type TEXT,
payload JSONB NOT NULL DEFAULT '{}',
occurred_at TIMESTAMPTZ NOT NULL DEFAULT now(),
lifecycle_stage TEXT NOT NULL DEFAULT 'operation',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL DEFAULT 'system',
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'platform',
business_domain TEXT NOT NULL DEFAULT 'operations'
);
8.2 tuner_proposals
CREATE TABLE tuner_proposals (
spine_network_id TEXT PRIMARY KEY,
account_id TEXT NOT NULL REFERENCES tenants(account_id),
user_id TEXT REFERENCES users(spine_network_id), -- null = tenant-level proposal
projection_key TEXT NOT NULL,
template_level TEXT NOT NULL, -- user | tenant
proposal_type TEXT NOT NULL, -- block_reorder | column_hide | filter_default | sort_default | block_collapse | action_promote | action_remove | view_reorder
target_block_id TEXT,
target_column_id TEXT,
proposed_change JSONB NOT NULL,
signal_count INTEGER NOT NULL DEFAULT 1,
confidence NUMERIC(4,3) NOT NULL,
auto_approve BOOLEAN NOT NULL DEFAULT false,
promotion_status TEXT NOT NULL DEFAULT 'none',
promotion_queue_id TEXT,
lifecycle_stage TEXT NOT NULL DEFAULT 'scale',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version INTEGER NOT NULL DEFAULT 1,
origin TEXT NOT NULL DEFAULT 'system',
promotion_id TEXT,
app_category TEXT NOT NULL DEFAULT 'platform',
business_domain TEXT NOT NULL DEFAULT 'operations'
);
8.3 Tuner Signal Types
| signal_type | trigger | tuner interpretation |
|---|---|---|
block_skipped | User scrolls past a block without interacting | Low-value block for this role; candidate for collapse/reorder |
block_collapsed | User manually collapses a block | Strong preference for hidden-by-default |
column_hidden | User hides a table column | Low-value column; candidate for default-hidden |
column_pinned | User pins a column left | High-value column; candidate for wider default width |
filter_applied | User applies a filter chip | Frequent filter; candidate for default filter |
filter_cleared | User clears default filter | Default filter is wrong |
row_clicked | User opens row detail | Signals cared-about entities; feeds Twin context |
kpi_tile_clicked | User drills into KPI tile | KPI is high-value; candidate for promotion to header |
action_used | User triggers a row action | High-value action; candidate for more prominent placement |
action_ignored | Action exists but unused over N sessions | Action may be irrelevant for this role |
view_switched | User switches between views | Default view may be wrong |
sort_changed | User changes sort order | Default sort is wrong |
session_duration | Time spent on a surface | Low duration = surface may not serve this user |
8.4 Auto-Tuning Eligibility Thresholds
These thresholds apply only to reversible presentation preferences. They never
authorize canonical writes, organizational policy changes or external actions.
Tenant-level changes require human approval.
| proposal_type | template_level | trigger signal types | min signal count | min confidence | local presentation auto-apply eligible |
|---|---|---|---|---|---|
column_hide | user | column_hidden | 3 across 3+ sessions | 0.80 | true |
column_hide | tenant | column_hidden | 10 | 0.90 | false |
filter_default | user | filter_applied, filter_cleared | 5 | 0.85 | true |
filter_default | tenant | filter_applied | 15 | 0.90 | false |
sort_default | user | sort_changed | 3 | 0.80 | true |
sort_default | tenant | sort_changed | 10 | 0.88 | false |
block_collapse | user | block_collapsed | 2 | 0.75 | true |
block_collapse | tenant | block_collapsed | 8 | 0.85 | false |
block_reorder | user | block_skipped, session_duration | 5 | 0.80 | false |
block_reorder | tenant | block_skipped | 20 | 0.85 | false |
action_promote | user | action_used | 5 | 0.85 | false |
action_promote | tenant | action_used | 20 | 0.90 | false |
action_remove | user | action_ignored | 10 | 0.90 | false |
action_remove | tenant | action_ignored | 30 | 0.92 | false |
view_reorder | tenant | view_switched | 15 | 0.85 | false |
kpi_promote | user | kpi_tile_clicked | 4 | 0.80 | false |
Tenant-level proposals are always human-reviewed.
8.5 Tuner Proposal JSONB Shape
{
"proposal_type": "column_hide",
"target": {
"projection_key": "proj:sales_rep:revenue:acct_01J9:pipeline",
"block_id": "b_deals_grid",
"column_field": "margin"
},
"change": {
"operation": "set_field_state",
"field": "margin",
"from": "VISIBLE",
"to": "OMITTED"
},
"rationale": "Field hidden by user in 4 of last 5 sessions.",
"signal_summary": {
"signal_type": "column_hidden",
"signal_count": 4,
"sessions_observed": 5,
"first_observed": "2026-07-20T09:14:00Z",
"last_observed": "2026-07-27T16:42:00Z"
}
}
9. Canvas View Projection JSONB Schema
Canvas projections are stored as JSONB in projection_manifests.
9.1 projection_manifests Table
CREATE TABLE projection_manifests (
manifest_id TEXT PRIMARY KEY, -- mfst_{ulid}
projection_key TEXT NOT NULL, -- proj:{role_slug}:{domain}:{account_id}:{view_name}
role_slug TEXT NOT NULL,
domain TEXT NOT NULL,
view_name TEXT NOT NULL,
template_level TEXT NOT NULL, -- system | tenant | user
tenant_id TEXT, -- NULL for system templates
user_id TEXT, -- NULL for system and tenant templates
version INTEGER NOT NULL DEFAULT 1,
canvas JSONB NOT NULL,
created_by TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
archived_at TIMESTAMPTZ -- NULL if active
);
9.2 Canonical JSONB Canvas Structure
{
"manifest_id": "mfst_01J9XK...",
"projection_key": "proj:sales_rep:revenue:acct_01J9:pipeline",
"view_name": "Pipeline",
"role_slug": "sales_rep",
"domain": "revenue",
"zones": [
{
"zone_id": "z_header",
"zone_type": "header",
"blocks": [
{
"block_id": "b_title",
"block_type": "markdown",
"content": "## My Pipeline",
"rbac_visible": ["sales_rep", "sales_manager", "cro"]
},
{
"block_id": "b_kpi",
"block_type": "kpi_strip",
"tiles": [
{
"label": "Open Pipeline",
"formula": "[deals].Filter([owner_id]=User().Id And [status]='open').[value].Sum()",
"format": "currency"
},
{
"label": "Deals This Month",
"formula": "[deals].Filter([owner_id]=User().Id And [close_date]<=Today()).Count()",
"format": "number"
},
{
"label": "Win Rate",
"formula": "[deals].Filter([owner_id]=User().Id And [status]='won').Count() / [deals].Filter([owner_id]=User().Id).Count()",
"format": "percent"
},
{
"label": "Avg Deal Size",
"formula": "[deals].Filter([owner_id]=User().Id And [status]='open').[value].Average()",
"format": "currency"
}
]
}
]
},
{
"zone_id": "z_main",
"zone_type": "work_surface",
"blocks": [
{
"block_id": "b_deals_grid",
"block_type": "table",
"entity": "deals",
"filter_formula": "[owner_id] = User().Id And [status] != 'lost'",
"sort": [{ "field": "close_date", "direction": "asc" }],
"columns": [
{ "field": "name", "label": "Deal", "width": 200, "rbac_field_state": "VISIBLE" },
{
"field": "account_name",
"label": "Account",
"width": 160,
"rbac_field_state": "VISIBLE"
},
{ "field": "stage", "label": "Stage", "width": 120, "rbac_field_state": "VISIBLE" },
{ "field": "value", "label": "Value", "width": 100, "rbac_field_state": "VISIBLE" },
{
"field": "close_date",
"label": "Close Date",
"width": 110,
"rbac_field_state": "VISIBLE"
},
{ "field": "margin", "label": "Margin", "width": 80, "rbac_field_state": "OMITTED" },
{ "field": "owner_id", "label": "Owner", "width": 120, "rbac_field_state": "VISIBLE" }
],
"row_actions": [
{
"label": "Update Stage",
"capability": "deal.update_stage",
"approval_required": false
},
{
"label": "Log Activity",
"capability": "deal.log_activity",
"approval_required": false
},
{
"label": "Request Discount",
"capability": "deal.request_discount",
"approval_required": true
}
]
}
]
},
{
"zone_id": "z_twin",
"zone_type": "twin_panel",
"blocks": [
{
"block_id": "b_twin",
"block_type": "twin_panel",
"activation": "on_row_click",
"session_scoped": true,
"read_entities": ["deals", "accounts", "signals", "tasks"],
"write_mode": "proposal_only",
"memory_scope": "agent"
}
]
}
]
}
9.3 Canvas Block Type Registry
| block_type | purpose | data binding | RBAC enforcement | key JSONB fields |
|---|---|---|---|---|
callout | Coloured alert/info/tip/critical box | Static text or inline formula | rbac_visible[] array | block_type, style, content, dismissible, icon, rbac_visible[] |
markdown | Rich text paragraph/headings/lists | Static content only | rbac_visible[] | block_type, content, rbac_visible[] |
kpi_strip | Horizontal KPI tiles | CFL formula against RBAC-filtered Operational DB | Post-RBAC formula result | block_type, tiles[] with label, formula, format, tooltip |
table | Full grid table bound to entity collection | entity, filter_formula, columns[], sort[] | Column rbac_field_state; row-level filter_formula | block_type, entity, filter_formula, columns[], sort[], group_by, row_actions[], page_size |
card_grid | Card layout over entity rows | Same as table, rendered as cards | Column rbac_field_state; row-level filter_formula | block_type, entity, filter_formula, card_fields[], sort[], row_actions[] |
chart | Bar/line/pie/area chart | CFL aggregate or entity + group_by + measure | Post-RBAC | block_type, chart_type, formula or {entity, group_by, measure, filter_formula}, x_axis, y_axis, color_by |
timeline | Horizontal timeline of events | entity + filter_formula + event_field + label_field | Row-level filter_formula | block_type, entity, filter_formula, event_field, label_field, color_by_field, zoom_default |
form | Input form for create/update | entity, fields[] from entity schema | Only writable fields for role rendered; submit gated by capability RBAC | block_type, entity, form_mode, fields[], submit_capability, approval_required |
button | Action trigger | capability_key, payload_formula | Capability RBAC at invocation | block_type, label, capability_key, payload_formula, approval_required, confirm_message, disabled_formula |
twin_panel | Contextual AI panel | Session-scoped read-only projection | Read: RBAC-filtered agent projection; write: NONE | block_type, activation, session_scoped, read_entities[], write_mode, memory_scope, approval_card_enabled |
approval_card | Inline approval card for pending Promotion Queue record | promotion_id, proposal payload, evidence refs | Approver RBAC | block_type, promotion_id, proposal_summary, evidence_refs[], confidence, actions, expiry_at |
divider | Visual separator | None | Always visible | block_type, style |
9.4 Canvas Manifest Registry — System Templates Per Role
| Role | View Name | Domain | projection_key | zone layout |
|---|---|---|---|---|
| Sales Rep | Pipeline | Revenue | proj:sales_rep:revenue:{acct}:pipeline | header + main + twin |
| Sales Rep | My Leads | Revenue | proj:sales_rep:revenue:{acct}:leads | header + main + twin |
| Sales Manager | Team Pipeline | Revenue | proj:sales_mgr:revenue:{acct}:team_pipeline | header + main + twin |
| CRO / VP Sales | Revenue Dashboard | Revenue | proj:cro:revenue:{acct}:dashboard | header + chart_row + main + twin |
| CS Manager | Account Grid | Revenue+Operations | proj:cs_mgr:revenue:{acct}:accounts | header + main + twin |
| CS Manager | Renewals Pipeline | Revenue | proj:cs_mgr:revenue:{acct}:renewals | header + main + twin |
| Finance Manager | Invoice Dashboard | Finance | proj:finance:finance:{acct}:invoices | header + main + twin |
| Finance Manager | Cashflow Forecast | Finance | proj:finance:finance:{acct}:cashflow | header + chart_row + main + twin |
| HR Manager | People Directory | People | proj:hr_mgr:people:{acct}:people | header + main + twin |
| HR Manager | Hiring Pipeline | People | proj:hr_mgr:people:{acct}:hiring | header + main + twin |
| Engineering Manager | Sprint Board | Product | proj:eng_mgr:product:{acct}:sprint | header + main + twin |
| Engineering Manager | Incident Dashboard | Product+Operations | proj:eng_mgr:product:{acct}:incidents | header + main + twin |
| Support Agent | Ticket Queue | Operations | proj:support:operations:{acct}:queue | header + main + twin |
| IT Manager | Security Dashboard | Operations+Platform | proj:it_mgr:operations:{acct}:security | header + main + twin |
| CEO / Founder | Company Pulse | All Domains | proj:ceo:all:{acct}:pulse | header + chart_row + main + twin |
| AI Twin | Contextual Panel | Session-scoped | proj:twin:{acct}:{session}:panel | twin_panel only |
10. RBAC View Projection Model
Every view is a projection, not a raw DB read. The Projection Engine applies three filters before data reaches the Operational DB cache:
- Domain Filter — which entity types this role can see at all
- Field Filter — which fields within those entities are visible (field-level RBAC)
- Row Filter — which rows are visible (ownership, team scope, account scope)
projection_key format: proj:{role_slug}:{domain}:{account_id}:{view_name}
Resolution flow:
USER OPENS A VIEW
-> Projection Engine: role_id + domain + lifecycle_stage + view_name
-> CACHE HIT (Operational DB / KV): return in < 50ms
-> CACHE MISS: query Canonical DB with all three RBAC filters
shape result into projection_manifest layout (JSONB)
write to Operational DB with TTL
return to workbench
10.1 Field Visibility States
VISIBLE— field is included in the projection, rendered normallyMASKED— field is included but value replaced with[RESTRICTED]for audit trail purposesOMITTED— field is not included in the projection at all
Immutable fields (spine_network_id, account_id, created_at, origin, promotion_id) are always OMITTED from projections.
10.2 RBAC Projection Matrix
| Role | Business Domain | Entities Visible (full) | Entities Visible (partial) | Entities Hidden | Field-Level Restrictions | Row-Level Scope |
|---|---|---|---|---|---|---|
| Platform Operator | Revenue, People, Product, Operations, Finance, Legal, Communications, Knowledge, Platform | None — full schema visible across all tenants | None | None | No field restrictions. Raw spine_network_id and account_id visible for debugging. | All tenants, all workspaces |
| Tenant Admin | Revenue, People, Product, Operations, Finance, Legal, Communications, Knowledge, Platform | All entities within own tenant: accounts, contacts, leads, deals, employees, positions, invoices, contracts, tickets, features, bugs, deployments, connectors, users, roles, permissions, audit_events | None | Other tenants’ data | compensation_records visible only if also HR Manager role; security_events visible only if also IT Manager role. compensation_records.salary, compensation_records.equity OMITTED unless HR Manager role also held. | Own tenant only |
| CEO / Founder | Revenue, People, Product, Operations, Finance, Legal, Communications, Knowledge | accounts, contacts, deals, opportunities, leads, employees, positions, teams, invoices, payments, budgets, cashflow_snapshots, contracts, obligations, tickets, features, bugs, releases, deployments, incidents, projects, milestones, strategic_goals, board_items, investor_updates, fundraising_pipeline, company_metrics, signals, proposals, approvals | None | None | No field restrictions. | All tenants, all accounts, all workspaces |
| CRO / VP Sales | Revenue, Communications, Knowledge | leads, contacts, accounts, opportunities, deals, quotes, sales_activities, sales_sequences, forecast_snapshots, routing_rules, territories, quota_plans, revenue_metrics, attribution_events, campaigns (read), communication_threads, messages, calendar_events, meetings, calls, knowledge_articles | invoices (status + overdue_count only), contracts (status + expiry_date only), employees (name + title only for team members) | compensation_records, budgets (detail), expenses, vulnerabilities, bugs, deployments, payroll | invoices.amount OMITTED. contracts.terms_text OMITTED. contracts.value MASKED. employees fields except name, title, department OMITTED. | All accounts in tenant |
| Sales Manager | Revenue, Communications, Knowledge | leads, contacts, accounts, opportunities, deals, quotes, sales_activities, sales_sequences, forecast_snapshots, communication_threads, messages, calendar_events, meetings, calls | invoices (status only), contracts (status + expiry only), employees (own team: name + title only) | compensation_records, budgets, expenses, all Product entities, all People entities except own team | invoices.amount OMITTED. contracts.value OMITTED. employees fields except name, title OMITTED. | Own team only; assigned accounts |
| Sales Rep | Revenue, Communications, Knowledge | leads (own), contacts (own accounts), accounts (assigned), opportunities (own), deals (own), quotes (own), sales_activities (own), communication_threads (own), messages (own), calendar_events (own), calls (own) | accounts (assigned only — health score visible, no billing detail), knowledge_articles (public) | All Finance, Legal, People, Product, Platform entities. Accounts not assigned to self. | accounts.billing_status OMITTED. accounts.ltv OMITTED. deals.margin OMITTED. | Own accounts, own contacts, own opportunities, own deals, own quotes |
| Customer Success Manager | Revenue, Operations, Communications, Knowledge | accounts (assigned), account_contacts, account_health_logs, account_tasks, account_playbooks, account_signals, renewals, adoption_milestones, tickets (linked to own accounts), tasks (own + account), communication_threads (own accounts), meetings, calls, knowledge_articles | deals (stage + close_date only), invoices (billing_status + overdue_count only), contracts (expiry_date + renewal_date only), employees (name + title only) | compensation_records, budgets, expenses, leads (unassigned), all Product internals, all IT/Security | deals.value OMITTED. invoices.amount OMITTED. contracts.terms_text OMITTED. employees fields except name, title OMITTED. | Own accounts only |
| Marketing Manager | Revenue, Communications, Knowledge | campaigns, campaign_members, content_assets, attribution_events, audience_segments, marketing_spend, forms, leads (all), contacts (all), communication_threads, messages, knowledge_articles | accounts (name + tier + industry only), deals (stage + value range only), invoices (none — omitted) | compensation_records, contracts, tickets, features, bugs, deployments, employees | accounts.health_score OMITTED. accounts.billing_status OMITTED. deals.margin OMITTED. | All leads, all contacts |
| RevOps Manager | Revenue, Operations, Knowledge | pipelines, pipeline_stages, routing_rules, territories, quota_plans, forecast_models, revenue_metrics, leads (all), deals (all), accounts (all), contacts (all), projects, milestones, workflows, operational_metrics | invoices (revenue metrics only), employees (headcount + department only), contracts (status only) | compensation_records (individual), tickets, bugs, deployments, security_events | compensation_records.salary OMITTED. invoices.amount OMITTED. | All accounts, all tenant |
| Finance Manager / CFO | Finance, Legal, Operations, Knowledge | invoices, payments, subscriptions, expenses, budgets, vendors, cashflow_snapshots, company_metrics, fundraising_pipeline, contracts, obligations, legal_requests, projects, milestones, operational_metrics | accounts (billing_status + ltv + arr only), deals (value + close_date only), employees (headcount + cost_band only) | compensation_records (individual salary), communications (personal), product_events, bugs, deployments | compensation_records.salary OMITTED. communication_threads.body OMITTED. employees.performance_rating OMITTED. | All accounts, all tenant |
| Legal Counsel | Legal, Finance, Operations, Knowledge | contracts, contract_parties, obligations, legal_requests, policies, compliance_controls, evidence_requests, invoices (value + status), vendors, employees (employment_terms only), accounts (contract status) | deals (value + close_date only), projects (legal milestones only), company_metrics (fundraising) | compensation_records (individual), communication_threads (personal), product_events, tickets, bugs | compensation_records.salary OMITTED. communication_threads.body OMITTED. deals.margin OMITTED. | All contracts, all tenant |
| HR Manager | People, Finance, Knowledge | employees, positions, teams, onboarding_plans, performance_cycles, leave_records, compensation_records, job_requisitions, candidates, interviews, offers, people_signals | accounts (name only — for client-facing employee context), projects (people-related only) | deals, invoices, contracts, tickets, bugs, deployments, communication_threads (personal), signals (non-people) | accounts.health_score OMITTED. deals.value OMITTED. invoices.amount OMITTED. | All employees, all tenant |
| Engineering Manager | Product, Operations, Communications, Knowledge | features, bugs, sprints, roadmap_items, releases, repositories, deployments, incidents, alerts, slo_records, post_mortems, tasks (engineering), projects (engineering), milestones, communication_threads (own team), meetings (own team), knowledge_articles | accounts (adoption_tier + health_score only), employees (own team: name + title + performance_rating) | compensation_records (salary/equity), invoices, contracts, leads, deals, marketing entities | compensation_records.salary OMITTED. compensation_records.equity OMITTED. accounts.arr OMITTED. | Own team items |
| Product Manager | Product, Revenue, Communications, Knowledge | features, bugs, roadmap_items, sprints, releases, requirements, product_events, adoption_milestones, accounts (adoption_tier + health_score), communication_threads (own), meetings, knowledge_articles | deals (stage only), employees (name + title only), invoices (none) | compensation_records, contracts, legal_requests, security_events, deployments (infra detail) | compensation_records OMITTED. contracts.value OMITTED. deals.margin OMITTED. | All projects, all tenant |
| Support Agent | Operations, Communications, Knowledge | tickets, cases, sla_policies, sla_events, escalations, support_interactions, csat_responses, tasks (own), communication_threads (own), messages (own), knowledge_articles | accounts (name + tier + health_score only), contacts (name + email + role only) | compensation_records, invoices, contracts, deals, bugs (internal), deployments, employees | accounts.arr OMITTED. accounts.billing_status OMITTED. contacts.personal_phone OMITTED. | Own tickets |
| IT Manager | Operations, Platform, Knowledge | systems, assets, licenses, certificates, vulnerabilities, access_requests, security_controls, incidents (IT), connectors, connections, api_clients, api_keys, audit_events, deployments (infra) | employees (name + provisioning_status only), accounts (system_usage only) | compensation_records, invoices, contracts, deals, marketing entities, product_events | compensation_records OMITTED. invoices.amount OMITTED. contracts.terms_text OMITTED. | All systems, all tenant |
| Operations Manager | Operations, Knowledge | projects, milestones, dependencies, processes, workflows, operational_metrics, tasks (all), work_items (all), queues, assignments, sla_policies, vendors, strategic_goals, board_items | accounts (name + health_score only), employees (name + team only), invoices (budget_status only) | compensation_records, deals (detail), contracts (detail), bugs, deployments, security_events | compensation_records OMITTED. deals.value OMITTED. contracts.terms_text OMITTED. | All projects, all workflows, all tenant |
| AI Twin (Agent Read Projection) | Revenue, Operations, Product, Communications, Knowledge | accounts (health_score, tier, signals), contacts (name, role, last_contact), deals (stage, value, close_date), tickets (status, priority, sla_status), features (status, adoption), tasks (title, status, due_at), signals (all), proposals (pending), communication_threads (entity-linked, session-scoped), knowledge_articles, memory_items (org scope, agent scope) | employees (name + title only), invoices (billing_status only), contracts (expiry_date only) | compensation_records, budgets, expenses, security_events, credential_refs, audit_events, personal memory of other users | ALL financial amounts OMITTED. ALL compensation fields OMITTED. ALL personal contact details beyond name+role OMITTED. spine_network_id OMITTED. promotion_id OMITTED. | Session account scope only |
11. Connector Extension Registry Table (Field Visibility by Role)
| Connector | Canonical Entity | Extension Field | Field Type | Label | Roles With Visibility |
|---|---|---|---|---|---|
| salesforce | deals | salesforce.lead_source | string | Lead Source | sales_rep, sales_manager, cro, founder |
| salesforce | deals | salesforce.forecast_category | string | Forecast Category | sales_manager, cro, founder |
| salesforce | deals | salesforce.competitor | string | Competitor | sales_manager, cro, founder |
| salesforce | deals | salesforce.next_step | string | Next Step | sales_rep, sales_manager, cro, founder |
| salesforce | contacts | salesforce.lead_status | string | Lead Status | sales_rep, sales_manager, cro |
| salesforce | contacts | salesforce.mailing_city | string | City | sales_rep, sales_manager, cro, founder |
| hubspot | deals | hubspot.hs_deal_stage_probability | number | Stage Probability | sales_manager, cro, founder |
| hubspot | contacts | hubspot.hs_lead_status | string | Lead Status | sales_rep, sales_manager, cro, founder |
| hubspot | accounts | hubspot.hs_analytics_source | string | First Touch Source | marketing_manager, cmo, founder |
| stripe | accounts | stripe.payment_method_fingerprint | string | Payment Fingerprint | finance_director, founder |
| stripe | invoices | stripe.payment_intent_id | string | Payment Intent | finance_director, founder |
| stripe | accounts | stripe.customer_id | string | Stripe Customer ID | sales, finance_director, founder |
| stripe | accounts | stripe.subscription_status | string | Subscription Status | sales, finance_director, founder |
| slack | activities | slack.channel_id | string | Slack Channel | sales_rep, sales_manager, cro |
| slack | activities | slack.thread_ts | string | Thread Timestamp | founder, sales_rep, sales_manager, cro |
| linear | tasks | linear.issue_id | string | Linear Issue ID | founder, engineering_lead |
| linear | tasks | linear.priority | number | Linear Priority | founder, engineering_lead |
| greenhouse | contacts | greenhouse.candidate_stage | string | Candidate Stage | hr_manager, founder |
| greenhouse | contacts | greenhouse.job_title_applied | string | Applied Role | hr_manager, founder |
| quickbooks | contacts | quickbooks.qb_invoice_id | string | QB Invoice ID | finance_director, founder |
| quickbooks | invoices | quickbooks.vendor_type | string | Vendor Type | finance_director, founder |
12. Execution Map — Schema Entity × Dev × Customer Zero × Product
| Schema Entity | Schema Page | Entity Type | Canonical Table | Dev Owner | Dev Status | Dev Blocker / Next Action | Customer Zero Status |
|---|---|---|---|---|---|---|---|
| tenants | 6 | Canonical Table | spine worker | Live on main | 114-table Neon schema live on main as of Jul 27. FORTRESS_DATABASE_URL bound. | Seed | |
| users | 6 | Canonical Table | spine worker + Clerk auth module | Live on main | Clerk is canonical auth. Descope is dev fallback. work_lifecycle_stage field needs wiring to onboarding completion API. | Seed | |
| roles | 6 | Canonical Table | spine worker | Live on main | System roles seeded in Neon fortress seed. Custom role creation UI pending. | Seed | |
| connector_catalog | 6 | Canonical Table | connector worker + schema-ai worker | Live on main | 64-connector catalog seeded Jul 28 with real logos. Vercel logo is 147-byte placeholder — needs real SVG asset. | Seed | |
| connector_installations | 6 | Canonical Table | connector worker + integration-management-mcp | Live on main | Activation endpoints live Jul 23. MCP pool scoped per tenant/user. OAuth release blocker resolved Jul 24. | Seed | |
| accounts | 6 | Canonical Table | spine worker + connector pipeline | Live on main | Table live in Neon. Connector pipeline writes on sync. No UI blocker. | Seed | |
| contacts | 6 | Canonical Table | spine worker + connector pipeline | Live on main | Table live. people domain projection active. | Seed | |
| deals | 6 | Canonical Table | spine worker + connector pipeline | Live on main | Table live. Revenue domain projection active. Deal stage pipeline view rendered via canvas manifest. | Seed | |
| connector_extensions | 7 | Extension Pattern | connector worker + schema-ai worker | In progress | Sidecar table schema defined. connector_extension_schemas table needs migration. Merge at projection time not yet wired into Projection Engine. | Pending | |
| connector_extension_schemas | 7 | Extension Pattern | schema-ai worker | In progress | Schema-AI service born Jul 19. Manifest parsing logic in progress. connector_extension_schemas migration pending. | Pending | |
| connector_extension_registry | 7 | Extension Pattern | connector worker | Pending | Depends on connector_extension_schemas migration. No blocker beyond sequencing. | Pending | |
| tasks | 6 | Canonical Table | spine worker + connector pipeline | Live on main | Table live. project_management app_category wired. operations domain projection active. | Seed | |
| activities | 6 | Canonical Table | spine worker + connector pipeline | Live on main | Table live. communication app_category wired. activities log projection active. | Seed | |
| signals | 6 | Canonical Table | pipeline worker | Live on main | Signal workflow wiring is a P1 TODO in intelligence worker. Pipeline emits signals but SignalWorkflow not yet wired to downstream consumers. | Seed | |
| invoices | 6 | Canonical Table | spine worker + connector pipeline | Pending | Billing connector (Stripe) not installed for Customer Zero. Table migrated but empty. | Pending | |
| playbooks | 6 | Canonical Table | pipeline worker + workflow worker | In progress | Playbook table live. Supabase Realtime event forwarding TODO in workflow worker. Playbook execution wiring in progress. | Pending | |
| memory_items | 6 | Canonical Table | continuity worker + twin-orchestrator | In progress | MorningBriefWorkflow wiring is P1 TODO in continuity worker. D1 brief storage TODO in intelligence worker. Personal and agent scopes partially wired. | Pending | |
| RBAC projection rules | 2 | Projection Rule | spine worker + Projection Engine (gateway) | In progress | Projection Engine defined Jul 21 (architecture freeze). SharedWorkbench contract shipped. D1 audit_log persistence TODO in gateway. Cache invalidation logic in progress. | Seed | |
| canvas projection manifests | 3 | Canvas / UI Contract | spine worker + cognitive workbench runtime | In progress | Cognitive workbench runtime shipped Jul 23. Canvas manifest JSONB being rendered. System templates per role defined in schema. Tenant/user override merge not yet wired. | Seed | |
| canvas_overrides | 6 | Canonical Table | cognitive workbench runtime + tuner | Pending | Table migrated. Override merge logic depends on tuner_proposals pipeline. Not yet wired end-to-end. | Pending | |
| personal memory scope | 4 | Memory Scope | continuity worker (Durable Objects per user_id) | In progress | Durable Objects wired. MorningBriefWorkflow P1 TODO. AI Search replacement P4 TODO. | Pending | |
| organizational memory scope | 4 | Memory Scope | continuity worker (Postgres/D1 — append-only) | Pending | Org memory scope table not yet migrated to Neon. Depends on continuity worker P1 completion. | Pending | |
| agent memory scope | 4 | Memory Scope | twin-orchestrator (Durable Objects per session) | In progress | Twin-orchestrator shipped. Wire to Act service in Phase 4 TODO. Session-scoped Durable Objects active. | Seed | |
| operational memory scope | 4 | Memory Scope | gateway + KV cache | Live on main | KV hot cache live. Operational DB projection cache active. TTL and invalidation working. | Seed | |
| promotion_queue | 5 | Queue / Event | spine worker + continuity worker | In progress | Promotion queue table live in Neon. Auto-promote logic for pipeline signals wired. Human approval review UI not yet built. | Pending | |
| teams | 6 | Canonical Table | spine worker | Pending | Table migrated. Team creation UI not built. Depends on Settings page expansion. | Not applicable | |
| team_members | 6 | Canonical Table | spine worker | Pending | Depends on teams table UI. | Not applicable | |
| approval_chains | 6 | Canonical Table | spine worker + gateway capability check | Pending | approval_chains table migrated. Capability check in gateway wired to RBAC. Custom chain definition UI not built. | Not applicable | |
| audit_log | 6 | Canonical Table | gateway worker | In progress | D1 audit_log persistence is a TODO in gateway. Datadog/Splunk compliance integration TODO. Table migrated. | Pending | |
| retention_policies | 6 | Canonical Table | spine worker + continuity worker | Pending | Table migrated. Retention enforcement logic not built. No blocker beyond prioritisation. | Not applicable | |
| workbench_signals | 8 | Tuner / Feedback | cognitive workbench runtime (frontend → KV) | Pending | Signal emission from frontend not yet wired. Frontend success/error toasts TODO. Workbench runtime shipped but signal capture not implemented. | Pending | |
| tuner_proposals | 8 | Tuner / Feedback | schema-ai worker + cognitive workbench runtime | Pending | Depends on workbench_signals being wired. Tuner aggregation logic not built. | Pending | |
| Salesforce extension (deals) | 7 | Extension Pattern | connector worker | Pending | Salesforce connector not installed for Customer Zero. Extension schema drafted in manifest format. | Pending | |
| HubSpot extension (contacts, accounts) | 7 | Extension Pattern | connector worker | In progress | HubSpot connector active for Customer Zero. Extension sidecar write not yet wired — connector writes to canonical tables only today. | Pending | |
| Linear extension (tasks) | 7 | Extension Pattern | connector worker | In progress | Linear connector active for Customer Zero. Extension sidecar write pending. | Pending | |
| Slack extension (activities) | 7 | Extension Pattern | connector worker | In progress | Slack connector active. Activity write wired. Extension sidecar (channel_id, thread_ts) pending. | Pending | |
| Marketplace catalog | 1 | Canvas / UI Contract | connector worker + apps/web (Cloudflare Pages) | Live on main | 64-connector catalog live. Marketing CTAs wiring to marketplace flow complete Jul 27. | Seed |
13. Frontend Projection Contract
The frontend renderer receives a fully-hydrated canvas projection JSONB document and renders it. It makes no schema decisions. It has no hardcoded column names. It has no hardcoded role logic.
What the frontend receives per view load:
{
"projection_key": "proj:sales_rep:revenue:acct_01J9:pipeline",
"rendered_at": "2026-07-28T10:00:00Z",
"ttl_seconds": 300,
"user": {
"user_id": "usr_01J9...",
"role_slug": "sales_rep",
"work_lifecycle_stage": "active"
},
"zones": [ ... ],
"available_actions": [
{"capability": "deal.update_stage", "label": "Update Stage", "approval_required": false},
{"capability": "deal.log_activity", "label": "Log Activity", "approval_required": false},
{"capability": "deal.request_discount", "label": "Request Discount", "approval_required": true}
],
"pending_approvals": 2,
"tuner_proposals_pending": 1
}
The frontend renders zones, surfaces available_actions, shows approval badges, and emits workbench_signals back. That is its entire contract with the backend.
14. Complete Frontend-to-Spine Loop
USER ACTION
-> [READ] Workbench renders canvas projection
Projection Engine: Spine → RBAC → canvas manifest → renderer
< 50ms from Operational DB cache
-> [WRITE] User edits a cell / triggers an action
Capability check: approval_chains
Human approval binds the exact proposal/version
Governed Spine Writer commits through the Promotion Queue
Signal emitted → pipeline → downstream playbooks
-> [BEHAVE] User interacts with the canvas surface
workbench_signals written (column_hidden, filter_applied, etc.)
Tuner aggregates signals → tuner_proposals
Proposals submitted to Promotion Queue
Approved proposals write to canvas_overrides
Projection Engine invalidates affected cache keys
Next render uses updated canvas manifest
15. Schema Layer Index
| Layer | Page | What it defines |
|---|---|---|
| Canonical tables | 06 | Every spine table, lifecycle stage, SQL shape |
| Connector extensions | 07 | How connectors extend entities without polluting canonical schema |
| RBAC projections | 02 | How roles filter entities and fields |
| Canvas manifests | 03 | How projections are laid out as JSONB for the renderer |
| Tuner | 08 | How the frontend feeds back into the spine |
| Memory | 04 | How observations accumulate |
| Promotion Queue | 05 | How memory becomes canonical truth |
| Entity domains | 01 | How app categories map to business domains |