## Phase 0(文件層,全部 Accepted) - ADR-106/107:AwoooP 平台架構 + 儲存策略 - ADR-111~118:Bootstrap → RLS 七項核心 ADR - ADR-119~124:SAGA → Singleton Decomposition 六項 ADR - ADR-UI-01~04:Operator Console 四個 UI ADR ## Phase 1(DB schema + migration) - awooop_phase1_control_plane_2026-05-04.sql:7 張新表 + trigger + RLS - Step 1:三角色(platform_admin/migration BYPASSRLS,awooop_app 受 RLS) - Step 13:GRANT awooop_app 最小權限(7 條) - Step 14:RLS fail-closed,移除 __platform__ 後門 - awooop_phase1_batch1_rls_2026-05-04.sql:高流量四表三步式 ADD COLUMN - awooop_phase1_batch1_backfill.py:SKIP LOCKED 分批回填腳本 - awooop_models.py:7 個 SQLAlchemy 2.x models ## Critic 修正(4 Critical + 3 Major) - C-1:ADD CONSTRAINT IF NOT EXISTS → DO 塊 + pg_constraint 查詢 - C-2:__mapper_args__ 字串 list → primary_key=True on mapped_column - C-3:__platform__ RLS 後門 → 全移除,改用 BYPASSRLS role - C-4:awooop_app role 從未建立 → Step 1 + 7 條 GRANT - M-1:active_pointer_guard SECURITY DEFINER(FORCE RLS 跨租戶保護) - M-2:pg_partman create_parent 加冪等防護 - M-3:immutability trigger 新增身份欄位保護(project_id/family/contract_id) ## Task 1.2 修補 - agent_loader.py:硬編碼 Mac 路徑 → AGENTS_DIR 環境變數 - Dockerfile:補 COPY .claude/agents/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6.7 KiB
ADR-107: AwoooP Control Plane Storage Strategy
Status: Accepted Date: 2026-05-01 Scope: AwoooP control plane storage, contract materialization, cache/watch, K8s projection
Context
ADR-106 defines AwoooP as the multi-tenant Agent Platform with six contracts:
- Project / Tenant
- Agent
- MCP Gateway
- Policy / Routing
- Runtime / Run State
- Communication / Channel Event
Those contracts need a physical source of truth. The key question is whether the AwoooP control plane should be implemented as Kubernetes CRDs first, or as PostgreSQL tables first.
AwoooP must serve more than Kubernetes:
- AWOOOI on K3s is the first runtime host and tenant.
- EwoooC / MOMO PRO currently runs Docker workloads.
- Tsenyang, Bitan, LINE, Slack, Email, and API entrypoints may not all be Kubernetes-native.
- Runtime state, audit, budget, approval, and conversation events are high-volume product control-plane data, not only deployment desired state.
ADR-105 already established the local pattern for MCP RAG: keep PostgreSQL + pgvector + Redis hot cache as the source of truth unless scale, latency, or tenant isolation requires a later split.
Decision
D1 - Use PostgreSQL as the Control Plane Source of Truth
AwoooP v1 uses PostgreSQL as the authoritative store for the six contract families and runtime governance state.
PostgreSQL owns:
- contract drafts and immutable published revisions
- active revision pointers
- tenant/project records
- agent registry and version metadata
- policy and routing revisions
- MCP tool registry, grants, and audit summaries
- budget ledgers and hard-stop state
- ACL subjects and project access
- run state and approval state
- channel event and outbound delivery state
- audit and trace correlation records
Kubernetes etcd is not the source of truth for these records in v1.
D2 - Materialize Contracts as Versioned Revisions
Each published contract must produce an immutable revision.
Minimum revision fields:
contract_familycontract_idrevision_idversionlifecycle_statusbody_jsonbody_schema_versionbody_hashcreated_bycreated_atpublished_atsupersedes_revision_id
Runtime reads only published or active revisions. Mutable drafts are never used for runtime decisions.
D3 - Keep Artifact Bodies Out of Control Tables
Large or independently governed artifacts are stored by reference plus hash:
- system prompts
- JSON Schemas
- eval suites
- policy fixtures
- replay fixtures
The database stores:
- artifact ref
- SHA-256 hash
- artifact type
- expected schema version
This makes historical runs replayable without stuffing large prompt bodies into every contract row.
D4 - Use Redis for Cache and Watch, Not Authority
Redis is allowed for:
- effective policy cache
- agent contract cache
- project boundary cache
- rate limit counters
- short-lived session hot state
- contract revision invalidation
- worker coordination
Redis is not allowed to be the only source of truth for:
- contract revisions
- active revision pointers
- budget hard-stop decisions
- run terminal state
- approval decisions
- audit history
Any cached value used by runtime must carry the source revision_id and
body_hash.
D5 - Use Kubernetes CRDs Only as Runtime Projection
CRDs are not the primary control-plane database in v1.
Allowed future CRD projections:
AwoooPRuntimeAwoooPWorkerMCPServerBindingChannelIngressTenantRuntimeBinding
These CRDs describe Kubernetes runtime wiring, deployment, service exposure, and MCP server binding. They do not own product contracts, budgets, run state, conversation events, or audit ledgers.
If an operator is later built, it should project from PostgreSQL into Kubernetes objects, not require Kubernetes CRDs to become the source of truth for all AwoooP state.
D6 - Define Read Paths by Stability
| Data | Source of truth | Runtime read path |
|---|---|---|
| Contract draft | PostgreSQL | Admin/API only |
| Published contract revision | PostgreSQL | DB read + Redis cache |
| Active revision pointer | PostgreSQL | DB read + Redis invalidation |
| Prompt/schema/eval artifact | Git or object storage | Ref + hash from DB |
| Effective policy | PostgreSQL-derived | Redis cache with revision IDs |
| Run state | PostgreSQL | Worker writes DB, optional Redis notification |
| Budget hard stop | PostgreSQL | DB transaction + Redis hot counter |
| Rate limit | PostgreSQL policy + Redis counter | Redis counter, DB policy |
| Audit history | PostgreSQL | DB append/query |
| K8s runtime wiring | CRD projection | Kubernetes watch |
Consequences
Benefits
- AwoooP remains useful for Docker, Next.js, API-only, and future non-K8s tenants.
- Product governance data can be joined with incidents, Playbooks, KM, budget, and audit records.
- Contract changes are transactional and replayable.
- Runtime can use Redis for speed without risking split-brain authority.
- K8s CRDs remain available for the infrastructure layer without forcing all business control-plane data into etcd.
Costs
- AwoooP needs explicit schema and migration discipline before runtime code.
- Runtime workers must implement revision-aware caches.
- K8s operator work, if needed later, must include a projection layer.
Risks
- PostgreSQL schema can become a dumping ground if contract families are not modeled explicitly.
- Redis cache can become stale if invalidation is not versioned by revision and hash.
- Future CRDs can drift from DB state if projection reconciliation is not audited.
Mitigations
- Every runtime decision records
revision_idandbody_hash. - Active revision changes must emit an invalidation event.
- Contract publish is append-only; do not mutate published
body_json. - CRD projection writes must be reconciled and auditable.
- High-volume audit/event tables should be partitioned before production scale.
Non-Goals
- This ADR does not create database migrations.
- This ADR does not create AwoooP directories or runtime services.
- This ADR does not introduce Kubernetes CRDs.
- This ADR does not choose Temporal, Celery, Redis Streams, or another worker engine.
- This ADR does not change paid provider behavior.
Acceptance Criteria
- PostgreSQL is declared as the v1 AwoooP control-plane source of truth.
- Redis is limited to cache/watch/counter responsibilities.
- Artifacts are referenced by ref + hash rather than copied into every runtime record.
- CRD-first is explicitly rejected for v1.
- Future CRDs are limited to Kubernetes runtime projection.
- ADR-106 and the task-routing docs point to this ADR.
References
docs/adr/ADR-105-mcp-agent-loop-governance.mddocs/adr/ADR-106-agent-platform-architecture.mddocs/LOGBOOK.mddocs/12-agent-game-rules.md