Usage rules, rollout plan, and final notes
Part of the Universal Audit Log Specification. Open Mercato reference (§19), usage rules for Constellation apps (§20), the rollout plan (§21), testing requirements (§22), known cleanup (§23), spelling consistency notes (§24), and the final implementation recommendation (§25).
19. Open Mercato Reference
19.1 What Open Mercato Does Well
Open Mercato implements audit/history as a shared core module with useful patterns: central shared module, reusable history UI, explicit snapshots and computed diffs, separate action/access logs, and related-resource history support.
19.2 What Constellation Should Not Copy
Constellation SHOULD NOT copy Open Mercato's command-bus-centric audit design. Constellation is tool-layer-centric, uses Prisma in apps / raw SQL in platform, and does not need undo/redo coupling. Borrow structural ideas, not the command bus.
20. Usage Rules for Constellation Apps
20.1 Mandatory Rules
- Every state-changing tool MUST write an audit entry.
- Audit writes MUST happen inside the same transaction as the domain mutation.
- Apps MUST use shared platform audit APIs.
- Apps MUST NOT create app-local audit tables for domain mutations.
- Repositories MUST NOT write audit rows directly.
- Route handlers MUST NOT bypass tools for auditable mutations.
- Failed and denied operations MUST be audited with
outcome: 'FAILURE'oroutcome: 'DENIED'. - Background jobs and event handlers MUST use audit capture points defined in Section 6.1.
20.2 Diff Rules
CREATEchangescontains{ after: ... }or a normalised field map
UPDATEchangescontains only fields that actually changed
DELETEchangescontains{ before: ... }or a normalised deletion snapshot
- sensitive fields
- MUST be redacted via the redaction framework (Section 18) before persistence
20.3 IP Address Rules
- Raw IP addresses MUST NOT be stored (see Section 9.4).
- IP extraction MUST use the trusted proxy chain, not raw
X-Forwarded-For. - Truncation to
/24(IPv4) or/48(IPv6) is applied at write time.
20.4 Enforcement
Audit coverage SHALL be enforced via automated checks that target mutating tools only. Read-only tools (e.g., queryAudit in audit.tools.ts) are explicitly exempt — they do not produce state changes and MUST NOT be forced to include meaningless audit calls.
- Typed wrapper convention: Mutating tool functions SHOULD use
withAuditedMutation()which makes audit capture structurally unavoidable. Tools that use this wrapper are automatically compliant. - Integration tests (primary enforcement): After running each mutating tool in the test suite, verify that an audit row exists with correct
action,resource_type,resource_id,tenant_id, andoutcome. This is the authoritative check — it validates behaviour, not file contents. - Optional static check (advisory): A CI lint rule MAY flag mutating tool files that contain no audit call as a warning, but it MUST NOT block merges. The integration test in (2) is the merge gate. The static check uses a naming convention or annotation (e.g.,
@audit-exemptcomment for read-only tools) to avoid false positives. - These checks SHALL be part of the CI pipeline.
21. Rollout Plan
Phase 1: Foundation
- Extend
audit.audit_entriesmigration with all new columns (organisation_id,parent_resource_type,parent_resource_id,context_json,entry_hash,previous_hash,session_id,user_agent,outcome,duration_ms,changed_fields). - Apply range partitioning on
created_atwith monthly partitions. - Create all indexes defined in Section 8.
- Define and document retention policy (Section 6.5); automate partition creation.
- Implement IP truncation at write time (Section 9.4); document retention alignment with architecture spec (Section 6.5).
- Implement
createAuditor(),withAuditedMutation(), andauditBatch(). - Implement
buildAuditDiff()with full specification (Section 10.4). - Implement
RedactionPolicyand default sensitive patterns (Section 18). - Add keyset cursor support to
queryAuditTrail()alongside existing offset/limit (Section 12.2). - Establish operational monitoring baseline (Section 14).
- Add integration test enforcement for mutating tools (Section 20.4).
- Add tests for new schema fields, query filters, diff generation, and redaction.
Phase 2: Directory as Reference Implementation
- Keep Directory as the reference implementation.
- Update audit-producing tools to use
createAuditor()and the richer contract. - Expand
apps/directory/src/server/tools/audit.tools.tsfor parent-resource, organisation, and outcome filters. - Implement granular audit access control (Section 13):
audit:read:own,audit:read:org,audit:read:tenant,audit:read:classified. - Implement tamper-evident chain (Section 11) with per-tenant chaining.
- Implement audit-of-audit-access logging (Section 13.3).
- Validate RLS and permission behaviour for tenant-scoped audit queries.
Phase 3: Catalog Adoption
- Update catalog tools to use normalised
resourceTypenaming. - Add before/after diffs to update and delete flows.
- Expose per-entry audit trail in Catalog UI once shared UI is ready.
Phase 4: Project-Tracker Migration
- Remove stub/no-op audit paths.
- Replace
src/lib/entity-audit.tsas the primary mechanism with explicit tool-layer writes. - Implement
/api/auditon top of shared platform queries. - Connect existing
AuditTrailUI to real shared audit data.
Phase 5: Shared UI Extraction
- Generalise the audit trail component for reuse across apps.
- Introduce standard display adapters for actor/resource labels.
- Add related-history support where parent resource fields are present.
- Implement streaming export for compliance (Section 15).
Phase 6: Defence-Tier Hardening
- SIEM integration (Section 17).
- Chain integrity verification job with alerting (Section 11.5).
- Archival automation: detach old partitions, export to cold storage (Section 6.5).
- Data residency controls for EU vs US defence tenants.
pg_auditextension for superuser action logging (Section 7.4).
22. Testing Requirements
22.1 Platform Tests
- Schema migration: all columns, partitioning, immutability triggers, JSON validation.
- Query filters: all fields including organisation, outcome, changed_fields; keyset pagination stability.
buildAuditDiff(): property tests, nested flattening, array diffs, 64 KB truncation, redaction,ignoreFields.- Pseudonymisation: HMAC generation, actor mapping CRUD, GDPR deletion flow.
- Ergonomic helpers:
createAuditor(),withAuditedMutation(),auditBatch(). - Redaction: default patterns, custom policies, double-exposure prevention in
auditCritical().
22.2 Module Integration Tests
For each module: every tool creates an audit row matching actor/action/resource/module/outcome; updates persist only changed fields; deletes preserve before-state; failed and denied operations produce appropriate outcome values; tenant isolation holds; organisation-scoped queries return only matching entries.
22.3 UI Tests
Audit panel loads and paginates (keyset); diffs render correctly; related-resource history toggles; outcome badges display; empty and error states are stable.
22.4 Enforcement Tests
CI check confirms every tool file contains an audit call. Integration suite verifies audit row existence after each tool execution.
23. Known Cleanup Required
The following repo state should be corrected during rollout:
apps/project-tracker/src/app/api/audit/route.ts- currently returns a stubbed empty result
apps/project-tracker/src/lib/audit.ts- currently contains stub auth audit logging
apps/project-tracker/src/lib/entity-audit.ts- currently logs debug output instead of canonical audit rows
packages/platform/testing/README.md- still references
identity.audit_login an example; canonical table isaudit.audit_entries
- still references
24. Spelling Consistency
This specification and all implementation code SHALL use British spelling consistently, matching the existing Constellation codebase:
organisation(notorganization)normalised(notnormalized)behaviour(notbehavior)serialisation(notserialization)
Database columns, API fields, and TypeScript types SHALL all follow this convention: organisation_id, organisationId.
25. Final Recommendation
Constellation should implement universal audit logging as:
- a shared platform library capability
- backed by the shared
auditschema with range partitioning and defined retention - captured explicitly in each module's tool layer and other defined capture points
- protecting PII surface via IP truncation and context_json prohibition, with actor identity retained per GDPR Article 17(3) exemptions
- secured by granular access control with audit-of-audit-access
- queried through shared platform APIs with keyset pagination
- rendered through reusable audit-history UI components
- hardened with tamper-evident per-tenant hash chains
- monitored with operational metrics and SLOs
- exportable for compliance reporting and SIEM integration
This is aligned with the approved Constellation architecture and uses Open Mercato appropriately as a pattern reference rather than a framework to copy.