Admin Control Plane 06 · ควบคุม · role · scope · approval · publish workflow · audit · alerting

Planning · v0.2
Admin surface ที่ runtime ทั้ง 5 (Dashboard · Cases · Generate · Tenant · Wizard) ต้องใช้ · sign-off UI · dual-approval enforcement · audit trail viewer · PagerDuty/Slack/LINE integration. ไม่มี runtime · เป็น planning เท่านั้น.
Runtime Phase 1 implementation: /runtime/admin-control-plane/ — role registry + masking + assist/view-as + approval queue + audit event model (spec live · enforcement not bound).
Runtime Phase 2a · Policy Engine Service: /runtime/admin-control-plane-service/ — HTTP boundary · 7 endpoints (access · mask · assist · viewas · sensitive · batch · health) · 24/24 canonical examples pass · decision-only · dev-mode (no JWT · no WORM sink · no admin UI yet).
Runtime Phase 2b: /runtime/admin-control-plane-service/phase-2b.html — additive · Bearer JWT resolver + file-backed approval store (8 rows) + TTL enforcement + audit sink BOUNDARY (POST /api/policy/audit/preview) · parity 24/24 preserved · rationale at admin-control-plane-phase-2b.html (still dev-mode · no JWKS · no Postgres · no Kafka · no mutation).

Context บริบท

Handoff hand-admin-control-plane ระบุ: B modeled roles+gates+scopes+stages; A ต้อง implement admin surface + sign-off + audit + notifier integration. ผลลัพธ์คือ control plane เดียวที่รองรับทุก runtime module · ไม่ใช่ admin per module.

docs/kb/data/approval_matrix.jsonRoles · matrix_rows · dual_approval_rules · sensitive_surface_markers · escalation_paths
docs/kb/data/tenant_scope.jsontenant_roles · scope transitions · app_registry_handoff · feature_flag_handoff
docs/kb/data/publish_workflow.jsonStages · rollback
docs/kb/data/alerting_model.json4 levels · 11 lifecycle · 3 escalation paths · 5 measures
docs/kb/data/sla_model.jsonper-level bands · sensitive_override dual-approval
docs/kb/data/case_schema.json27 fields surfaced in audit viewer

A-owned Runtime Boundary ขอบเขต A vs B

B owns (read-only for A)

  • approval_matrix · all rows · all roles
  • dual_approval_rules · sensitive_surface_markers
  • tenant_scope.tenant_roles + scope transitions
  • publish_workflow stages + rollback spec
  • alerting_model levels + escalation paths
  • sla_model bands + breach consequences

A owns (this runtime)

  • Admin UI (Next.js / React)
  • Role + scope storage (Postgres)
  • Approval queue + workflow engine
  • Sign-off capture + JWT-anchored signatures
  • Audit trail (WORM S3 + search index)
  • PagerDuty / Slack / LINE delivery
  • Feature flag override per-tenant/user
  • Cost monitoring per tenant (infra)

Scope A implement อะไร

ER Diagram tables + relations

Admin Control Plane · core entities
tenants ● id (PK) name status (enum) tier created_at founder_signoff_ref users ● id (PK) email_hash tier_claim global_role locale last_login_at tenant_user_roles ● tenant_id ● user_id role_id (FK) scope_id (FK) granted_by granted_at approvals ● id (PK) target_type target_id matrix_row (FK) required_signers status (enum) sensitive_flag opened_at closed_at signatures ● id (PK) approval_id (FK) signer_user_id decision signed_jwt signed_at audit_log (WORM) ● id (PK) entity_type entity_id actor_user_id action before_state after_state ts sig_chain feature_flags ● id (PK) key default_value rollout_pct tenant_overrides approval_required 1..n 1..n scopes 1..n mutates gated

Field Mapping — Approvals Table B matrix_rows → A approvals

Source: approval_matrix.matrix_rows[*].

B Field B Type A Runtime Target A Owner Approval Gate Binding Notes
row_id string approvals.matrix_row FK Backend none mapped-not-bound Stable · never renamed
required_roles[] array approvals.required_signers JSONB Backend none mapped-not-bound Enforced at sign-off API
dual_approval_required boolean approvals.sensitive_flag + enforce 2 distinct signers Backend gate-sensitive-dual placeholder Hard-block transition if <2 distinct signers
sensitive_surface boolean UI badge + domain-expert reviewer pool Backend + FE gate-sensitive-dual placeholder Triggers additional domain expert in signers
sla_band enum SLA timer · escalation trigger Backend gate-sla-enforce mapped-not-bound Breach → alerting escalation
escalation_path array PagerDuty / Slack / LINE routing Backend + Infra gate-alert-routing placeholder Per alerting_model.escalation_paths
scope_key string Scope filter for role matrix Backend none mapped-not-bound Per tenant_scope transitions

API Sketch FastAPI endpoints

GET/api/admin/approvals?status=pending&module=cases
List approval items filtered by status · module · tenant · sensitive flag
// response { "items": [ { "id": "APP-260418-0001", "target_type": "case", "target_id": "CASE-260417-AB12", "matrix_row": "row-sensitive-override", "required_signers": ["governance", "domain-expert"], "status": "in_review", "sensitive_flag": true, "sla_due_at": "2026-04-18T13:00:00+07:00" } ], "total": 42 }
POST/api/admin/approvals/{id}/sign
Sign an approval · reviewer decision + rationale + JWT signature
// request { "decision": "approve", // approve | reject | request_changes "rationale": "verified PDPA + faithfulness", "signed_jwt": "eyJhbGciOi..." } // response 200 if gate satisfied, 428 if waiting for more signers
GET/api/admin/audit?entity=case&id=CASE-260417-AB12
WORM audit viewer · all actions on an entity · sig chain verifiable
POST/api/admin/flags/{key}/rollout
Update feature flag rollout % / tenant override · sensitive flag requires dual-approval first
// request { "rollout_pct": 25, "tenant_overrides": { "tenant-pty-zeroth": 100 }, "approval_ref": "APP-260418-0099" }

Sequence Flow sensitive-surface dual-approval

Case · sensitive_flag=true · dual-approval + audit
Case Runtime Admin API Reviewer #1 Reviewer #2 Audit · Notifier 1 POST /approvals (open) 2 notify reviewer #1 + #2 (PagerDuty) 3 POST /sign (approve, JWT) 4 POST /sign (approve, JWT) 5 write audit_log (WORM, sig chain) 6 200 gate-satisfied · transition allowed 7 status=resolved · notify LINE (L0)

Dependencies

Upstream

  • Auth + JWT (signer identity)
  • Postgres cluster (RLS-enabled)
  • S3 WORM bucket (audit)
  • PagerDuty / Slack / LINE credentials
  • Feature flag registry

Downstream (enables)

  • Cases · Generate · Tenant · Wizard · Dashboard — all need admin control plane for sign-off
  • Publish workflow (shared kanban)
  • Tenant provisioning

Approval Gates

Risks

Signer = target-drafter (self-approval)
High
API rejects signer.id == target.created_by · enforce 2 distinct for dual
Audit log tampered
High
S3 Object Lock WORM mode · hash chain · periodic chain verifier job
Alerting spam during incident storm
Med
Rate-limit per channel · batch low-priority · LINE only for L0
Approval stuck (signer unavailable)
Med
SLA timer → escalate to backup role per escalation_paths · reassignment UI

Definition of Done

  1. approvals + signatures + audit_log tables deployed · RLS verified
  2. Matrix + queue + kanban UI operational
  3. Dual-approval enforced with penetration test
  4. PagerDuty/Slack/LINE round-trip tested per level
  5. WORM audit chain verifiable end-to-end
  6. Feature flag tool writes to registry with gated API
  7. Founder sign-off captured for first pilot tenant
  8. All 5 approval gates signed off with evidence

Deferred

Admin Control Plane Planning · v0.2 · Session A · A-owned ← Planning hub