# Design: cp9 Account Persona

Issue: <https://github.com/tidbcloud/controlplane9/issues/254>

Dogfood design:
[`20260527-design-cp9-account-persona-dogfood.md`](./20260527-design-cp9-account-persona-dogfood.md)

Sibling Billing design:
[`20260527-design-cp9-billing-persona.md`](./20260527-design-cp9-billing-persona.md)

This document defines only the Account persona. Account is larger than the
`tidbcloud/account` repo alone: the accepted local proof must include the
gateway/auth edge that enforces TiDB Cloud API authentication and authorization.

## Current cp9 Baseline

The current active baseline is the Premium family:

- `premium-full`: real CP plus real Premium dataplane proof.

Older material may say Premium Reserved. That active persona has been removed.
Account implementation should reuse current Premium-family mechanics and
`skills/get-started/SKILL.md`, not resurrect `premium-reserved`.

## Decisions

1. Billing and Account are separate runnable personas.
2. Account acceptance must prove real identity/authz behavior through
   Account/Auth/API-gateway logic, not a permissive auth bypass.
3. API-gateway is in scope for Account. The TiDB Cloud account edge lives in
   `tidbcloud/api-gateway` custom Kong plugins and Pulumi deployment inputs.
4. Account local storage must model MySQL, Redis, and DynamoDB responsibilities
   explicitly. Redis-only or MySQL-only shortcuts are not accepted unless the
   selected proof avoids the omitted path by design.
5. App delivery for Account/Auth is Kustomize-based, while API-gateway is
   Pulumi-based. cp9 must design both input styles instead of pretending all
   Account infrastructure is app-delivery/Argo backed.
6. External IdP/Auth0, OIDC, MFA, invite email, and real enterprise SCIM
   providers are local deterministic fakes for this local gate. Real sandboxes
   are later certification lanes.
7. Staging may provide read-only seed/config reference data. It is not a
   runtime success path.
8. `tidb-management-service`, `cluster-service-ng`, and `config-center` are not
   Account source/live services. If Account/Auth/API-gateway config references
   them, cp9 must classify that dependency as stub/fake/skipped for the selected
   Account proof.

## Product Scope

The Account persona focuses on TiDB Cloud IAM:

- Account services from `tidbcloud/account`;
- Auth Server from `tidbcloud/auth-server`;
- Kong API-gateway from `tidbcloud/api-gateway`;
- local MySQL/Aurora-equivalent IAM schema;
- local DynamoDB-equivalent API key/role-privilege mirror;
- local Redis-equivalent gateway/account caches and rate-limit counters.

Account must prove an authorization decision on a TiDB Cloud API call. A service
health check or local token mint alone is insufficient.

## Account Architecture Evidence

The design uses the account research architecture input and current repo
evidence:

- Account service entrypoints from issue #254:
  - `admin/cmd/server/main.go`;
  - `central/cmd/acl/main.go`;
  - `central/cmd/openapi/main.go`;
  - `central/cmd/central/main.go`;
  - `central/cmd/worker/main.go`;
  - `central/cmd/provider/main.go`.
- Auth Server entrypoint:
  - `auth-server/cmd/auth-server`.
- API-gateway evidence:
  - `api-gateway/deploy/pulumi/index.ts` deploys Kong, ALB/Ingress,
    plugin ConfigMaps, and route/plugin wiring;
  - `api-gateway/deploy/configs/formal.yaml` owns the real route inventory;
  - `api-gateway/plugins/digest-auth`, `custom-basic-auth`,
    `bearer-token-auth`, `inner-basic-auth`, `cookie-auth`,
    `cookie-filter`, `rate-limit`, and related plugins contain core
    TiDB Cloud-specific gateway logic;
  - `api-gateway/deploy/ddbtoredis/index.ts` owns DynamoDB-to-Redis sync.

## Runtime Shape

Expected source services:

| Service | Source repo path | Role |
|---|---|---|
| `account-central` | `tidbcloud/account/central/cmd/central` | Console IAM, org/user/project, SSO/SCIM, API keys |
| `account-openapi` | `tidbcloud/account/central/cmd/openapi` | Public OpenAPI and SCIM facade |
| `account-provider` | `tidbcloud/account/central/cmd/provider` | Internal AccountAPIService and RBAC data |
| `account-acl` | `tidbcloud/account/central/cmd/acl` | AccessService and API-key access checks |
| `account-admin` | `tidbcloud/account/admin/cmd/server` | Management portal admin API |
| `account-worker` | `tidbcloud/account/central/cmd/worker` | Migrations and background jobs |
| `authserver-central` | `tidbcloud/auth-server/cmd/auth-server` | OAuth2 HTTP server |
| `authserver-provider` | `tidbcloud/auth-server/cmd/auth-server` | Token identity gRPC provider |
| `kong` | `tidbcloud/api-gateway/deploy/pulumi` plus `plugins/*` | Edge routing and auth plugins |
| `ddbtoredis` | `tidbcloud/api-gateway/deploy/ddbtoredis` | DynamoDB Streams to Redis cache sync |

Phase 0 must confirm whether `kong` and `ddbtoredis` run as source-built local
services, generated manifests, or a minimal cp9-owned local wrapper. The proof
must still exercise the real plugin/config contract.

Explicit non-source/non-live services for Account:

| Service | Account role |
|---|---|
| `tidb-management-service` | stub/fake/skipped only |
| `cluster-service-ng` | stub/fake/skipped only |
| `config-center` | stub/fake/skipped only |

## Storage Contract

Account local storage must model these data roles:

| Store | Local cp9 behavior | Business role |
|---|---|---|
| MySQL/Aurora | cp9 local IAM DB seeded from reviewed SQL/migrations | org/user/project state, RBAC bindings, OAuth2 tokens, API key metadata |
| DynamoDB | local DynamoDB-compatible service or deterministic adapter with stream/event semantics | encrypted API key mirror and role/privilege datasets feeding gateway auth |
| Redis gateway DB0 | local Redis | `dbaas:account:api_keys:<ak>` lookup for Kong auth plugins |
| Redis gateway DB1 | local Redis | rate-limit counters such as `ratelimit:<key>:<epoch_ms>:minute` |
| Redis account cache | local Redis or local cache adapter | Account service API-key cache such as `account_api_key_ak_<ak>` |

The accepted design must explain how a local API key mutation reaches the Kong
request-time cache. Valid options include:

- real local DynamoDB-compatible storage plus local `ddbtoredis`; or
- a deterministic local adapter that emits the same Redis key/value contract and
  records the skipped DynamoDB stream boundary.

Simply seeding Redis by hand is not enough unless the dogfood proof explicitly
names it as a temporary Phase 0 input and the implementation issue remains
open.

## Acceptance Matrix

The Account persona is accepted when a developer can:

1. start cp9 with `cp9.account.example.yaml` from clean repo heads;
2. see real Account/Auth/API-gateway services healthy through Tilt;
3. create or validate a local identity path: org, user, membership, role,
   service account, API key, token, or equivalent Account-owned primitive;
4. drive that identity through Kong/API-gateway and Account/Auth logic to
   authorize a TiDB Cloud API request;
5. prove a matching negative case, such as invalid digest/basic auth,
   underprivileged API key, revoked/expired token, missing role, or bad scope;
6. prove the local Redis/DynamoDB/MySQL contract for the selected auth path;
7. hot reload an Account/Auth/API-gateway source edit without rebuilding the
   whole cp9 session;
8. run `cp9 destroy` and direct zero-survivor checks when the run creates AWS
   resources.

The Account persona is not accepted by permissive auth bypass, direct internal
gRPC calls that skip gateway auth, or process health alone.

## Phases

### Phase 0: Account Contract Inventory

Deliver:

- current Account and Auth Server entrypoint list;
- API-gateway plugin/route list needed by the first proof;
- Pulumi inputs that must be represented in cp9;
- app-delivery Account/Auth service/env inputs;
- local MySQL schema/migration and seed source;
- local DynamoDB/Redis cache contract and sync plan;
- one selected first positive/negative authorization workflow with concrete
  commands and expected responses;
- explicit list of local fakes for Auth0/IdP/OIDC/MFA/email/SCIM boundaries.

### Phase 1: Account Persona Graph

Deliver:

- `cp9.account.example.yaml`;
- Account/Auth app-delivery env/base inputs;
- API-gateway Pulumi-derived local inputs or a reviewed cp9-owned translation;
- local MySQL/DynamoDB/Redis inputs;
- render/plan tests that prove the service graph;
- tests forbidding permissive auth bypass and hidden staging dependencies;
- get-started doc updates with concrete commands.

### Phase 2: Account Runtime Proof

Deliver at least two cold proofs with:

- cp9, account, auth-server, and api-gateway SHAs;
- exact `cp9.yaml`;
- Tilt health;
- positive authorization command transcript;
- negative authorization command transcript;
- storage/cache evidence for MySQL, DynamoDB, and Redis on the selected path;
- hot reload evidence;
- cleanup evidence when cloud resources were created.

### Phase 3: External Certification Follow-Up

After local Account passes, file separate follow-ups for real Auth0/IdP, OIDC,
MFA, email, SCIM, and other enterprise identity sandboxes. These are not
prerequisites for closing the local Account persona.

## Done Definition

Account is done when the local Account product workflow passes repeatedly from
clean heads, the dogfood contract has concrete gateway-visible commands, the
local MySQL/Redis/DynamoDB model is explicit, source changes are data/config
driven, external identity dependencies are explicit local fakes, and cleanup
evidence is attached to implementation PRs.
