接 DB 後真人 OIDC 登入暴露 MC OIDC provider 實作不完整,visionA 端逐項繞過, 讓登入/換帳號可用;另補真轉檔服務的整合 e2e。 OIDC 登入修復(MC 端根因另有交接檔,visionA 先繞過): - email fallback:MC id_token 不發 email claim(ASP.NET Identity 預設 factory 只發 sub/name)→ A7 email 必填擋住登入。callback email 空時用 <sub>@noemail.visiona.local placeholder,不污染 schema,MC 修好發真 email 後 ON CONFLICT 自動覆寫 - prompt=login:authorize 帶 prompt=login(config VISIONA_OIDC_PROMPT_LOGIN,預設關) - logout 連動 MC:logout 回 idp_logout(MC Web :7880 /account/logout,GET),前端用 隱藏 iframe 觸發清 MC session(Web/Api 共享 DataProtection)→ 能換帳號。 config VISIONA_OIDC_LOGOUT_URL、向下相容(未設則只清本地) 真轉檔鏈路 e2e(//go:build realconv,按需對 stage 跑、不污染主測試集): - real_converter_e2e:give 真轉檔服務 contract(init→poll→completed/promote/result) - real_chain_e2e:真轉檔→PromoteToModels→model 進 PG→冪等 全鏈路(對 stage 跑 PASS) 交接檔(給對應團隊根治): - mc-email-claim-handoff:MC 加 email claim(自訂 UserClaimsPrincipalFactory) - converter-promote-oauth-handoff:轉檔服務 OAuth 用 form body 非 Basic Auth 全程 Reviewer 審查 + 對 stage 真環境驗證。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
321 lines
15 KiB
Plaintext
321 lines
15 KiB
Plaintext
# visionA-backend 環境變數範本
|
||
#
|
||
# 使用方式:
|
||
# cp .env.example .env
|
||
# # 視情況修改 .env 內的值(尤其 VISIONA_STORAGE_SIGNING_SECRET 與 VISIONA_PAIRING_TOKEN)
|
||
#
|
||
# ⚠️ 不要把 .env commit 進 git(已在 .gitignore 中排除)
|
||
# 相關文件:
|
||
# - .autoflow/04-architecture/build-deploy.md §9(變數對照表)
|
||
# - internal/config/config.go(每個欄位的定義)
|
||
|
||
# ============================================================
|
||
# 共用
|
||
# ============================================================
|
||
|
||
# 日誌等級:debug / info / warn / error
|
||
VISIONA_LOG_LEVEL=info
|
||
|
||
|
||
# ============================================================
|
||
# api-server
|
||
# ============================================================
|
||
|
||
# 對前端的 REST / WebSocket port(對齊 local-tool 的 base URL 預設)
|
||
VISIONA_API_PORT=3721
|
||
|
||
# api-server 連 remote-proxy 的 internal HTTP base URL
|
||
# 本機 go run 時用 localhost;docker-compose 內部會被 compose 覆寫為 http://remote-proxy:3801
|
||
VISIONA_PROXY_INTERNAL_URL=http://localhost:3801
|
||
|
||
# Static user — Phase 0.7 security audit 後僅供 dev seed(VISIONA_SEED_DEMO_DATA=true)
|
||
# 與 unit test fixture 用;不再注入 api.Deps、stage/prod 留空無影響。
|
||
# 見 .autoflow/05-implementation/review/phase-0.7-security-audit.md C1。
|
||
VISIONA_STATIC_USER_ID=demo-user
|
||
|
||
# 啟動時 seed 示範資料(device + model + pairing token),方便前端 demo
|
||
VISIONA_SEED_DEMO_DATA=true
|
||
|
||
# CORS 白名單(逗號分隔)— 預設允許 frontend dev server(http://localhost:3000)
|
||
VISIONA_CORS_ALLOWED_ORIGINS=http://localhost:3000
|
||
|
||
# ============================================================
|
||
# OIDC(必填 — OB5 起 OIDC 是唯一認證路徑;A1 起支援 public PKCE-only client)
|
||
# ============================================================
|
||
# 必填欄位缺任何一項,main.go 啟動時會 fatal log 退出。
|
||
#
|
||
# 對應 Innovedus Member Center 的 OIDC client 設定:
|
||
# - 在 Member Center 註冊一個 OAuth client(confidential 或 public 皆可)
|
||
# - 取得 client_id(public client 沒有 client_secret)
|
||
# - 將 RedirectURL 加入 Member Center 的白名單
|
||
|
||
# Member Center 的 issuer(不帶結尾斜線;MC 的 issuer 末尾斜線必要時請保留)
|
||
# dev: http://localhost:5050
|
||
# stage: https://stage-9527.innovedus.com:7850/
|
||
# prod: https://members.innovedus.com
|
||
VISIONA_OIDC_ISSUER_URL=http://localhost:5050
|
||
|
||
# 在 Member Center 註冊的 OAuth client_id
|
||
VISIONA_OIDC_CLIENT_ID=visiona-cloud
|
||
|
||
# Client secret(A1:選填 — public PKCE-only client 留空)
|
||
# - 有值 → confidential client mode(client_secret + PKCE 雙保險)
|
||
# - 留空 → public PKCE-only client mode(依靠 PKCE 防 code interception)
|
||
# ⚠️ 不可 commit;prod 用 Secrets Manager。Stage MC 配的 client `b8093fea...` 是 public,留空。
|
||
VISIONA_OIDC_CLIENT_SECRET=
|
||
|
||
# Backend callback URL — 必須與 Member Center 註冊值完全一致
|
||
# dev: http://localhost:3721/api/auth/callback
|
||
# stage: https://stage-9527.innovedus.com:9527/api/auth/callback
|
||
# prod: https://api.visiona.cloud/api/auth/callback
|
||
VISIONA_OIDC_REDIRECT_URL=http://localhost:3721/api/auth/callback
|
||
|
||
# Frontend base URL — callback 完成後 302 redirect 的目的地
|
||
# dev: http://localhost:3000
|
||
# stage: https://stage-9527.innovedus.com:9527
|
||
# prod: https://app.visiona.cloud
|
||
VISIONA_FRONTEND_URL=http://localhost:3000
|
||
|
||
# MC 連動登出入口(讓使用者登出 visionA 後能換帳號)
|
||
# 背景:Member Center 不支援標準 OIDC RP-initiated logout(discovery 的
|
||
# end_session_endpoint 是 POST+JSON API、非標準 GET 流程,且 client 未註冊
|
||
# post_logout_redirect_uri),後端無法乾淨地 302 導向 MC end_session。
|
||
# 唯一瀏覽器可觸發的 MC 登出是 MemberCenter.Web(:7880)的 /account/logout(GET 即 302)。
|
||
# 設定本變數後,POST /api/auth/logout 的 response 會多回 idp_logout(url + method=GET),
|
||
# 由前端 navigate(window.location)觸發 MC 登出。
|
||
# **host 必須是 MC Web :7880,不是 MC Api :7850**(:7850 沒 logout 頁、會 404)。
|
||
# **留空=logout 只清 visionA 本地 session、不連動 MC(向下相容)。**
|
||
# stage 範例:https://stage-9527.innovedus.com:7880/account/logout
|
||
VISIONA_OIDC_LOGOUT_URL=
|
||
|
||
# 強制每次登入都重新認證(OIDC prompt=login)
|
||
# - true → authorize request 帶 prompt=login,IdP 忽略既有 SSO session、要求重新輸入帳密。
|
||
# - false → 沿用 IdP 既有 session(標準 SSO 體驗),為預設值。
|
||
# stage 想「每次點登入都重新輸入帳密」時設 true;prod 視 UX 決定(通常 false)。
|
||
VISIONA_OIDC_PROMPT_LOGIN=false
|
||
|
||
# Phase 0.8b 移除:VISIONA_OIDC_SERVICE_CLIENT_ID / _SECRET
|
||
# 服務間認證從 OAuth client_credentials 改為 pre-shared API key(見 ADR-015、conversion.md §3)。
|
||
# 兩個 service client env 不再讀取(OIDCConfig.ServiceClientID/Secret struct 欄位
|
||
# 為了 backward compat 暫保留、但 conversion 模組不再依賴)。
|
||
# 取代設定見下方 Phase 0.8 / 0.8b 區塊的 VISIONA_CONVERTER_API_KEY
|
||
# (Phase 0.8b v0.6 T4 起 visionA 端不再直接呼叫 FAA、原 VISIONA_FAA_API_KEY 已撤回)。
|
||
|
||
# Cookie HMAC 簽章 secret(⚠️ 至少 32 byte 隨機字串;prod 用 openssl rand -hex 32)
|
||
VISIONA_SESSION_SECRET=CHANGE_ME_TO_RANDOM_64_BYTES_in_production
|
||
|
||
# Cookie 設定(dev 預設 host-only / non-secure;prod 改 .visiona.cloud + Secure=true)
|
||
VISIONA_SESSION_COOKIE_NAME=visiona_session
|
||
VISIONA_SESSION_COOKIE_DOMAIN=
|
||
VISIONA_SESSION_COOKIE_SECURE=false
|
||
|
||
# Session TTL — 預設 7 天 absolute / 24h idle
|
||
VISIONA_SESSION_ABSOLUTE_TTL=168h
|
||
VISIONA_SESSION_IDLE_TTL=24h
|
||
|
||
# Relay 對外可達 URL(agent tunnel 用)— POST /api/pairing/exchange 會回給 agent。
|
||
# 雛形為空時會 fallback 到 wss://relay.visionA.cloud(placeholder)。
|
||
# 實機請設為實際可達的 WSS URL,例:wss://relay.visionA.cloud
|
||
VISIONA_RELAY_PUBLIC_URL=
|
||
|
||
|
||
# ============================================================
|
||
# remote-proxy
|
||
# ============================================================
|
||
|
||
# 對 local agent 的 WebSocket tunnel port
|
||
VISIONA_TUNNEL_PORT=3800
|
||
|
||
# 對 api-server 的 internal HTTP port(不對外暴露)
|
||
VISIONA_PROXY_INTERNAL_PORT=3801
|
||
|
||
|
||
# ============================================================
|
||
# Tunnel 心跳 / 掉線判定(對齊 tunnel.md §4.2)
|
||
# ============================================================
|
||
|
||
VISIONA_TUNNEL_HEARTBEAT_INTERVAL=10s
|
||
VISIONA_TUNNEL_IDLE_TIMEOUT=30s
|
||
|
||
|
||
# ============================================================
|
||
# Storage(LocalFS — Phase 0 雛形;Phase 1 會改 S3)
|
||
# ============================================================
|
||
|
||
# 儲存根目錄(容器內;docker-compose 已 mount 成 volume)
|
||
VISIONA_STORAGE_BACKEND=localfs
|
||
VISIONA_STORAGE_LOCALFS_ROOT=./data/storage
|
||
|
||
# 瀏覽器 / 上傳 client 看到的 presigned URL base
|
||
# 本機開發:http://localhost:3721/storage
|
||
# docker-compose demo:同上(透過 host port mapping)
|
||
VISIONA_STORAGE_BASE_URL=http://localhost:3721/storage
|
||
VISIONA_STORAGE_LOCALFS_BASE_URL=http://localhost:3721/storage
|
||
|
||
# HMAC 簽章 secret — 用於 LocalFS presigned URL 與(Phase 1)pairing token hash
|
||
# ⚠️ 生產環境必改(openssl rand -hex 32 產生 64 字元 hex)
|
||
VISIONA_STORAGE_SIGNING_SECRET=CHANGE_ME_IN_PRODUCTION_use_openssl_rand_hex_32
|
||
|
||
|
||
# ============================================================
|
||
# Model 上傳限制
|
||
# ============================================================
|
||
|
||
# 單檔上限(MB)— Phase 0 規範 100 MB(PRD §8.4)
|
||
VISIONA_MODEL_MAX_SIZE_MB=100
|
||
|
||
|
||
# ============================================================
|
||
# Pairing(local agent ↔ remote-proxy 配對)
|
||
# ============================================================
|
||
|
||
# 格式:vAc_ + 32 hex(見 security.md §1.3)
|
||
# 建議用:vAc_$(openssl rand -hex 16)
|
||
# 留空代表雛形 InMemoryPairingStore 會動態配發(前端呼叫 POST /api/pairing/token)
|
||
VISIONA_PAIRING_TOKEN=
|
||
|
||
|
||
# ============================================================
|
||
# Phase 0.8 / 0.8b — 轉檔功能整合(converter pre-shared API key)
|
||
# ============================================================
|
||
# 對齊 docs/autoflow/04-architecture/conversion.md §3 + ADR-015 + ADR-016。
|
||
#
|
||
# Phase 0.8b 變更:服務間認證從 OAuth client_credentials 改為 pre-shared API key。
|
||
#
|
||
# 啟用判定:2 個欄位(ConverterBaseURL / ConverterAPIKey)**全部非空**才視為啟用;
|
||
# 任一缺 → 5 個 /api/conversion/* endpoint 不註冊 / 回 501。
|
||
#
|
||
# Phase 0.8b 移除(不再讀取):
|
||
# - VISIONA_OIDC_SERVICE_CLIENT_ID / _SECRET(OAuth client_credentials 機制取消)
|
||
# - VISIONA_OIDC_TENANT_ID(取消 tenant 概念,converter 端的 user_id 仍由 visionA 灌入)
|
||
# - VISIONA_FAA_DELEGATED_TTL_SECONDS(delegated download token 機制取消,改 server-side stream proxy)
|
||
#
|
||
# Phase 0.8b v0.6 T4 移除(不再讀取;ADR-016 撤回 v0.5 設計缺口):
|
||
# - VISIONA_FAA_BASE_URL(visionA 端不再直接呼叫 FAA)
|
||
# - VISIONA_FAA_API_KEY(同上;download / promote 改走 converter.GetResult)
|
||
|
||
# kneron_model_converter task-scheduler base URL
|
||
# dev/stage:http://192.168.0.130:9501
|
||
# prod:https://converter.visiona.cloud
|
||
VISIONA_CONVERTER_BASE_URL=
|
||
|
||
# Pre-shared API key — visionA → converter 服務間認證(Phase 0.8b 新增;ADR-015 §3)
|
||
# 產生:openssl rand -hex 32(64 字元 hex)
|
||
# 與 converter 端 CONVERTER_API_KEY env 對齊(雙方獨立持有,嚴格分環境 dev / stage / prod)
|
||
# ⚠️ 不可 commit;prod 用 Secrets Manager / Vault;log 永遠不印此值全文
|
||
VISIONA_CONVERTER_API_KEY=
|
||
|
||
# 上傳模型檔大小上限(MB)— 與 converter 端 limit 對齊
|
||
VISIONA_CONVERTER_MAX_MODEL_SIZE_MB=500
|
||
|
||
# ============================================================
|
||
# Phase 0.9 — 模型庫 model 直連 FAA 下載(ADR-017 (a))
|
||
# ============================================================
|
||
# 對齊 docs/autoflow/04-architecture/adr/adr-017-model-library-access.md §10(stage e2e 實測藍本)。
|
||
#
|
||
# 下載鏈:visionA 用 service client 打 MC /oauth/token(scope files:download.delegate)
|
||
# → 打 MC POST /file-access/download-tokens(Issue)簽 opaque fdt_ token
|
||
# → 回給 Client「FAA 下載 URL + fdt token」,Client 帶 Authorization: Bearer fdt_...
|
||
# 直接 GET {FAA}/files/{object_key}(不經 visionA、不經 AWS)。
|
||
#
|
||
# 啟用判定:MC_BASE_URL / SERVICE_CLIENT_ID / SERVICE_CLIENT_SECRET / TENANT_ID / FAA_BASE_URL
|
||
# 全部非空才啟用;任一缺 → GET /api/models/:id/download 回 501。
|
||
#
|
||
# ⚠️⚠️ 技術債(ADR-017 §7 R1 / Q10):第一階段 PoC 短期**共用 FAA 的 service client**
|
||
# (stage 用 4242ba63...,實測可拿 files:download.delegate token)。MC 規範明訂
|
||
# 「OAuth client 禁止混用 usage、secret 不共用」——這份 secret 同時被 FAA 與 visionA 持有,
|
||
# 任一邊洩漏會波及兩個服務。**正式上線前須請 MC 配發 visionA 專屬 usage=file_api client**
|
||
# 換掉此共用 client,把 secret 邊界收回 visionA。
|
||
|
||
# Member Center API base URL(不帶結尾斜線)
|
||
# stage:https://stage-9527.innovedus.com:7850
|
||
VISIONA_FILE_ACCESS_MC_BASE_URL=
|
||
|
||
# Service client(client_credentials grant,打 MC /oauth/token + Issue download token)
|
||
# ⚠️ 技術債:第一階段 PoC 共用 FAA service client(stage:4242ba63099d4f318dd3f143d27ef4c5)
|
||
VISIONA_FILE_ACCESS_SERVICE_CLIENT_ID=
|
||
|
||
# Service client secret
|
||
# ⚠️ 不可 commit;prod 用 Secrets Manager / Vault;log 永遠不印此值全文
|
||
# ⚠️ 技術債:第一階段 PoC 共用 FAA service client secret(正式上線前換 visionA 專屬 client)
|
||
VISIONA_FILE_ACCESS_SERVICE_CLIENT_SECRET=
|
||
|
||
# 簽 download token 時帶給 MC 的 tenant_id(須與 FAA validate 的 tenant 一致)
|
||
# stage:732270c0-449c-489c-bfad-321e9bf89b3d
|
||
VISIONA_FILE_ACCESS_TENANT_ID=
|
||
|
||
# File Access Agent 對外 base URL(不帶結尾斜線)— 組回給 Client 的 download_url 用
|
||
# stage:https://stage-9527.innovedus.com:5081
|
||
VISIONA_FILE_ACCESS_FAA_BASE_URL=
|
||
|
||
# download token 有效期(秒)— ADR-017 Q2 區間 60–300s,預設 120
|
||
VISIONA_FILE_ACCESS_DOWNLOAD_TOKEN_TTL_SECONDS=120
|
||
|
||
|
||
# ============================================================
|
||
# DB 接入塊 0 — PostgreSQL(持久業務資料:model / device / token)
|
||
# ============================================================
|
||
# 對齊 docs/autoflow/04-architecture/database.md §5.5.1。
|
||
#
|
||
# 啟用判定:HOST / USER / NAME 三者全非空才啟用;任一缺 →
|
||
# api-server 不建連線池,所有 repository 維持 in-memory(local dev fallback,雛形行為不變)。
|
||
# ⚠️ 塊 0 範圍:即使啟用,目前 repository 仍是 in-memory(建池只為驗證基礎建設 + 讓 schema 就位);
|
||
# model/device/token 切到 Postgres 是塊 1–3。
|
||
#
|
||
# ⚠️ DB 由他人在 stage host(130) 另開 visionA 專用實例並提供連線資訊;visionA 端不 provision、只接上。
|
||
# ⚠️ PASSWORD 不可 commit;prod 走 Secrets Manager / Vault;log 永遠不印密碼/DSN 全文。
|
||
|
||
# visionA 專用 PG host(credential 已取得;他人在 130 provision)。留空 = 不啟用(用 in-memory)。
|
||
VISIONA_DB_HOST=
|
||
|
||
# PG port,預設 5432
|
||
VISIONA_DB_PORT=5432
|
||
|
||
# app role
|
||
VISIONA_DB_USER=
|
||
|
||
# ⚠️ 不可 commit;走 secrets 機制
|
||
VISIONA_DB_PASSWORD=
|
||
|
||
# visionA 專用 database 名稱
|
||
VISIONA_DB_NAME=
|
||
|
||
# sslmode:stage/prod 用 require / verify-full;本機 testcontainers 用 disable
|
||
VISIONA_DB_SSLMODE=require
|
||
|
||
# pgxpool 連線數上限 / 常駐數
|
||
VISIONA_DB_MAX_CONNS=10
|
||
VISIONA_DB_MIN_CONNS=2
|
||
|
||
# 連線生命週期 / 建池+啟動 ping 逾時
|
||
VISIONA_DB_MAX_CONN_LIFETIME=1h
|
||
VISIONA_DB_CONN_TIMEOUT=5s
|
||
|
||
# 啟動時是否自動跑 migrate up(預設 true)。設 false 改用獨立 `go run ./cmd/migrate up`。
|
||
VISIONA_DB_AUTO_MIGRATE=true
|
||
|
||
|
||
# ============================================================
|
||
# DB 接入塊 4 鉤子 — Redis(僅 userSession:browser cookie session)
|
||
# ============================================================
|
||
# 對齊 docs/autoflow/04-architecture/database.md §5.5.2。
|
||
#
|
||
# ⚠️ 塊 0 只先把 config 鉤子留好,main.go 尚未 wire(等塊 4 接 RedisUserSessionStore)。
|
||
# 啟用判定:HOST 非空即啟用;未啟用 → userSession 仍用 in-memory(process 重啟掉 session)。
|
||
# ⚠️ visionA 專用 Redis 實例由使用者在 130 另起、設密碼;PASSWORD 不可 commit、log 不印全文。
|
||
|
||
# visionA 專用 Redis host。留空 = 不啟用(用 in-memory)。
|
||
VISIONA_REDIS_HOST=
|
||
|
||
# Redis port,預設 6379
|
||
VISIONA_REDIS_PORT=6379
|
||
|
||
# ⚠️ visionA 專用實例必設密碼;不可 commit
|
||
VISIONA_REDIS_PASSWORD=
|
||
|
||
# Redis db index,預設 0
|
||
VISIONA_REDIS_DB=0
|
||
|
||
# 建連 / 啟動 ping 逾時
|
||
VISIONA_REDIS_CONN_TIMEOUT=5s
|