Sentin8:Sys — Business Requirements & Functionality
Audience: product owners, business analysts, and anyone evaluating what Sentin8:Sys does for the business. For architecture read
README.md; for wire-level detail readDESIGN.md.
1. Business Purpose
Sentin8:Sys is the platform's control plane. It owns the tenant registry (organizations, environments, app instances), service enablement, memberships and invitations, tenant branding, the hostname→instance resolver, the platform bootstrap surface, and the canonical audit trail. The business value it delivers:
- One tenant registry. Orgs, envs, and app instances are
platform-level facts every service needs at request time (tenant
resolution, branding, feature gating); they live in
sys.*tables owned by exactly one service. - Zero compile-time vertical knowledge. Sys knows nothing about
bank8, hotel8, or any other vertical — verticals register their admin
scopes, services, error codes, and listings at runtime
(
vertical enroll); sys only persists and serves them. - Authorization is data, not code. Shield policy sets, ReBAC relation tuples, and ABAC attributes are sys-owned rows per environment; per-service engines load and evaluate them. Sys is the durable substrate and the admin surface, not the evaluator.
- Immediate usability. An org/env exists the moment its creation call returns: the record, the access model, and the creator's membership are provisioned together in one request — the owner never waits for a background workflow, and a caller never has to retry because "the org isn't ready yet".
2. Business Scope (What the Service Provides)
| Area | Capabilities |
|---|---|
| Org lifecycle | Create (synchronous: record + full access model in one request), list, get, update, archive, delete — status machine active/suspended/archived |
| Env lifecycle | Create (synchronous, same contract), list, get, update, archive, delete — unique (org, slug), optional auth domain |
| App instances | Hostname→app mapping, OAuth client id, feature flags, scope/service whitelists, auth-mode/group-gate, custom-domain verification |
| App-environment bindings | App↔env bindings with slug uniqueness |
| Service enablement | Per-env service enablement (GET/PUT /v1/env/{id}/services) — emits sentin8:sys:service:updated so verticals react event-driven |
| Memberships & invitations | List/remove memberships; invitations (create/list/revoke/accept) with one-time tokens, expiry, email-bound acceptance |
| Branding | Org-level base + env-level override; merged view (non-empty wins) |
| Hostname resolver | GET /v1/resolve/hostname + auth-domain, scopes, auth-mode endpoints (BFF, Auth, Proxy, TLS all consume these) |
| Bootstrap | GET /v1/bootstrap — the dash's first-screen data (orgs the caller can reach, via auth's live group listing) |
| Audit trail | POST /v1/audit (M2M ingest, service stamped from the verified client_id) + GET /v1/audit (admin query with keyset pagination); canonical rows + local retry journal |
| Shield substrate | policy_sets, policy_relations, policy_principal_attrs per (env, service) — storage + admin surface |
| Vertical registry | GET /v1/verticals/services, GET /v1/scopes/catalog (open, pre-login) |
| Notifications | Invitation mails via the local post_outbox queue (same transaction) + the sys-post pusher to Post's send API |
| Events | Durable lifecycle events (outbox → Bus) + best-effort MemBus domain:changed for resolver refresh |
| Admin surfaces | RFW admin UI + Shield policy-admin API |
What the service does NOT own (business boundary)
| Out of scope | Owner |
|---|---|
| Identity / token issuance | Sentin8:Auth (sys provisions through auth's membership API — never its tables) |
| Roles/groups storage | Auth-owned rows; sys is a writer through the owner's API |
| MemBus transport | Valkey (sys publishes post-commit, best-effort) |
| Vertical domain records | Runtime-registered (vertical enroll); sys persists and serves only |
| Long-running business workflows | Sentin8:Flow (step engine, retries, DLQ) — no sys lifecycle rides it |
3. Business Capabilities
3.1 Tenant Lifecycle (the flagship family)
| Capability | Business rule |
|---|---|
| Org creation | Synchronous: org record + access-model provisioning (roles/nesting/groups/creator membership) through auth's API complete before the response — 200 means the org is fully usable; a provisioning failure rolls the org back (500), so nothing half-created survives |
| Env creation | Same synchronous contract; per-env access model + optional auth domain; the env's platform policy template is seeded before its access model so the very first env-scoped call passes |
| Archive/delete | Archive is reversible-ish state; delete cascades |
| Idempotent provisioning | All provisioning writes are upserts — a caller retrying a failed create converges to the same access model without duplicates |
3.2 Memberships & Invitations
| Capability | Business rule |
|---|---|
| Membership listing/removal | Org-scoped; gated by sys:read/sys:memberships:admin |
| Invitations | Create/list/revoke/accept; one-time token + expiry; status machine pending → accepted/revoked |
| Email-bound acceptance | The token must carry the invited email (proof-of-possession); a mismatch is 403 |
| No fabricated groups | Acceptance assigns sentin8:org:{org_id}:admins through auth's API; a missing access model fails 409 — acceptance never invents groups |
| Acceptance atomicity | Status + group assignment + audit + event in ONE transaction |
| Invitation mails | Ride the local post_outbox in the same domain transaction; the sys-post pusher (10s loop) drains to Post — a Post outage never drops notifications |
3.3 Resolver, Branding, Enablement
| Capability | Business rule |
|---|---|
| Hostname resolver | Read-only, sys:instances:read-gated — tenant resolution data cannot be mutated through it |
| Branding merge | Env override → org base, non-empty wins; merged is read-only |
| Service enablement | Per-env toggles + config; every change emits sentin8:sys:service:updated — vertical services react event-driven (env-init pattern), the platform never special-cases them |
| MemBus invalidation | Post-commit domain:changed (org/env/app/branding scopes) so proxy/TLS resolvers refresh surgically; a Valkey outage degrades to their 30s safety poll — never fails the mutation |
3.4 Audit & Policy
| Capability | Business rule |
|---|---|
| Audit ingest | M2M-only (audit:write); service stamped from the verified DCR client_id — never caller-supplied; user tokens 403 |
| Canonical + journal | The ingest writes the canonical row AND a local journal row in one transaction — a downstream failure never loses the event |
| Audit query | Admin audit:read with service/action/env_id filters + keyset pagination; non-admins are forced to their own env |
| Shield substrate | Policy sets (origin platform/tenant, mode shadow/enforced, version), ReBAC relations, ABAC attributes per env; write-time validation; the admin surface manages them |
| Identity invalidation | sentin8:sys:identity:updated / policy:updated events (payload-complete) so consumers reload without callbacks |
| Bootstrap policy read | The SECURITY DEFINER sentin8_boot_policy_load(service) helper is the sanctioned cold-start read for NOBYPASSRLS engines |
4. Business Events (Outbound)
Event family sys (outbox-first, same transaction as the change):
| Event | When |
|---|---|
sentin8:sys:org:created/updated/archived/deleted | Org lifecycle |
sentin8:sys:env:created/updated/archived/deleted | Env lifecycle |
sentin8:sys:app:created/updated/archived | App instance lifecycle |
sentin8:sys:binding:created/deleted | Bindings |
sentin8:sys:service:updated | Service enablement (the env-init trigger) |
sentin8:sys:membership:removed | Membership removal |
sentin8:sys:invitation:sent/revoked/accepted | Invitation lifecycle |
sentin8:sys:audit:recorded | From BOTH the ingest API and every internal audit write — Stat's audit-volume aggregate sees the full platform volume |
Event family policy: sentin8:sys:identity:updated,
sentin8:sys:policy:updated (payload-complete envelopes).
Post-commit MemBus: sentin8:sys:domain:changed (ephemeral,
best-effort, scope-tagged).