Files
awoooi/apps/api/migrations/awooop_phase2_budget_ledger_2026-05-04.sql
Your Name 8629ac709b
Some checks failed
run-migration / migrate (push) Failing after 59s
Code Review / ai-code-review (push) Successful in 1m8s
Type Sync Check / check-type-sync (push) Successful in 2m27s
feat(awooop): Phase 1-8 完整實作 — AwoooP Agent Platform 六平面架構
## 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>
2026-05-04 19:31:53 +08:00

67 lines
2.8 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- AwoooP Phase 2.6: budget_ledger 建表 + 欄位定義
-- 2026-05-04 ogt + Claude Sonnet 4.6ADR-120 D5 實作)
--
-- 防止 $47k 事故的三層 Hard Kill 架構中的 accounting 層:
-- - 每次 LLM call 完成後寫入一筆 ledger record
-- - 供 Tenant Budget Cache 計算 / 儀表板消費統計 / 告警閾值觸發
--
-- Phase 1 Control Plane migration 必須先執行awooop_projects 表存在)
-- awooop_run_state 欄位在 Phase 3 SAGA 實作後補加
-- =========================================================
-- STEP 1: 建立 budget_ledger 表
-- =========================================================
CREATE TABLE IF NOT EXISTS budget_ledger (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
project_id VARCHAR(64) NOT NULL DEFAULT 'awoooi',
agent_id VARCHAR(128),
run_id UUID,
model VARCHAR(64),
provider VARCHAR(32),
prompt_tokens INT,
completion_tokens INT,
cost_usd NUMERIC(10, 4) NOT NULL DEFAULT 0.0000,
recorded_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
COMMENT ON TABLE budget_ledger IS 'ADR-120: 每次 LLM call 的 token/cost accounting 記錄';
COMMENT ON COLUMN budget_ledger.cost_usd IS 'prompt + completion token 的估算費用USD';
-- =========================================================
-- STEP 2: Index分析 + 查詢效率)
-- =========================================================
CREATE INDEX IF NOT EXISTS idx_budget_ledger_project_date
ON budget_ledger(project_id, recorded_at DESC);
CREATE INDEX IF NOT EXISTS idx_budget_ledger_run
ON budget_ledger(run_id)
WHERE run_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_budget_ledger_agent
ON budget_ledger(project_id, agent_id, recorded_at DESC)
WHERE agent_id IS NOT NULL;
-- =========================================================
-- STEP 3: RLSADR-118 多租戶隔離)
-- =========================================================
ALTER TABLE budget_ledger ENABLE ROW LEVEL SECURITY;
ALTER TABLE budget_ledger FORCE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS budget_ledger_tenant_isolation ON budget_ledger;
CREATE POLICY budget_ledger_tenant_isolation ON budget_ledger
FOR ALL TO awooop_app
USING (project_id = current_setting('app.project_id', TRUE))
WITH CHECK (project_id = current_setting('app.project_id', TRUE));
-- =========================================================
-- STEP 4: GRANT
-- =========================================================
GRANT SELECT, INSERT ON budget_ledger TO awooop_app;
-- =========================================================
-- 驗收查詢
-- =========================================================
-- SELECT tablename, rowsecurity FROM pg_tables WHERE tablename = 'budget_ledger';
-- -- 結果rowsecurity = true
-- SELECT count(*) FROM budget_ledger; -- = 0剛建