## Phase 1-3: Control Plane + Contract System - awooop_phase1_control_plane_2026-05-04.sql: 12 張核心表 + RLS - awooop_phase1_batch1_rls_2026-05-04.sql: 全部 FORCE RLS + GRANT - packages/awooop-contracts/: 六合約 JSON Schema + golden fixtures - src/models/awooop_contracts.py: Pydantic v2 contract models(extra=forbid) - src/repositories/contract_repository.py: contract lifecycle(draft→published→active) - src/services/contract_service.py: HMAC publish sig + Redis multi-sig activate - src/services/schema_validator.py: LLM output validator(retry×3, E-SCHEMA-001) ## Phase 2: Tenant Isolation - awooop_phase2_budget_ledger_2026-05-04.sql: budget_ledger + RLS - src/services/budget_service.py: Token Budget Hard Kill 三層防線 - src/core/context.py: PROJECT_ID ContextVar(31 background loop 自動繼承) - src/db/base.py + models.py: project_id 欄位 + RLS set_config 注入 - src/hermes/nl_gateway.py: project_id Redis key 前綴(Phase A 雙寫) - src/services/anomaly_counter.py: per-project 改造(Phase A fallback) ## Phase 4: Platform Shell in Shadow Mode - awooop_phase4_run_state_2026-05-04.sql: run_state + step_journal + idempotency - src/services/run_state_machine.py: 8-state FSM + SKIP LOCKED + stale reaper - src/services/platform_runtime.py: UUID v7 + W3C trace_id + shadow_execute - src/services/audit_sink.py: PII/secret redaction 9 patterns - src/api/v1/platform/runs.py: POST/GET /v1/platform/runs(Router→Service 架構) - src/workers/platform_worker.py: SKIP LOCKED worker + heartbeat + reaper loop - src/main.py: platform router + lifespan worker start/stop ## Phase 5: MCP Gateway 五閘門 - awooop_phase5_mcp_gateway_2026-05-04.sql: 4 表 + RLS - src/plugins/mcp/gateway.py: McpGateway(Gate 1~5, E-MCP-GATE-001~009) - src/plugins/mcp/redaction_middleware.py: 雙層 redaction + 16K 截斷 - src/plugins/mcp/registry.py: __provider name mangling(ADR-116) - src/plugins/mcp/credential_resolver.py: k8s secret ref 解析 - tests/test_mcp_credential_isolation.py: 10 個迴歸測試(secret leak 防再現) ## Phase 6-8: EwoooC + Channel Hub + Approval Token - awooop_phase6_ewoooc_onboarding_2026-05-04.sql: ewoooc tenant + 4 read-only MCP tools - awooop_phase7_channel_hub_2026-05-04.sql: conversation_event + outbound_message - src/services/provider_proxy.py: ProviderProxy + PlatformEnvelope(ADR-115) - src/services/channel_hub.py: Telegram inbound mirror + Progressive Feedback(30s) - src/services/awooop_approval_token.py: HS256 + jti NX replay 防護 + suggest mode Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
105 lines
7.2 KiB
Markdown
105 lines
7.2 KiB
Markdown
# INV-1: Redis Key Inventory
|
||
|
||
**版本**:v1.0 初稿
|
||
**日期**:2026-05-03(台北)
|
||
**範圍**:`apps/api/src/` 全 codebase grep
|
||
**用途**:Phase 2 三階段雙寫遷移的完整 Redis key 清單
|
||
|
||
---
|
||
|
||
## 使用方式
|
||
|
||
本 INV 列出所有 Redis key pattern、TTL、用途、寫入點、讀取點、是否硬碼跨兩處。
|
||
Phase 2 遷移按批次執行:P0(Critical)→ P1(高風險)→ P2(業務資料)→ P3(低影響)
|
||
|
||
---
|
||
|
||
## 1. P0 — Critical(必須優先遷移)
|
||
|
||
| Key Pattern | 用途 | TTL | 寫入點 | 讀取點 | 問題 | 新 Pattern(Phase 2 後)|
|
||
|-------------|------|-----|--------|--------|------|------------------------|
|
||
| `ollama:current_primary` | Ollama primary URL 選擇 | 無 | `ollama_auto_recovery.py` (兩處!) | `ollama_failover_manager.py` | 🔴 P0-11:第二定義 at ollama_auto_recovery.py:230;三層 GCP 拓撲無法塞入單一 URL | `platform:ollama:topology`(JSON:primary/secondary/fallback)|
|
||
| `ollama:gemini_daily_count:{date}` | Gemini 每日使用計數 | 24h | `ollama_auto_recovery.py` | same | 🔴 無 project 前綴,多 tenant 共用 | `platform:ollama:gemini_daily_count:{date}` |
|
||
| `telegram:polling:leader` | Telegram polling pod 鎖 | ~30s | `telegram_gateway.py:55` | same | 🔴 platform_resource,應明確標記 | `platform:telegram:polling:leader` |
|
||
| `telegram_silence:{target}` | 告警靜默控制 | 設定值 | `telegram_gateway.py:4079`(用 SILENCE_KEY_PREFIX)| `decision_manager.py:240`(🔴 硬碼 `telegram_silence:{target}`,未 import 常數)| P1-24:兩處定義不一致 | `{project_id}:telegram:silence:{target}` |
|
||
| `ai_rate:total_cost:{provider}` | 費用上限控制 | 無 | `ai_rate_limiter.py` | `ai_router.py` | 🔴 無 project 前綴,AWOOOI 費用計數會與 EwoooC 混算 | `{project_id}:ai_rate:total_cost:{provider}` |
|
||
|
||
## 2. P1 — 高風險(Phase 2 第二批)
|
||
|
||
| Key Pattern | 用途 | TTL | 寫入點 | 讀取點 | 問題 | 新 Pattern |
|
||
|-------------|------|-----|--------|--------|------|------------|
|
||
| `approval:{run_id}:*` | approval 審核狀態 | 15min | `multi_sig_redis.py` | same | 🔴 P1-15:無 trace_id;approval_token 未簽章 | `{project_id}:approval:{run_id}:*`(Phase 8 後加 jti)|
|
||
| `incident:{incident_id}` | incident working memory | 24h | `incident_service.py` | `incident_service.py:603`(SCAN `incident:*`)| 🔴 P1-18:SCAN 無 prefix 篩選 | `{project_id}:incident:{incident_id}` |
|
||
| `consensus:{*}` | consensus engine 狀態 | varies | `consensus_engine.py`(CONSENSUS_PREFIX="consensus:")| same | 🔴 P0-12:無 project 前綴,multi-tenant 共用 | `{project_id}:consensus:{*}` |
|
||
| `playbook:{playbook_id}` | playbook cache | 1h | `playbook_repository.py` | same | 🟠 無 project,但目前 AWOOOI 只有一個 tenant | `{project_id}:playbook:{playbook_id}` |
|
||
| `playbook:embedding:index` | embedding index | 無 | `playbook_repository.py` | same | 🟠 無 project | `{project_id}:playbook:embedding:index` |
|
||
| `playbook:index:alert:{alert_name}` | alert → playbook 映射 | 1h | `playbook_repository.py` | same | 🟠 無 project | `{project_id}:playbook:index:alert:{alert_name}` |
|
||
| `playbook:embedding:{playbook_id}` | embedding vector | 無 | `playbook_repository.py` | same | 🟠 無 project | `{project_id}:playbook:embedding:{playbook_id}` |
|
||
| `km:backfill:dlq` | KM backfill dead letter queue | 無 | `km_service.py` | same | 🟠 無 project | `{project_id}:km:backfill:dlq` |
|
||
|
||
## 3. P2 — 業務資料(Phase 2 第三批)
|
||
|
||
| Key Pattern | 用途 | TTL | 寫入點 | 讀取點 | 問題 | 新 Pattern |
|
||
|-------------|------|-----|--------|--------|------|------------|
|
||
| `anomaly:disposition:{alert_id}` | 告警處置決定 | 7d | `anomaly_counter.py:790` | same | 🔴 P1-17:AnomalyCounter 全域單例,6 個 prefix 無 tenant | `{project_id}:anomaly:disposition:{alert_id}` |
|
||
| `anomaly:metadata:{alert_id}` | 告警 metadata | 7d | `anomaly_counter.py` | same | 同上 | `{project_id}:anomaly:metadata:{alert_id}` |
|
||
| `anomaly:permanent_fix:{alert_id}` | 永久修復紀錄 | 30d | `anomaly_counter.py` | same | 同上 | `{project_id}:anomaly:permanent_fix:{alert_id}` |
|
||
| `anomaly:repair_count:{alert_id}` | 修復計數 | 7d | `anomaly_counter.py` | same | 同上 | `{project_id}:anomaly:repair_count:{alert_id}` |
|
||
| `anomaly:repair_history:{alert_id}` | 修復歷史 | 30d | `anomaly_counter.py` | same | 同上 | `{project_id}:anomaly:repair_history:{alert_id}` |
|
||
| `anomaly:timeline:{alert_id}` | 告警時間線 | 7d | `anomaly_counter.py` | same | 同上 | `{project_id}:anomaly:timeline:{alert_id}` |
|
||
| `hermes:session:{chat_id}:{user_id}` | Hermes 對話狀態 | 30min | `hermes/nl_gateway.py:146` | same | 🔴 P1-16:無 project 前綴 | `{project_id}:hermes:session:{chat_id}:{user_id}` |
|
||
| `hermes:rl:{chat_id}` | Hermes rate limit | 1min | `hermes/nl_gateway.py:163` | same | 🔴 P1-16 | `{project_id}:hermes:rl:{chat_id}` |
|
||
| `hermes:approvers` | Hermes 審核者清單 | 無 | `hermes/nl_gateway.py:7` | same | 🔴 P1-16 | `{project_id}:hermes:approvers` |
|
||
| `session:{session_id}` | agent session | varies | `agent_sessions service` | same | 🟠 無 project | `{project_id}:session:{session_id}` |
|
||
| `tg_sent:{fingerprint}` | Telegram 去重 dedup | 10min | `telegram_gateway.py` | same | 🟢 ADR-109 已定(dedup 相容性);注意 EwoooC Telegram 需要不同 fingerprint scope | `{project_id}:tg_sent:{fingerprint}` |
|
||
| `telegram:{user_id}:{*}` | Telegram session / callback | varies | `telegram_gateway.py` | same | 🟠 無 project | `{project_id}:telegram:{user_id}:{*}` |
|
||
|
||
## 4. P3 — 低影響(Phase 2 最後)
|
||
|
||
| Key Pattern | 用途 | TTL | 問題 | 新 Pattern |
|
||
|-------------|------|-----|------|------------|
|
||
| `playbook:*`(SCAN)| playbook 全量掃描 | — | 🟠 SCAN 無 prefix 篩選 | 禁止裸 SCAN,改 `SCAN {project_id}:playbook:*` |
|
||
| `approval:123:lock`(測試用)| 測試 key | — | 🔵 hardcode 測試字串,清理 | 移除 |
|
||
|
||
---
|
||
|
||
## 5. Platform Resource(不按 project 隔離,明確標記)
|
||
|
||
| Key Pattern | 理由 | 備註 |
|
||
|-------------|------|------|
|
||
| `platform:telegram:polling:leader` | 全域 polling leader 鎖,不屬於任何 tenant | ADR-111 platform_resource |
|
||
| `platform:ollama:topology` | GCP-A/GCP-B/Local 三層路由狀態,所有 tenant 共用 | ADR-111 + ADR-110 |
|
||
| `platform:ollama:gemini_daily_count:{date}` | 全 platform Gemini 緊急路由計數 | ADR-111 |
|
||
|
||
---
|
||
|
||
## 6. 遷移執行順序(三階段)
|
||
|
||
```
|
||
Phase A(雙寫,30 天觀察):
|
||
新 key 寫入 + 舊 key 繼續寫入
|
||
讀取仍以舊 key 為主
|
||
監控:舊 key 讀取次數 / 新 key 命中次數
|
||
|
||
Phase B(雙讀,14 天):
|
||
新 key 為主,舊 key 為 fallback
|
||
讀不到新 key → 讀舊 key,並回填新 key
|
||
監控:舊 key fallback 率必須 < 1%
|
||
|
||
Phase C(移除舊 key 寫入):
|
||
停止寫入舊 key
|
||
舊 key 自然過期
|
||
監控:確認舊 key 0 讀取後才進行
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 驗收標準
|
||
|
||
- [ ] 所有 P0 key 完成 Phase A 雙寫
|
||
- [ ] `decision_manager.py:240` 改為 import `telegram_gateway.SILENCE_KEY_PREFIX`
|
||
- [ ] `ollama:current_primary` 改為 `platform:ollama:topology`(JSON 格式)
|
||
- [ ] 無任何裸 `SCAN *` 或 `SCAN prefix:*`(改為 `SCAN {project_id}:prefix:*`)
|
||
|
||
*最後更新:2026-05-03(台北)*
|