Skip to main content

Ledger Data Model

Ledger manages three primary entities: Audit Events, Retention Policies, and Classifications. All entities use nanoid(8) identifiers and support both file-based and Convex storage backends.

AuditEvent

An immutable record of an action performed by an actor on a resource.

interface AuditEvent {
id: string; // nanoid(8) unique identifier
action: string; // Action performed (e.g., "service.deployed")
actor: string; // Who performed the action (user, service, or system)
resource: string; // The resource acted upon
metadata: Record<string, any>; // Additional context about the event
timestamp: string; // ISO 8601 timestamp
}

Notes

  • Audit events are append-only. Once emitted, they cannot be modified or deleted.
  • The action field uses dot-notation by convention (e.g., service.deployed, config.updated).
  • actor can be a user ID, service name, or system identifier like ci-pipeline.
  • metadata is freeform and can contain any event-specific context.

RetentionPolicy

A rule defining how long data in a given scope should be retained.

interface RetentionPolicy {
id: string; // nanoid(8) unique identifier
name: string; // Human-readable policy name
retentionDays: number; // Number of days to retain data
scope: string; // What this policy applies to (e.g., "ledger.events", "pulse.events")
createdAt: string; // ISO 8601 timestamp
}

Notes

  • scope uses dot-notation to identify the target (e.g., ledger.events, pulse.events, passport.audit).
  • Multiple policies can exist for different scopes. If scopes overlap, the most specific policy takes precedence.

Classification

A sensitivity label applied to a specific field within a service's data model.

interface Classification {
id: string; // nanoid(8) unique identifier
serviceId: string; // Reference to the service in Yellow Pages
field: string; // Dot-notation field path (e.g., "user.email")
level: string; // Classification level (e.g., "public", "internal", "confidential", "pii")
justification: string; // Reason for this classification
createdAt: string; // ISO 8601 timestamp
}

Classification Levels

LevelDescription
publicData that can be freely shared
internalData for internal use only
confidentialSensitive business data with restricted access
piiPersonally identifiable information subject to privacy regulations

Storage

File-Based (SHIFT_STORAGE=file)

.ledger/
events/
<id>.json # One file per audit event
policies/
<id>.json # One file per retention policy
classifications/
<id>.json # One file per classification

Convex (SHIFT_STORAGE=convex)

Tables use the ledger_ prefix:

TableDescription
ledger_eventsAudit event records
ledger_policiesRetention policy records
ledger_classificationsField classification records

Each record includes a sid field (shift ID) that maps to the application-level id. Convex internal _id fields are abstracted away by the ConvexStore layer.