Data model
Every tenant-owned primary and foreign key includes tenant_id. Database row-level security is
defence in depth; application authorization remains mandatory. Public identifiers are random
ULIDs/UUIDv7-like values, never sequential customer counts.
Core ER model
Section titled “Core ER model”erDiagram
TENANT ||--o{ LEGAL_ENTITY : contains
TENANT ||--o{ USER : authorises
LEGAL_ENTITY ||--o{ PROCESSING_ACTIVITY : owns
PURPOSE ||--o{ PROCESSING_ACTIVITY : justifies
PROCESSING_ACTIVITY }o--o{ SYSTEM : uses
PROCESSING_ACTIVITY }o--o{ PROCESSOR : sends_to
NOTICE_VERSION }o--|| PURPOSE : describes
DATA_PRINCIPAL_REF ||--o{ CONSENT_RECEIPT : acts
NOTICE_VERSION ||--o{ CONSENT_RECEIPT : proves
DATA_PRINCIPAL_REF ||--o{ RIGHTS_REQUEST : submits
RIGHTS_REQUEST ||--o{ FULFILMENT_TASK : dispatches
RETENTION_RULE ||--o{ DISPOSAL_JOB : schedules
LEGAL_HOLD }o--o{ DISPOSAL_JOB : blocks
INCIDENT ||--o{ STATUTORY_CLOCK : triggers
INCIDENT ||--o{ NOTIFICATION : produces
VENDOR ||--o{ PROCESSOR : provides
PROCESSOR ||--o{ SUBPROCESSOR : delegates
CONNECTOR ||--o{ SYNC_RUN : executes
AUDIT_EVENT }o--|| TENANT : records
SQL-oriented definitions
Section titled “SQL-oriented definitions”create table tenant ( tenant_id uuid primary key, slug text not null unique, status text not null check (status in ('trial','configuring','live','suspended','offboarding','deleted')), time_zone text not null, deployment_profile text not null, key_ref text not null, created_at timestamptz not null, version bigint not null default 1);
create table data_principal_ref ( tenant_id uuid not null references tenant, principal_ref uuid not null, entity_id uuid not null, subject_hmac bytea not null, source_namespace text not null, reidentification_connector_id uuid not null, status text not null, created_at timestamptz not null, last_seen_at timestamptz, primary key (tenant_id, principal_ref), unique (tenant_id, entity_id, source_namespace, subject_hmac));
create table consent_receipt ( tenant_id uuid not null, receipt_id uuid not null, principal_ref uuid not null, purpose_version_id uuid not null, notice_version_id uuid not null, action text not null check (action in ('grant','deny','withdraw')), occurred_at timestamptz not null, recorded_at timestamptz not null, channel text not null, proof_json jsonb not null, previous_receipt_id uuid, receipt_hash bytea not null, idempotency_key_hash bytea not null, primary key (tenant_id, receipt_id), unique (tenant_id, idempotency_key_hash));
create table rights_request ( tenant_id uuid not null, request_id uuid not null, entity_id uuid not null, principal_ref uuid, request_type text not null, state text not null, source_clock_id uuid, business_target_at timestamptz, identity_assurance_level text, assigned_team_id uuid, resource_version bigint not null default 1, submitted_at timestamptz not null, closed_at timestamptz, primary key (tenant_id, request_id));create index rights_request_queue_idx on rights_request (tenant_id, state, business_target_at) where closed_at is null;
create table audit_event ( tenant_id uuid not null, event_id uuid not null, sequence bigint not null, occurred_at timestamptz not null, actor_type text not null, actor_ref text not null, action text not null, resource_type text not null, resource_id text not null, correlation_id uuid not null, reason_code text, details_redacted jsonb not null, previous_hash bytea, event_hash bytea not null, primary key (tenant_id, event_id), unique (tenant_id, sequence)) partition by range (occurred_at);All foreign keys in production migrations include tenant ID. Examples abbreviate some composite references for readability.
Entity catalogue
Section titled “Entity catalogue”- tenant/access:
Tenant,LegalEntity,BusinessUnit,Brand,User,Group,Role,RoleBinding,ServiceAccount,Approval; - legal/control:
Source,InstrumentVersion,ApplicabilityAssessment,Obligation,Control,EvidenceArtifact,Exception; - inventory:
System,Dataset,DataField,Classification,ProcessingActivity,DataFlow; - consent:
Purpose,PurposeVersion,Notice,NoticeVersion,Translation,ConsentReceipt,Preference,PropagationTask; - Principal operations:
DataPrincipalRef,IdentityMatch,RightsRequest,Grievance,Nomination,FulfilmentTask,SecureMessage,DisclosurePackage; - retention:
RetentionPolicy,RetentionRule,LegalHold,DisposalJob,DeletionCertificate; - third party:
Vendor,Processor,Subprocessor,Contract,Assessment; - incident:
Incident,BreachAssessment,AffectedPopulation,StatutoryClock,Notification,RegulatorReport; - assurance:
DPIA,Audit,AlgorithmicSystem,Finding,Remediation; - integration:
Connector,IntegrationCredentialRef,SyncRun,WebhookDelivery,DeadLetter; - evidence:
AuditEvent,ExportManifest.
Encryption classification
Section titled “Encryption classification”| Class | Example | Protection |
|---|---|---|
| public metadata | source title, control ID | integrity/signature |
| tenant confidential | purpose, system, vendor | envelope encryption at rest |
| restricted operational | cases, incident, nominee | per-tenant DEK, field encryption for select text |
| secret | OAuth token, private key | external secrets manager; reference only |
| raw customer PII | source/disclosure content | avoid; bounded encrypted object with expiry if needed |
Search indexes contain redacted projections. Sensitive free text is not placed in logs, metrics or traces.
Subject pseudonymisation
Section titled “Subject pseudonymisation”The customer agent computes HMAC-SHA-256(tenant_subject_key, namespace || stable_customer_id).
The control plane stores the HMAC and random Principal ref. Re-identification calls the scoped
customer connector after policy/assignment checks. Rotate by dual-key migration; never use an
unsalted plain hash of email/mobile/Aadhaar.
Deletion and history
Section titled “Deletion and history”Use immutable versions and explicit supersession for legal decisions, notices, receipts, contracts and evidence. Soft delete is not a substitute for disposal: operational records use state/history; personal content receives physical deletion or crypto-erasure after holds/retention. Audit events retain minimised identifiers and action evidence under an approved rule.
Synthetic record
Section titled “Synthetic record”{ "principal_ref": "subj_H7K4Q2", "display_label": "Synthetic Customer 0042", "source_namespace": "demo-core", "purpose": "PUR-DEMO-SERVICE", "notice": "NOT-DEMO-2", "real_person": false}