🏢

TEN

P4 · Long-term · SaaS-ification Planned · P4 long-term Owner: CEO + CFO

The SaaS-ification module. Self-serve tenant signup, plan management, Stripe + VN-PSP billing, usage metering, tenant isolation invariants, 90-day offboarding grace. This is what unlocks CyberOS as an external product.

TEN is the module that takes CyberOS from an internal CyberSkill OS to an external multi-tenant SaaS. Until TEN lands, CyberOS is a single-tenant system operating under the tenant-as-degenerate-tenant decision (DEC-058 in SRS) — every multi-tenant invariant is already in place but the tenant population is one. TEN turns that population into N. It owns: self-serve signup with residency choice + plan selection ((FR pending)); Stripe (international) and Vietnamese PSP (domestic) billing ((FR pending)); plan tiers Starter (≤ 10 seats) / Team (≤ 50) / Enterprise (custom) ((FR pending)); per-tenant brand pack overriding the @cyberskill/tokens layer ((FR pending)); a tenant-admin UI surface for billing, seats, audit, residency, and retention overrides ((FR pending)); a signed bundle export of all tenant data — BRAIN + module data — for portability and DSAR ((FR pending)); and 90-day offboarding with irreversible delete + attestation ((FR pending)). It also owns usage metering — API calls, AI tokens, storage, seats — surfaced as both a tenant-admin dashboard and a revenue-ops feed. Tenant data isolation is the central invariant: every Postgres table has tenant_id RLS, every NATS subject is tenant-scoped, every S3 bucket prefix is tenant-scoped. The SOC 2 CC6.6 and ISO 27017 controls live here. PRD §9.22 and SRS §7.22 lock the FRs; this page documents the planned implementation at cyberos/services/ten/.

TEN is CyberOS's tenant lifecycle + billing + isolation control plane. It is the module without which CyberOS cannot exist as a paying-customer SaaS. The architecture is conventional: a Rust service for tenant CRUD + plan management + usage metering; Stripe for international card billing + invoicing; Vietnamese PSP integration (VnPay, Momo, ZaloPay) for VND domestic transactions; a tenant-admin SPA for seat management, audit-log review, residency / retention overrides; a signed-bundle exporter for portability + GDPR Art. 20. What is distinctive is the isolation invariant: TEN owns the per-tenant resource manifest (Postgres schema layout, NATS subject namespace, S3 bucket prefix, AI-gateway token quotas) and the verification harness that proves cross-tenant zero-leakage on every release. ARR / NDR / churn metrics roll up to a CFO dashboard. The 90-day offboarding grace is mandatory — even a hostile termination has 30 days of read-only access for export plus 60 days of dead-letter recoverability before irreversible wipe.

Status
Planned
P4 long-term
Plan tiers
3
Starter · Team · Enterprise
Billing
Stripe + VN-PSP
USD + VND multi-currency
Metering
4 axes
seats · API · AI tokens · storage
Isolation
3 layers
PG RLS · NATS subject · S3 prefix
Signup p95
≤ 30 s
end-to-end self-serve
Offboarding
90 d grace
30d read-only + 60d recover
Depends on
AUTH · BRAIN · all modules
+ Stripe · VnPay · Momo
1

Why TEN exists

CyberOS is multi-tenant by construction from day one — every table has tenant_id, every NATS subject is namespaced, every S3 bucket key is prefixed. But until TEN lands, the system runs as a single-tenant instance (DEC-058 — tenant-as-degenerate-tenant). TEN is the module that activates the second tenant, then the hundredth, then the thousandth. It owns three things: (1) tenant lifecycle — signup, plan change, suspension, offboarding; (2) billing — international (Stripe) + domestic VN (VnPay / Momo / ZaloPay); (3) the verification harness that proves tenant isolation has not regressed. Without TEN, CyberOS remains an internal tool. With TEN, CyberOS is a product.

🚀
Self-serve signup ≤ 30s

Org name, residency choice, plan, payment → tenant provisioned, first founder logged in. No "contact us" friction at Starter / Team tiers.

💳
Dual billing rails

Stripe for international + USD invoices; VnPay / Momo / ZaloPay for VND domestic. PCI scope is Stripe / PSP, never CyberOS.

🔒
Isolation is verifiable

The isolation harness in tests/ten/isolation/ runs 100k cross-tenant probes against PG / NATS / S3 on every release. Zero leaks is a release gate.

The bet is that the value of CyberOS unlocks at N>1 tenants — the BRAIN compounding, the audit chain, the agent surface — and TEN is the on-ramp. Pricing is plan-tier-anchored at Starter / Team / Enterprise; usage metering is informational at P4 (no per-API overage) but feeds future revenue-ops at P4+. The 90-day offboarding grace is partly a customer-experience commitment and partly a GDPR Art. 20 (portability) + Art. 17 (erasure) compliance posture.

2

What it does — 5W1H2C5M

Structured decomposition. Cells trace to PRD §9.22 + SRS §7.22.

AxisQuestionAnswer
5W · WhatWhat is TEN?A tenant lifecycle + billing + isolation control-plane service. Owns Tenant, Plan, Subscription, Seat, BrandingConfig, UsageMeter, RetentionPolicy. Integrates Stripe + Vietnamese PSPs. Operates the cross-tenant isolation verification harness.
5W · WhoWho uses it?Prospective customers: self-serve signup. Tenant admins: seat / billing / audit / retention via tenant-admin SPA. CFO (CyberSkill): ARR / NDR / churn dashboards. CCO (CyberSkill): upgrade routing. Agents: usage-metering scheduled jobs.
5W · WhenWhen does it run?On-demand for signup, plan change, offboarding. Continuous for usage metering (per-NATS-event aggregation). Daily for billing-reconciliation. Monthly for ARR snapshot + churn calculation.
5W · WhereWhere does it run?P4: SG-1 control plane; per-tenant data partition lives in the residency chosen at signup (vn-hanoi-1 for VN, sg-1 for SG, eu-fra-1 for EU at P4+). Stripe API in stripe.com regions; VN PSPs in VN.
5W · WhyWhy a separate module?Because the multi-tenant control plane is its own primary concern — distinct from any one feature module. SOC 2 / ISO 27017 expect this control plane to be auditable and isolated from the application layer.
1H · HowHow does it work?Signup flow: account create → residency pick → plan pick → payment method capture → tenant provision (schema namespace + S3 prefix + NATS subject + AUTH tenant row + first founder Subject + default RBAC seed) → SSO + first-login redirect. Usage metering: per-tenant NATS subject aggregator; nightly rollup; monthly invoice generation.
2C · CostCost budget?P4: control plane ~$60 / month (Fargate + Postgres for control state + Redis). Stripe pass-through fee 2.9% + 30¢; VN PSPs ~1.5% + 1,000 VND. Per-tenant ongoing infra: ~$5–$80 / month depending on plan.
2C · ConstraintsConstraints?(a) Zero cross-tenant data leakage (SOC 2 CC6.6 + N(FR pending)). (b) PCI scope minimisation — CyberOS never touches PAN. (c) Vietnamese PSP regulations (Circular 18/2018/TT-NHNN). (d) GDPR Art. 20 portability + Art. 17 erasure. (e) Tenant signup ≤ 30s p95.
5M · MaterialsStack?Rust 1.81 · axum · sqlx · PostgreSQL 16 · Redis 7 · Stripe Rust SDK · VnPay / Momo / ZaloPay HTTP clients · NATS JetStream · AWS Fargate · OpenTelemetry.
5M · MethodsMethod choices?Tenant provisioning is idempotent + atomic across modules (saga pattern). Usage metering is event-sourced (NATS aggregates → cumulative counters). Offboarding is two-phase: read-only-30d → recoverable-60d → wipe. Billing reconciliation is per-PSP scheduled job.
5M · MachinesDeployment?Fargate control-plane task + scheduled-job task. Per-tenant data partition keyed by residency-region.
5M · ManpowerWho maintains?0.6 FTE at P4 + revenue-ops part-time. CFO seat owns billing + revenue dashboards. CSO seat owns isolation verification.
5M · MeasurementHow measured?N(FR pending) (= 0 cross-tenant leaks), N(FR pending) (signup ≤ 30s p95). KPIs: ARR, NDR, churn, CAC, seat-utilisation per tenant, isolation-probe pass rate.
3

Architecture

TEN is a Rust control-plane service plus a tenant-admin SPA, integrated with Stripe + VN PSPs and a per-tenant usage-metering pipeline. Tenant provisioning is implemented as a saga across AUTH (create tenant + first Subject), BRAIN (initialise audit chain), all module DBs (create schema-scoped rows), and S3 (create bucket prefix). Offboarding is the inverse saga with a 90-day grace window.

graph TB subgraph PUBLIC ["Public surfaces"] SIGN["Signup SPA
(unauth)"] ADMIN["Tenant-admin SPA
(post-signup)"] BILL["Billing UI"] end subgraph TEN ["TEN service (Rust · axum)"] SU["signup.rs
signup flow"] PROV["provisioner.rs
tenant saga"] PLAN["plan.rs
plan / subscription CRUD"] SEAT["seat.rs
seat add/remove"] BRAND_S["branding.rs
brand pack"] METER["meter.rs
usage aggregation"] ISO["isolation.rs
verification harness"] OFFBOARD["offboard.rs
90d grace + wipe"] EXPORT["export.rs
signed bundle"] ARR["arr.rs
revenue rollup"] end subgraph PSP ["Payment partners"] STRIPE["💳 Stripe
international + USD"] VNPAY["🇻🇳 VnPay"] MOMO["🇻🇳 Momo"] ZALO["🇻🇳 ZaloPay"] end subgraph DOWNSTREAM ["Module orchestration"] AUTH_M["🔐 AUTH
tenant + founder Subject"] BRAIN_M["🧠 BRAIN
chain init"] ALL_M["all 21 modules
schema namespace"] S3_M["S3 prefix"] NATS_M["NATS subject"] AI_M["🧠 AI gateway
per-tenant quota"] end subgraph STORES ["Control-plane stores"] PG[("PostgreSQL
ten.tenant · plan
subscription · seat
branding · usage_meter
retention_policy")] REDIS[("Redis 7
signup-flow state")] NATS_USAGE[("NATS JetStream
tenant.*.usage.*")] end subgraph SINKS ["Audit + ops"] BRAIN["🧠 BRAIN
tenant.* rows"] OBS["👁 OBS"] CFO["💰 CFO dashboard
ARR / NDR / churn"] end SIGN --> SU ADMIN --> PLAN ADMIN --> SEAT ADMIN --> BRAND_S BILL --> PLAN SU --> PROV PROV --> AUTH_M PROV --> BRAIN_M PROV --> ALL_M PROV --> S3_M PROV --> NATS_M PROV --> AI_M PLAN --> STRIPE PLAN --> VNPAY PLAN --> MOMO PLAN --> ZALO NATS_USAGE --> METER METER --> PG ISO --> PG ISO --> NATS_M ISO --> S3_M OFFBOARD --> ALL_M EXPORT --> S3_M ARR --> CFO TEN --> BRAIN TEN --> OBS classDef planned fill:#e2e8f0,stroke:#1e293b classDef store fill:#f5f3ff,stroke:#7c3aed classDef sink fill:#f5ede6,stroke:#45210e classDef partner fill:#fef2f2,stroke:#7f1d1d class SIGN,ADMIN,BILL,SU,PROV,PLAN,SEAT,BRAND_S,METER,ISO,OFFBOARD,EXPORT,ARR,AUTH_M,BRAIN_M,ALL_M,S3_M,NATS_M,AI_M planned class PG,REDIS,NATS_USAGE store class BRAIN,OBS,CFO sink class STRIPE,VNPAY,MOMO,ZALO partner

Internal components

ComponentPath (planned)Responsibility
signup.rsservices/ten/src/signup.rsSelf-serve signup flow. Captures org name, residency choice, plan tier, founder email, payment method.
provisioner.rsservices/ten/src/provisioner.rsTenant provisioning saga. Idempotent + atomic across AUTH / BRAIN / module DBs / S3 / NATS / AI. Compensating actions on partial failure.
plan.rsservices/ten/src/plan.rsPlan CRUD. Subscription lifecycle. Feature flags per tier (e.g., LEARN locked at Starter, available at Team+).
seat.rsservices/ten/src/seat.rsSeat add / remove / invite. Enforces plan-tier seat caps.
branding.rsservices/ten/src/branding.rsPer-tenant brand pack — @cyberskill/tokens override layer. Logo, colour anchors, email templates, custom-domain integration with PORTAL.
meter.rsservices/ten/src/meter.rsUsage metering. NATS aggregator subscribes to tenant.{id}.usage.{kind} subjects; nightly rollup; monthly snapshot.
billing.rsservices/ten/src/billing.rsStripe integration: customer + subscription + invoice + webhook handling.
vnpsp.rsservices/ten/src/vnpsp.rsVnPay / Momo / ZaloPay adapters. Single trait, multiple impls. VND-denominated.
isolation.rsservices/ten/src/isolation.rsCross-tenant verification harness. 100k probes against PG RLS, NATS subject ACL, S3 prefix IAM on every release.
offboard.rsservices/ten/src/offboard.rs90-day offboarding flow: 30d read-only → 60d recoverable → wipe. Pre-generates export bundle.
export.rsservices/ten/src/export.rsSigned-bundle exporter. Full tenant data dump: BRAIN deterministic zip + per-module data + manifest with SHA-256 + Ed25519 signature.
retention.rsservices/ten/src/retention.rsPer-tenant retention policy override. Defaults: 30 days (logs), 365 days (audit), forever (legal docs).
arr.rsservices/ten/src/arr.rsRevenue rollup: ARR / MRR / NDR / GRR / churn / CAC. Daily snapshot, monthly review.
migrations/services/ten/migrations/sqlx migrations. Tenant rows in control plane; RLS on every row by tenant_id.
TEN-INV-001 · Zero cross-tenant data leakage

Three-layer enforcement: (1) PostgreSQL RLS keyed by tenant_id on every row in every module's database; (2) NATS subject ACL keyed by tenant.{id}.* namespace; (3) S3 bucket-prefix IAM scoped per tenant. The isolation harness runs 100k randomised cross-tenant probes against all three layers on every release; any leak halts deploys. SOC 2 CC6.6 + ISO 27017 control objective. Verification: tests/ten/isolation/ + nightly chaos in staging.

TEN-INV-002 · Tenant provisioning is atomic + idempotent

The provisioner saga has explicit compensating actions for partial failure at any of the ~8 steps (AUTH tenant, AUTH Subject, BRAIN init, module DB schemas, S3 prefix, NATS subject, AI quota, billing customer). Idempotent on replay via deterministic tenant slug. Property-tested with crash injection at every step.

4

Data model

Seven primitives: Tenant (the org), Plan (catalogue), Subscription (the active plan + billing state), Seat (paid headcount slot), BrandingConfig, UsageMeter (per-axis counter), RetentionPolicy. Audit lives in BRAIN.

erDiagram TENANT ||--o| SUBSCRIPTION : "has" TENANT ||--o{ SEAT : "owns" TENANT ||--o| BRANDING_CONFIG : "themed by" TENANT ||--o| RETENTION_POLICY : "configures" TENANT ||--o{ USAGE_METER : "consumes" TENANT ||--o{ INVOICE : "billed by" PLAN ||--o{ SUBSCRIPTION : "instantiated as" PLAN ||--o{ PLAN_FEATURE_FLAG : "exposes" SUBSCRIPTION ||--o{ INVOICE : "generates" SEAT ||--o| SUBJECT : "occupied by" TENANT { uuid id PK string slug string display_name string country "VN | SG | US | EU | …" string residency "vn-hanoi-1 | sg-1 | eu-fra-1" string status "provisioning | active | suspended | offboarding | grace | closed" timestamp created_at timestamp grace_until "if offboarding" string founder_subject_id } PLAN { string code PK "starter | team | enterprise | enterprise-vn" string display_name string currency "USD | VND" decimal monthly_price_minor int max_seats int ai_token_quota_monthly string features_json "feature flag map" } PLAN_FEATURE_FLAG { string plan_code FK string feature_code "learn | esop | doc | portal | …" bool enabled } SUBSCRIPTION { uuid id PK uuid tenant_id FK string plan_code FK string psp "stripe | vnpay | momo | zalopay" string psp_customer_id string psp_subscription_id string status "trialing | active | past_due | canceled | unpaid" date current_period_start date current_period_end timestamp updated_at } SEAT { uuid id PK uuid tenant_id FK uuid subject_id FK "null if invited but not accepted" string status "invited | active | suspended" timestamp added_at } BRANDING_CONFIG { uuid id PK uuid tenant_id FK string logo_s3_key string accent_color string typography_pack bytea email_template_overrides } USAGE_METER { uuid id PK uuid tenant_id FK string axis "api_call | ai_token | storage_gb | seat_count" date period_start decimal counter timestamp last_updated } RETENTION_POLICY { uuid tenant_id PK int log_retention_days "default 30" int audit_retention_days "default 365" bool legal_doc_forever "default true" int brain_retention_days "default -1 (forever, tombstone only)" } INVOICE { uuid id PK uuid subscription_id FK decimal amount_minor string currency string status "draft | open | paid | overdue | void" date period_start date period_end string psp_invoice_id timestamp paid_at }

Plan-tier matrix (planned)

PlanCurrencyPriceSeatsAI tokens/moModules locked
starterUSD$49 / mo10500kOKR · REW · ESOP · DOC · PORTAL
teamUSD$249 / mo503MESOP · DOC · PORTAL
enterpriseUSDcustomcustomcustomnone (all enabled)
starter-vnVND1,190,000 ₫ / mo10500kOKR · REW · ESOP · DOC · PORTAL
team-vnVND5,990,000 ₫ / mo503MESOP · DOC · PORTAL
enterprise-vnVNDcustomcustomcustomnone
5

API surface

Public REST for signup (unauth), federated GraphQL for tenant admin (post-signup), PSP webhook endpoints, and MCP tools for the tenant admin AI assistant.

GraphQL subgraph (federated, tenant-admin scope)

extend schema
  @link(url: "https://specs.apollo.dev/federation/v2.5", import: ["@key", "@external", "@shareable", "@requiresScopes"])

type Tenant @key(fields: "id") {
  id: ID!
  slug: String!
  displayName: String!
  country: String!
  residency: String!
  status: TenantStatus!
  subscription: Subscription
  seats: [Seat!]!
  branding: BrandingConfig
  usage: [UsageMeter!]!
  retentionPolicy: RetentionPolicy!
  createdAt: DateTime!
  graceUntil: DateTime
}

type Plan @key(fields: "code") {
  code: String!
  displayName: String!
  currency: String!
  monthlyPriceMinor: Int!
  maxSeats: Int!
  aiTokenQuotaMonthly: Int!
  features: [PlanFeatureFlag!]!
}

type PlanFeatureFlag {
  featureCode: String!
  enabled: Boolean!
}

type Subscription @key(fields: "id") {
  id: ID!
  plan: Plan!
  status: SubscriptionStatus!
  currentPeriodStart: Date!
  currentPeriodEnd: Date!
  psp: PspProvider!
}

type Seat @key(fields: "id") {
  id: ID!
  subjectId: ID
  email: String
  status: SeatStatus!
  addedAt: DateTime!
}

type BrandingConfig {
  logoUrl: String
  accentColor: String!
  typographyPack: String!
}

type UsageMeter {
  axis: UsageAxis!
  periodStart: Date!
  counter: Float!
}

type RetentionPolicy {
  logRetentionDays: Int!
  auditRetentionDays: Int!
  legalDocForever: Boolean!
  brainRetentionDays: Int!
}

type Invoice {
  id: ID!
  amountMinor: Int!
  currency: String!
  status: InvoiceStatus!
  periodStart: Date!
  periodEnd: Date!
  paidAt: DateTime
}

enum TenantStatus { PROVISIONING ACTIVE SUSPENDED OFFBOARDING GRACE CLOSED }
enum SubscriptionStatus { TRIALING ACTIVE PAST_DUE CANCELED UNPAID }
enum SeatStatus { INVITED ACTIVE SUSPENDED }
enum PspProvider { STRIPE VNPAY MOMO ZALOPAY }
enum UsageAxis { API_CALL AI_TOKEN STORAGE_GB SEAT_COUNT }
enum InvoiceStatus { DRAFT OPEN PAID OVERDUE VOID }

type Query {
  myTenant: Tenant! @requiresScopes(scopes: [["ten.admin"]])
  myInvoices(year: Int): [Invoice!]! @requiresScopes(scopes: [["ten.admin"]])
  availablePlans(country: String): [Plan!]!
}

type Mutation {
  changePlan(planCode: String!): Subscription! @requiresScopes(scopes: [["ten.admin"]])
  inviteSeat(email: String!): Seat! @requiresScopes(scopes: [["ten.admin"]])
  revokeSeat(seatId: ID!): Seat! @requiresScopes(scopes: [["ten.admin"]])
  updateBranding(input: BrandingInput!): BrandingConfig! @requiresScopes(scopes: [["ten.admin"]])
  setRetentionOverride(input: RetentionInput!): RetentionPolicy!
    @requiresScopes(scopes: [["ten.admin"]])
  initiateOffboarding(reason: String!): Tenant! @requiresScopes(scopes: [["ten.founder"]])
  cancelOffboarding: Tenant! @requiresScopes(scopes: [["ten.founder"]])
}

REST endpoints

MethodPathPurpose
GET/signup/plans?country=VNList available plans for a country.
POST/signup/startBegin signup; returns signup_token.
POST/signup/paymentAttach payment method (Stripe SetupIntent or VnPay vault).
POST/signup/finalizeProvision tenant; returns first-login redirect.
POST/billing/stripe/webhookStripe webhook (signature-verified).
POST/billing/vnpay/webhookVnPay IPN handler.
POST/billing/momo/webhookMomo IPN handler.
POST/billing/zalopay/webhookZaloPay IPN handler.
GET/tenants/{id}/export-bundleGenerate or fetch signed export bundle.
GET/tenants/{id}/usage.csv?period=YYYY-MMMonthly usage roll-up CSV.
POST/admin/isolation/probeTrigger isolation-harness run.
GET/admin/arr.jsonARR / NDR / churn snapshot (CFO scope).

MCP tool catalogue

Tool nameInputsOutputsAnnotations
cyberos.ten.tenant_statusTenantreadonly · scope=ten.admin
cyberos.ten.invite_seatemail{seat_id, invite_link}scope=ten.admin · human-confirm
cyberos.ten.revoke_seatseat_id{ok}destructive · scope=ten.admin · human-confirm
cyberos.ten.change_planplan_code{subscription}destructive · scope=ten.admin · founder-confirm
cyberos.ten.usage_reportperiodUsageReportreadonly
cyberos.ten.export_bundle{bundle_url, sha256}destructive · scope=ten.founder
cyberos.ten.initiate_offboardreason{grace_until}destructive · scope=ten.founder · human-confirm-twice
cyberos.ten.cancel_offboard{ok}destructive · scope=ten.founder
cyberos.ten.set_retentionRetentionInputRetentionPolicyscope=ten.admin · CLO-confirm if reducing
6

Key flows

Flow 1 — Self-serve tenant signup

sequenceDiagram autonumber participant U as Prospective customer participant SPA as signup SPA participant S as signup.rs participant ST as Stripe (or VnPay) participant P as provisioner.rs (saga) participant AUTH as 🔐 AUTH participant BRAIN as 🧠 BRAIN participant ALL as all 21 modules (schema init) participant S3 as S3 prefix participant NATS as NATS subject ACL participant AI as 🧠 AI gateway U->>SPA: choose plan, residency, org name, founder email SPA->>S: POST /signup/start S->>ST: create customer + setup intent ST-->>S: client_secret S-->>SPA: payment form U->>SPA: enter card (or VnPay redirect) SPA->>ST: confirm payment method ST-->>SPA: ok SPA->>S: POST /signup/finalize S->>P: run provisioning saga par tenant saga (atomic) P->>AUTH: createTenant + founder Subject + roles P->>BRAIN: init audit chain for tenant P->>ALL: provision schema for each module P->>S3: create bucket prefix s3://…/{tenant_id}/ P->>NATS: create subject ACL tenant.{id}.* P->>AI: register tenant + AI-token quota end P->>BRAIN: append tenant.provisioned root row P-->>S: ready S->>U: 302 redirect to first-login (magic link emailed to founder) Note over P: total elapsed ≤ 30s p95

The saga has compensating actions at every step. If any step fails after partial commit, the saga unwinds the prior steps and surfaces the failure to the user with a refund / retry path.

Flow 2 — Plan upgrade (Team → Enterprise)

sequenceDiagram autonumber participant F as Founder participant ADMIN as tenant-admin SPA participant PL as plan.rs participant ST as Stripe participant FF as feature_flag service participant B as 🧠 BRAIN F->>ADMIN: choose Enterprise → confirm ADMIN->>PL: changePlan(plan=enterprise) PL->>ST: update_subscription(items=[…enterprise…]) ST-->>PL: prorated invoice generated PL->>FF: refresh feature flags (DOC + PORTAL + ESOP unlock) FF->>FF: invalidate per-tenant cache PL->>B: append subscription.upgraded row {from:team, to:enterprise} PL-->>ADMIN: success ADMIN-->>F: "Upgrade complete — modules unlocked"

Flow 3 — Tenant offboarding (90-day grace)

sequenceDiagram autonumber participant F as Founder participant ADMIN as tenant-admin SPA participant O as offboard.rs participant E as export.rs participant PL as plan.rs participant CR as cron (daily sweep) participant ALL as all module DBs participant B as 🧠 BRAIN F->>ADMIN: initiateOffboarding(reason) ADMIN->>O: confirm-twice flow (typed slug) O->>PL: cancel subscription at period_end O->>E: pre-generate export bundle E->>ALL: dump per-tenant data (RLS-scoped) E->>BRAIN: BRAIN deterministic zip E->>O: bundle ready (s3://…/exports/{tenant}/bundle.zip + sig) O->>BRAIN: append tenant.offboarding_started row O-->>ADMIN: grace_until = now() + 30d Note over CR: day 1–30: read-only access; export downloadable Note over CR: day 31–90: tenant suspended; bundle still downloadable CR->>O: day 91 sweep O->>ALL: wipe tenant_id rows (cascading delete) O->>S3: wipe prefix O->>NATS: revoke subject ACL O->>BRAIN: append tenant.wiped row (audit fact survives) O->>F: email "Attestation: tenant X fully erased on YYYY-MM-DD"

Flow 4 — Brand customization (CNAME + theme)

sequenceDiagram autonumber participant F as Founder participant ADMIN as tenant-admin SPA participant BR as branding.rs participant PORTAL as 🌐 PORTAL service participant S3 as S3 (logo asset) participant ACM as AWS ACM participant B as 🧠 BRAIN F->>ADMIN: upload logo + pick accent color ADMIN->>S3: upload logo asset ADMIN->>BR: updateBranding(logo_s3_key, accent, typography) BR->>BR: validate (CSP-safe, hex colour, supported typography pack) BR->>PORTAL: notify branding refresh PORTAL->>PORTAL: invalidate edge cache alt custom CNAME requested F->>ADMIN: claim portal.tenantname.com ADMIN->>PORTAL: forward to cname.rs (PORTAL module) PORTAL->>ACM: request cert end BR->>B: append branding.updated row BR-->>ADMIN: success

Flow 5 — Usage metering rollup (per-tenant)

sequenceDiagram autonumber participant MODS as 21 module services participant NATS as NATS JetStream
tenant.{id}.usage.* participant M as meter.rs participant PG as PostgreSQL (usage_meter) participant CR as cron (nightly) participant ARR as arr.rs participant CFO as CFO dashboard participant B as 🧠 BRAIN loop continuous MODS->>NATS: publish tenant.{id}.usage.api_call (or .ai_token, .storage_gb) NATS->>M: deliver M->>PG: UPSERT usage_meter SET counter = counter + delta end Note over CR: nightly 02:00 ICT CR->>M: rollup snapshot for previous day M->>PG: write daily usage rows; flush per-event detail Note over CR: monthly 1st 03:00 ICT CR->>ARR: compute MRR / ARR / NDR / churn per tenant ARR->>PG: snapshot ARR->>CFO: push dashboard update ARR->>B: append revenue_snapshot.created row
7

Tenant lifecycle

A tenant traverses six states across its lifetime. Offboarding has a mandatory two-phase grace period (read-only 30 days + recoverable 60 days) before irreversible wipe.

stateDiagram-v2 [*] --> Provisioning: signup saga running Provisioning --> Active: saga completes successfully Provisioning --> Failed: saga compensation; refund Active --> Suspended: billing past_due > 14d OR admin action Suspended --> Active: payment recovered OR admin reactivate Active --> Offboarding: founder initiates close (confirm-twice) Suspended --> Offboarding: 60d past_due → auto-cancel Offboarding --> Grace: day 1 of 90d window Grace --> Active: founder cancels offboard (within 30d read-only window) Grace --> Closed: day 91 — sweep + wipe Closed --> [*] Failed --> [*]

Per-state actions

StateTriggerSide-effects
Provisioningsignup payment capturedSaga runs across 8 step; idempotent; compensation on failure.
ActiveSaga completeTenant usable; first-login email sent; AI quota armed; usage metering live.
SuspendedPast-due ≥ 14d OR adminLogin refused (soft "account paused"); data preserved; export still available.
OffboardingFounder confirm-twice OR auto from suspendedSubscription cancelled at period_end; export bundle pre-generated; emails sent.
Grace (day 1–30 read-only)Day 1 of graceRead-only access; banner; founder can cancel offboard.
Grace (day 31–90 recoverable)Day 31Login refused; bundle still downloadable; admin can re-instate via support.
ClosedDay 91Per-tenant rows wiped across modules; S3 prefix wiped; NATS ACL revoked; attestation emailed; tenant.wiped audit row remains in BRAIN (forever).
8

Functional Requirements

The CyberOS FR catalogue is being rebuilt one feature at a time via the open fr-author Agent Skill.

Previous FR enumerations were archived 2026-05-14 and are no longer reflected on this page. PRD/SRS narrative remains authoritative for the spec; specific FRs land here as they are re-authored.

9

Non-Functional Requirements

TEN's NFRs are dominated by tenant isolation and signup-flow performance — the two metrics that determine whether CyberOS can run as a SaaS at scale.

NFR IDConcernTargetMeasurement
N(FR pending)Cross-tenant data leakage incidents= 0 (sev-0)100k-probe isolation harness on every release + quarterly pen-test
N(FR pending)PSP webhook signature verification= 100% rejected unsignedintegration test
N(FR pending)PCI scopeSAQ-A (Stripe / PSP handles PAN)annual PCI attestation
N(FR pending)Tenant signup end-to-end p95≤ 30 sk6 + RUM
N(FR pending)Plan upgrade p95≤ 5 sk6
N(FR pending)Tenant-admin SPA TTFB≤ 500 msRUM
N(FR pending)TEN control-plane availability≥ 99.95%SLO monitor
N(FR pending)Tenant export bundle integrity= 100% sha256-verifiedcosign verification on every export
N(FR pending)Provisioning saga atomicity under crash injection0 inconsistent tenantschaos test (1000 runs)
N(FR pending)Usage-meter accuracy vs ground truth (NATS replay)≤ 0.5% drift / 24hweekly reconciliation
N(FR pending)SOC 2 CC6.6 control objectivepassed (annual)external audit
N(FR pending)ISO 27017 cloud-services controlspassedexternal audit
10

Dependencies

TEN depends on AUTH (tenant Subject), BRAIN (audit chain), Stripe + VN PSPs, and all 21 other modules (for schema provisioning + offboarding wipe). It is consumed by every CyberOS user-facing surface — every API call traverses TEN's plan / feature-flag / quota check.

graph LR subgraph upstream ["TEN depends on"] AUTH["🔐 AUTH"] BRAIN["🧠 BRAIN"] OBS["👁 OBS"] AI["🧠 AI gateway"] NATS["📡 NATS JetStream"] S3["🗄 S3"] STRIPE["💳 Stripe"] VNPSP["🇻🇳 VnPay / Momo / ZaloPay"] end TEN["🏢 TEN"] subgraph downstream ["TEN orchestrates"] PROV["module provisioning
(all 21 modules)"] BILL["billing flows"] METER["usage metering"] ISO["isolation harness"] OFF["offboarding"] end subgraph CONSUMERS ["Used by"] CFO_D["💰 CFO dashboard"] ADMIN["tenant-admin SPA"] EDGE["Apollo Router
plan / quota gate"] PORTAL["🌐 PORTAL"] end AUTH --> TEN BRAIN --> TEN OBS --> TEN AI --> TEN NATS --> TEN S3 --> TEN STRIPE --> TEN VNPSP --> TEN TEN --> PROV TEN --> BILL TEN --> METER TEN --> ISO TEN --> OFF TEN --> CFO_D TEN --> ADMIN TEN --> EDGE TEN --> PORTAL classDef planned fill:#e2e8f0,stroke:#1e293b classDef partner fill:#fef2f2,stroke:#7f1d1d class AUTH,BRAIN,OBS,AI,NATS,S3,TEN,PROV,BILL,METER,ISO,OFF,CFO_D,ADMIN,EDGE,PORTAL planned class STRIPE,VNPSP partner
11

Compliance scope

TEN is the SaaS-compliance hotspot. SOC 2, ISO 27001 multi-tenant controls, PCI SAQ-A, and Vietnamese PSP regulation all live here.

Regulation / standardArticle / clauseTEN feature that satisfies it
SOC 2 Type IICC6.1 — Logical accessAUTH + plan/feature-flag gating; per-tenant scope.
SOC 2 Type IICC6.6 — Restricted accessThree-layer isolation (PG RLS + NATS subject + S3 prefix); 100k-probe harness.
SOC 2 Type IICC7.2 — System monitoringPer-tenant usage telemetry; isolation-harness alerts.
ISO/IEC 27001:2022A.5.30 — ICT readinessMulti-region residency + offboarding grace.
ISO/IEC 27017Cloud services controlsTenant separation + signed-bundle portability.
ISO/IEC 27018Privacy for PIIPer-tenant residency choice + retention-policy override.
PCI DSSSAQ-A — Card-not-presentPAN never touches CyberOS; Stripe / PSP own PCI scope.
Vietnam Decree 53/2022Art. 26 — Data localisation for VN tenantsResidency choice = vn-hanoi-1 for VN tenants.
Vietnam Circular 18/2018/TT-NHNNPayment intermediary rulesVnPay / Momo / ZaloPay are SBV-licenced PSPs.
Vietnam Decree 13/2023Personal data processingPer-tenant retention policy + 90d offboarding grace.
Vietnam PDPL (Law 91/2025)Art. 14 — DSARSigned-bundle export covers all tenant data.
GDPR (EU 2016/679)Art. 20 — Right to portabilitySigned-bundle export covers (FR pending).
GDPRArt. 17 — Right to erasureOffboarding wipe with audit attestation.
GDPRArt. 28 — Processor obligationsDPA per tenant; sub-processor list on Trust Center.
12

Risk entries

TEN risks tracked in the risk register.

IDRiskLikelihoodImpactOwnerMitigation
R-TEN-001Information disclosure — billing data exposed across tenantsMediumCatastrophicCSOPer-tenant billing key; PCI scope minimisation via Stripe; webhook signature verification.
R-TEN-002Cross-tenant data leakage via RLS bypassLowCatastrophicCSO100k isolation harness; RLS at PG + NATS subject + S3 prefix; release-gate enforcement.
R-TEN-003Provisioning saga half-applied; tenant in inconsistent stateMediumHighCTOCompensating actions; chaos test with crash injection; idempotent replay.
R-TEN-004Stripe webhook spoofingLowHighCSOHMAC signature verification mandatory; replay-window enforcement; OBS alert on signature failure.
R-TEN-005Premature wipe (offboarding bug deletes too early)LowCatastrophicCTOTwo-phase grace (read-only 30d, recoverable 60d); cron job double-checks date + status; audit alarm.
R-TEN-006VN PSP integration outage blocks domestic signupMediumMediumCTOMulti-PSP support (VnPay + Momo + ZaloPay); failover at signup.rs; degraded-mode banner.
R-TEN-007Usage-meter drift causes revenue under/over-chargeMediumMediumCFONATS replay reconciliation weekly; ≤ 0.5% drift target; finance audit quarterly.
R-TEN-008Plan-tier feature flag bypassed (tenant accesses locked module)LowMediumCSOFeature flag check at Apollo Router + module GraphQL; CI test gate.
R-TEN-009Retention-override allows compliance breachLowHighDPOOverride bounded by DPO-configured min/max; CLO approves below-default values.
R-TEN-010Export-bundle leaks via mis-scoped pre-signed URLLowHighCSOPre-signed URL audience-bound + 24h TTL; tenant-scope verified in URL signer.
R-TEN-011Cancellation-saga compensation fails partiallyMediumMediumCTOIdempotent compensation; backup wipe-cron picks up partial state nightly.
R-TEN-012SBV compliance change affecting VN PSP onboardingMediumMediumCLOQuarterly review of Circular 18/2018; PSP partner notification subscription.
13

KPIs

TEN rolls up into 11 KPIs spanning revenue health, isolation hygiene, signup conversion, and offboarding compliance.

KPIFormulaSourceTarget
ARRΣ monthly subscription × 12subscriptionper-quarter board target
MRR growth(MRR_now − MRR_30d_ago) / MRR_30d_agosubscriptiontracked
NDR (Net Dollar Retention)(starting + expansion − contraction − churn) / startingsubscription≥ 110%
GRR (Gross Revenue Retention)(starting − contraction − churn) / startingsubscription≥ 92%
Logo churn ratecancelled / total active (per month)tenant≤ 2% / mo
Signup completion rateactive / signup_startedsignup≥ 60%
Signup p95 latencyhistogramOBS≤ 30 s
Isolation probe pass ratepassed / probedisolation.rs= 100%
Provisioning saga success ratecomplete / startedprovisioner.rs≥ 99.9%
Offboarding compliancewiped_on_or_after_day_91 / offboardedtenant= 100%
Export-bundle integrity rateverified / generatedexport.rs= 100%
14

RACI matrix

TEN spans CEO (strategy), CFO (revenue), CTO (engineering), CSO (isolation), CLO (compliance), DPO (data-subject rights).

ActivityCEOCFOCTOCSOCLODPO
Service design + specACRCCC
ImplementationIIA/RCII
Pricing policy + plan designARIIII
Stripe / PSP integrationIARCII
Isolation verificationIIRA/RII
Offboarding attestationCIRCAR
ARR / NDR / churn review (monthly)ARIIII
SOC 2 / ISO 27017 audit prepCCRA/RRC
PCI SAQ-A attestation (annual)IARRCI

R Responsible · A Accountable · C Consulted · I Informed.

15

Planned CLI surface

Admin CLI cyberos-ten for CyberSkill operators. Every destructive action writes a chained BRAIN audit row.

1. Provision a tenant (admin force-create)

$ cyberos-ten tenant create \
    --slug acme-corp --display "Acme Corp" \
    --country VN --residency vn-hanoi-1 \
    --plan team-vn \
    --founder pm@acmecorp.com

[saga running]
  step 1/8  auth.tenant + founder Subject   ✓
  step 2/8  brain init chain                ✓
  step 3/8  module schemas (21)             ✓
  step 4/8  s3 prefix                       ✓
  step 5/8  nats subject ACL                ✓
  step 6/8  ai gateway quota                ✓
  step 7/8  branding default theme          ✓
  step 8/8  billing customer (VnPay)        ✓
[provisioned]   tenant_id=01HZ8K9N7…   elapsed=21s
[audit]         brain seq=42118 chain=…

2. Change a plan

$ cyberos-ten plan change --tenant 01HZ8K9N7… --to enterprise

[plan change]
  from:        team-vn (5,990,000₫/mo)
  to:          enterprise-vn (custom)
  proration:   12,400,000₫ debited at period end
  features:    DOC + PORTAL + ESOP unlocked
[audit]        brain seq=42127 chain=…

3. Initiate offboarding

$ cyberos-ten tenant offboard --tenant 01HZ8K9N7… --reason "engagement ended"
Type the tenant slug to confirm: acme-corp
Type the tenant slug AGAIN to confirm: acme-corp

[offboarding initiated]
  grace_until:      2026-08-13 (90 days)
  read_only_until:  2026-06-14 (day 30)
  recover_until:    2026-08-13 (day 90)
  export ready:     s3://…/exports/01HZ8K9N7…/bundle.zip
[founders notified]  2 founders emailed
[audit]              brain seq=42148 chain=…

4. Run isolation harness

$ cyberos-ten isolation probe --probes 100_000

[probes]   PG RLS         100k cross-tenant queries · 0 leaks
[probes]   NATS subject   100k cross-tenant subs    · 0 deliveries
[probes]   S3 prefix      100k cross-tenant gets    · 0 successes
[passed]   release gate green

5. View ARR / NDR snapshot

$ cyberos-ten arr

[period 2026-05]
  ARR:                $4,420,800
  MRR:                $368,400 (+8.2% mom)
  NDR (3-mo trail):   118%
  GRR:                94%
  Logos:              208 active (+12 this month, −2 churned)
  ARR by plan:        starter 8% · team 41% · enterprise 51%
  ARR by region:      VN 23% · SG 19% · EU 31% · US 27%

6. Export tenant bundle

$ cyberos-ten export --tenant 01HZ8K9N7… --output bundle.zip

[exporting]   brain · auth · proj · time · crm · …  (21 modules)
[bundle]      bundle.zip (62 MB)
[sha256]      9f3a2c1b…
[signature]   Ed25519 ok (signer cyberos-ten-prod-2026-q2)
[audit]       brain seq=42163 chain=…

7. Usage report

$ cyberos-ten usage --tenant 01HZ8K9N7… --period 2026-05

[period 2026-05]
  api_call:      1,284,012 / unlimited (team plan)
  ai_token:      2,184,000 / 3,000,000 quota (73%)
  storage_gb:    18.4 / unlimited
  seat_count:    32 / 50

8. Set retention override

$ cyberos-ten retention set --tenant 01HZ8K9N7… \
    --log-days 60 --audit-days 730 --reason "EU regulator compliance"

[override applied]
  log_retention_days:     30 → 60
  audit_retention_days:   365 → 730
  legal_doc_forever:      true
[clo approval required]   if reducing — current change is INCREASE: auto-approved
[audit]                   brain seq=42199 chain=…
16

Phase status & estimates

Status
Planned
P4 long-term
Est. LoC (Rust)
~11,500
services/ten + isolation harness
Est. LoC (TS)
~4,800
signup SPA + tenant-admin SPA
Planned tests
220+
incl. isolation property fuzz + saga chaos
External libs
~18
stripe-rs · momo / vnpay / zalopay clients
P4 budget
~$60/mo + 2.9% pass-thru
Fargate + PG + Redis + Stripe fees
CapabilityStatus
Self-serve signup with residency choiceplanned · P4
Stripe integration (USD + EUR + …)planned · P4
VnPay / Momo / ZaloPay integration (VND)planned · P4
Plan tiers + feature flagsplanned · P4
Tenant-admin SPA (seats / billing / audit / retention)planned · P4
Per-tenant brand packplanned · P4
Usage metering (4 axes)planned · P4
Provisioning saga with compensationplanned · P4
Three-layer isolation enforcementplanned · P4
Isolation verification harness (100k probes)planned · P4
Signed export bundle ((FR pending))planned · P4
90-day offboarding grace + wipe attestationplanned · P4
ARR / NDR / churn dashboardplanned · P4
SOC 2 Type II auditplanned · P4+
ISO 27017 cloud-services auditplanned · P4+
17

References

  • PRD §9.22 — TEN — Tenancy & Billing. FRs 001..007.
  • SRS §7.22 — TEN subjects + tenant-as-degenerate-tenant decision (DEC-058).
  • SRS §12 (Multi-tenancy) — isolation invariants + RLS posture.
  • SOC 2 Type II — Trust Service Criteria CC6.1, CC6.6, CC7.2.
  • ISO/IEC 27017:2015 — Cloud-services security controls.
  • ISO/IEC 27018:2019 — Public-cloud PII processor controls.
  • PCI DSS v4.0 — SAQ-A self-assessment questionnaire.
  • Vietnam Circular 18/2018/TT-NHNN — Payment intermediary services rules.
  • Vietnam Decree 53/2022 — Cybersecurity Law implementing decree; data localisation.
  • Vietnam Decree 13/2023 — Personal data processing.
  • Vietnam Law 91/2025/QH15 (PDPL) — Personal Data Protection Law.
  • GDPR (EU 2016/679) — Art. 17 (erasure), Art. 20 (portability), Art. 28 (processor).
  • Stripe Billing API — subscription + invoice + webhook docs.
  • VnPay / Momo / ZaloPay merchant docs — Vietnamese PSP integration.
  • Architecture context: infrastructure.html#ten.
  • AUTH moduleauth.html · upstream for tenant + Subject provisioning.
  • BRAIN modulebrain.html · audit chain.
  • PORTAL moduleportal.html · client-facing surface above TEN.