Primitives
Three primitives, infinite possibilities.
The z0 SDK has exactly three primitives. Everything else is derived from or built on top of these.
Entity
Section titled “Entity”What: Identity and state container. Like a row in a database, but immutable.
When to use:
- Need unique identity for a domain object
- Building multi-tenant systems
- Tracking lifecycle (active, retired, deleted)
When NOT to use:
- Storing events themselves (use Facts)
- Configuration (use Config)
TypeScript Interface
Section titled “TypeScript Interface”interface Entity<T = Record<string, unknown>> { id: string; // Unique identifier type: string; // Domain category (e.g., 'account', 'asset') parent_id: string | null; // Parent entity ID (null = root) tenant_id?: string; // Tenant ownership version: number; // Optimistic concurrency control metadata: Record<string, unknown>; // Platform metadata data: T; // Domain-specific payload created_at: number; // Unix timestamp (ms) updated_at: number; // Unix timestamp (ms)
// GDPR compliance anonymized_at?: number; anonymization_reason?: 'gdpr_request' | 'data_retention' | 'manual'; anonymization_request_id?: string; original_data_hash?: string; // SHA-256 proof of original data
// Extension point for domain-specific indexing [key: string]: any;}Example
Section titled “Example”const account: Entity<{ balance: number }> = { id: 'acct_abc123', type: 'account', parent_id: null, tenant_id: 'tenant_xyz', version: 42, metadata: { status: 'active' }, data: { balance: 1000.00 }, created_at: 1704067200000, updated_at: 1704153600000};Lifecycle States
Section titled “Lifecycle States”| State | Description | Facts Accepted |
|---|---|---|
active | Normal operation | All |
retiring | Draining in progress | System only |
retired | Read-only, complete | None |
anonymized | GDPR-compliant | None |
deleted | Marked for cleanup | None |
What: Immutable event record. Once written, never changed.
When to use:
- Recording business events (payment, login, API call)
- Audit trail requirements
- Time-series data
- Event sourcing
When NOT to use:
- Storing current state (derive from Facts instead)
- Mutable data (append correction Facts)
TypeScript Interface
Section titled “TypeScript Interface”interface Fact<T = Record<string, unknown>> { id: string; // Unique fact identifier type: string; // Primary event category (e.g., 'payment') subtype?: string; // Refined action (e.g., 'completed') timestamp: number; // Business time (can be backdated) recorded_at?: number; // System time (always "now") seq?: number; // Monotonic sequence for replay
tenant_id: string; // Tenant isolation source_id?: string; // Tool/service that generated fact entity_id?: string; // Master entity ID correlation_id?: string; // Distributed tracing
data: T; // Domain-specific payload schema_version?: number; // For migrations (default: 1)
// Extension point [key: string]: any;}Example
Section titled “Example”const deposit: Fact<{ amount: number; currency: string }> = { id: 'fact_deposit_xyz', type: 'payment', subtype: 'deposit', timestamp: 1704153600000, recorded_at: 1704153601000, seq: 127, tenant_id: 'tenant_xyz', entity_id: 'acct_abc123', correlation_id: 'trace_456', data: { amount: 500.00, currency: 'USD' }, schema_version: 1};Fact Taxonomy
Section titled “Fact Taxonomy”Facts follow a two-level taxonomy:
- type: Broad category (e.g.,
payment,lifecycle,webhook) - subtype: Specific action (e.g.,
completed,failed,retrying)
System Fact Types:
lifecycle- Entity state changeswebhook- Delivery eventscache_invalidated- Cache bustingentity_retired,entity_anonymized,entity_deleted
Config
Section titled “Config”What: Versioned configuration. Changes create new versions, never overwrite.
When to use:
- Routing rules
- Pricing tiers
- Feature flags
- Policies that change over time
When NOT to use:
- Environment variables (use Cloudflare secrets)
- Per-request state (use middleware)
- Frequently-changing data (use Facts)
TypeScript Interface
Section titled “TypeScript Interface”interface Config<T = Record<string, unknown>> { id: string; // Unique config identifier tenant_id: string; // Owner tenant type: string; // Config category category: string; // Logical grouping name: string; // Human-readable name applies_to: string; // Target entity type/ID scope: string; // Access level
version: number; // Auto-incrementing effective_at: number; // When this version activates superseded_at?: number | null; // When replaced by newer version
settings: T; // The actual configuration}Example
Section titled “Example”const pricingConfig: Config<{ tiers: Tier[] }> = { id: 'pricing_standard', tenant_id: 'tenant_xyz', type: 'pricing', category: 'subscription', name: 'Standard Plan Pricing', applies_to: 'subscription', scope: 'tenant', version: 3, effective_at: 1704067200000, superseded_at: null, settings: { tiers: [ { ending_quantity: 100, unit_price_cents: 200 }, { ending_quantity: 1000, unit_price_cents: 100 }, { ending_quantity: null, unit_price_cents: 50 } ] }};Scope Priority
Section titled “Scope Priority”| Scope | Priority | Use Case |
|---|---|---|
global | 10 | Platform defaults |
tenant | 20 | Tenant overrides |
entity | 30 | Entity-specific |
Higher priority wins during resolution.
Summary Table
Section titled “Summary Table”| Primitive | Mutable | Versioned | Use For |
|---|---|---|---|
| Entity | Yes (via version) | Yes | Identity, state container |
| Fact | No | Yes (schema_version) | Events, audit trail |
| Config | No (new version) | Yes | Configuration, policies |
Related Types (Not Primitives)
Section titled “Related Types (Not Primitives)”These are TypeScript types used with primitives, not primitives themselves:
| Type | Purpose |
|---|---|
CachedState | Derived views stored in EntityLedger (rebuilt from Facts) |
InvariantSettings | Runtime validation rules (stored as Config) |
EntityLifecycleState | Lifecycle state enum (active, retiring, retired, etc.) |
EntityMigrationState | Migration state enum |
AnonymizationReason | GDPR anonymization reasons |
BudgetMode | Budget enforcement mode |