2026-06-18 · branch
feature/FR-039-evidence-agent(BE + evidence-agent)· 均未 push 接手前必讀:①design.md②2026-06-18-FR039-progress.md(進度表)③ 本檔 ④2026-06-18-FR039-next-prompt.md
WHY:Guidant AI 是雲端 SaaS,但客戶的證據檔案是機敏資料,部分客戶不接受上傳到我們雲端託管。所以把「檔案儲存」拉出去,落地在客戶自有設備;雲端依不同客戶把檔案轉發到客戶端的 agent,binary 不存我們雲端磁碟。
目標不是「做一個檔案上傳服務」,是「讓檔案物理上待在客戶機房、雲端只持有指標 + 業務 metadata」。任何改動若讓 binary 回流雲端磁碟,就是違背初衷。
冷接自檢(答得出才開工):
STORAGE_CONFIG(per-tenant、走 RLS)。雲端 BE(compliance-manager-be) 客戶 server(121 / 122)
───────────────────────────────── ──────────────────────────
業務碼(不動) evidence-agent(獨立 Flask + Docker)
└ IUploadFileProvider(不動) └ jedi-file-upload 原廠(local/minio adapter + 轉檔)
└ RemoteAgentAdapter(Phase 2 新)──HTTP──► └ 既有 MinIO(bucket guidant-ai)
· 寫雲端 upload_files 參照 └ 本地 Postgres(upload_files:uid↔物件名)
· 算 SHA-256 錨點(Phase 3)
STORAGE_CONFIG(per-tenant):remote_agent
· inline base_url,或
· agent_uid → file_agents registry(方案 B)
關鍵設計:
save_file_name 記 agent 回傳的 uid 當跨邊界 key;binary 全在客戶端。STORAGE_CONFIG(system_configs 走 RLS),不是另建 routing 機制。blsadmin / Billows@123!)登入前端,上傳一個新檔。agent_uid=agent-cust-a-121 → registry 拿 http://192.168.50.121:8080 → RemoteAgentAdapter → 121 agent → 落 121 MinIO bucket guidant-ai。UPDATE public.system_configs SET value='{"minio_bucket":"guidant-ai-stg","storage_type":"minio","minio_endpoint":"192.168.50.171:9002","minio_access_key":"admin","minio_secret_key":"1qaz2wsx"}'
WHERE "group"='STORAGE_CONFIG' AND key='CONFIG' AND tenant_id=102;同 121,evidence-agent/deploy/:把 evidence-agent:0.1.0 image(amd64)docker load 到 122 → .env 的 MINIO_ENDPOINT=192.168.50.122:9000 → docker compose up -d。要驗 122 就把 102 改 {"agent_uid":"agent-cust-b-122"}。
jedi-file-upload 的 UploadFileMapper.to_entity 漏 map checksum,已在套件 source 補一行(未 commit)。BE 現 pin 0.0.16 → 要 dev path-dep 或發套件版 才 live;未 live 時整性 fail-open(不驗、不誤擋)。
FE 已有 /system/storage-config(StorageConfigForm.vue,支援 local/minio)。要加:storage_type 多 remote_agent 選項 + agent 下拉(讀 file_agents registry,需新增 BE 查詢 API)。
image 必須 build 成 linux/amd64(客戶 server 是 x86_64,Mac 是 arm64):
# 我們這邊(Mac)
cd ~/Projects/Billows/Audit-Manager/evidence-agent
docker build --platform linux/amd64 --secret id=nexus_auth,src=.secrets/nexus.env -t evidence-agent:0.1.0 .
docker save evidence-agent:0.1.0 | gzip > /tmp/evidence-agent-0.1.0.tar.gz # 傳到 121/122
# 客戶 server(121/122,x86_64)
docker load < evidence-agent-0.1.0.tar.gz
# 放 deploy/docker-compose.yml + .env(填 MINIO_ENDPOINT=本機IP:9000 / keys / bucket / DB_PASSWORD)
docker compose up -d && curl http://localhost:8080/health.secrets/nexus.env(Nexus 帳密 admin/1qaz2wsx)只在 build 用、gitignored。192.168.50.121:9000),非 minio:9000。agent-db。| 雷 | 解 |
|---|---|
exec format error |
image 架構不對:Mac=arm64、server=amd64 → build 要 --platform linux/amd64 |
| 分開 compose 連不到 minio | 不同 compose 不同 network → 用 host LAN IP,非 service 名 |
DB_PASSWORD 含 @ 打爆 DATABASE_URL |
compose 傳 DB_PASSWORD 各段、agent config.py quote_plus 組 URL(已改) |
container name already in use |
移除 container_name(已改);或 docker rm -f 舊 container |
| Postgres 密碼改了沒生效 | Postgres 只在 pgdata 首次初始化套密碼;第一次就設好別後改 |
| 整性驗證被靜默跳過 | jedi-file-upload mapper to_entity 漏 map checksum(write-only)→ 補一行才讀得回 |
| 切 tenant 到 remote_agent 後舊檔讀不到 | read adapter 依「當前 STORAGE_CONFIG」非每檔 storage_type;mixed backend 不支援 |
flask-restful 非 debug 吞 500 |
app_factory 設 PROPAGATE_EXCEPTIONS=True(evidence-agent 已設) |
tenant_id 欄沒出現 |
TenantScopedMixinModel 看 ENABLE_MULTI_TENANT=true env 才加;產 DDL 要帶此 env |
source .env 漏讀後段 |
DB_SECRET JSON 那行會中斷 source;取值用 python parse .env |
minio 預覽 500 os.replace EXDEV |
PDF_CACHE_DIR 不可指 bind-mount(/data);要容器內 /tmp(同 os.replace 目標裝置)。套件已 os.replace→shutil.move 根治(待發版) |
| 轉檔後中文變空白/豆腐字 | LibreOffice 缺 CJK 字型 → Dockerfile 加 fonts-noto-cjk,要重 build image |
| 刪程序書留 minio 孤兒 | 各刪除路徑要經 file_upload_service.delete_file→adapter;已修 delete_from_pool,其他刪除路徑(如 job_evidence)若有同問題比照 |
BE(雲端)
infra/upload_file/remote_agent_adapter.py — RemoteAgentAdapter(HTTP 轉發 + 寫參照 row + SHA-256)infra/upload_file/remote_agent_config_dto.py / common/code/file_storage_type.py(REMOTE_AGENT 常數)app/upload_file/service/managed_file_upload_service.py — _load_config / _build_adapter / _resolve_agent_base_urldomain/file_agent/ + infra/file_agent/ + di_containers/file_agent/ — registry 模組api/uploadfile/routes/uploadfile_route.py — download/preview 的 REMOTE_AGENT 分支scripts/sql/2026-06-18-fr039-file-agents-table.sql — registry 表 migrationevidence-agent(客戶端)
core/app_factory.py(極小)/ config/config.py(env→DTO)/ api/blob/(5 endpoint)/ di_containers/containers.pydeploy/docker-compose.yml + .env.example(客戶部署)/ Dockerfile(含 LibreOffice)CLAUDE.md(專案規範與硬規則)| 項 | 值 |
|---|---|
| dev DB | 192.168.50.188:25432 / guidant_ai_dev / cmmgr(密碼查 .env DB_SECRET) |
| 測試 tenant | 102(登入 blsadmin / Billows@123!) |
| 121 agent | http://192.168.50.121:8080,minio bucket guidant-ai |
| registry uids | agent-cust-a-121(→121)、agent-cust-b-122(→122) |
IUploadFileProvider / 既有 local/minio adapter 不得改。