Admin & Platform
Purpose
Admin & Platform serves two cross-cutting roles:
- Configuration and feature flags — runtime toggles for in-progress features, per-environment config, and tenant-level overrides. No redeploy required to change a flag.
- Append-only audit sink — every domain event flowing through the system is consumed and written to an immutable audit log, attributable to a specific tenant, user, and action.
Data owned
| Table | Purpose |
|---|---|
feature_flags |
Named boolean / variant flags with per-environment and per-tenant overrides |
config |
Structured key/value config with version history |
audit_log |
Immutable, append-only record of all domain events (one row per event) |
Internal API
Admin.* gRPC methods:
| Method | Description |
|---|---|
Admin.GetFlag |
Resolve a feature flag for a given tenant + environment context |
Admin.SetFlag |
Create or update a flag value (operator / deployment tool) |
Admin.ListFlags |
Enumerate all flags and their current resolved values |
Admin.GetConfig |
Read a config key with version |
Admin.SetConfig |
Write a config key (creates a new version; old version retained) |
Admin.QueryAuditLog |
Read audit log entries with filters (tenant, time range, event type) |
Feature flags
Feature flags are used to:
- Enable in-progress features in development or staging without exposing them in production.
- Roll out features to a subset of tenants (beta program, canary users).
- Disable a misbehaving feature at runtime without a redeploy.
Flags are evaluated at the call site in the relevant module; the Admin gRPC API is called (with a short Redis cache TTL) to resolve the current value.
| Scope | Override level |
|---|---|
| Global default | Applied to all tenants unless overridden |
| Environment override | Overrides global for a specific environment (dev / staging / prod) |
| Tenant override | Overrides environment for a specific tenant |
Audit log
The audit log is immutable and append-only:
- The Admin module consumes all domain events from NATS JetStream and writes one audit row per event.
- Rows are never updated or deleted. The log is a tamper-evident record.
- Each row attributes the event to a tenant, a user (actor), an action (event type), and a timestamp.
- Optional cryptographic chaining: each row’s hash includes the hash of the previous row, making tampering detectable by verification.
| Column | Description |
|---|---|
id |
Monotonic ID |
tenant_id |
Tenant the event belongs to |
actor_id |
User or service account that caused the event |
event_type |
Fully-qualified event name (e.g. node.changed, share.created) |
payload |
Full event payload (JSONB) |
at |
Event timestamp |
prev_hash |
Hash of the previous row (optional chaining) |
row_hash |
Hash of this row’s content + prev_hash |
Audit log queries are available to tenant admins (filtered to their tenant) and platform operators (cross-tenant).
Relation to observability
The audit log is a business-level record of “what did users do” — distinct from the operational observability stack (OpenTelemetry traces, metrics, structured logs). Both are populated from the same events, but serve different consumers: audit log for compliance/forensics, OTel for SRE/debugging. See the observability docs for the ops side.