7 Commits

Author SHA1 Message Date
81a32a5bf8 feat(stage): nginx 加 /ws/ location(推論 inference WS + 其餘 /ws/* stub)
兩個 server block(公網 stage-9527 + 內網 IP 直連 192.168.0.130)各加
一條 location /ws/ → proxy_pass api-server(:3721)。缺這條時 /ws/* 會落到
catch-all → Next.js → 404,擋住前端推論頁 WS 握手。

- WS upgrade 三要素(http/1.1 + Upgrade + Connection $connection_upgrade)
- 長 timeout 86400s + proxy_buffering off(比照 /tunnel/connect)
- 不影響既有 /tunnel/connect(不同 path 前綴、互不 shadow)
- 兩 block header 對齊(含 X-Forwarded-Host)

驗證:/ws/devices/test-id/inference 不帶 cookie → 401(過 backend auth)
不再 404;/tunnel/connect 回歸 401;preset 下載 200/206;demo 設定保留。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 06:00:59 +08:00
58313169c2 feat(stage): nginx 加內網 IP 直連 server block(demo 用)
agent 本機 demo 需直連內網 192.168.0.130:9527 建 tunnel(繞過公網邊界
proxy — 那台剝 WS upgrade header、碰不到)。但直連 IP 時 Host=192.168.0.130
不命中 stage-9527 白名單被 444 擋。

加一個 server_name 192.168.0.130 的 server block(複製 stage-9527 block、
XFP 改 http),8 個 location 全對齊含 /tunnel/connect WS upgrade。現有兩
block(default 白名單 + stage-9527)一字未動。

安全:公網經 proxy 進來 Host 固定 stage-9527、偽造 Host 打不進;IP block
只內網可達;default 444 白名單未削弱。⚠️ demo 專用、正式上線前應移除或
加 allow/deny(註解已標)。

搭配 .env.stage VISIONA_RELAY_PUBLIC_URL 改內網 ws(部署時設、缺一不可)。
Reviewer 通過 0C/0M/0Mi。stage 純 demo 無正式使用者。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 20:59:13 +08:00
838d10b084 fix(stage): nginx 加 /preset-models/ 反代到 api-server(B8 stage 修正)
preset .nef 公用下載端點 GET /preset-models/{id}.nef 由 api-server :3721
串流。nginx.stage.conf 原本無此 location → 落 catch-all 反代到 frontend
:3000 → 404。

加 /preset-models/ location(在 /storage 後、catch-all 前),比照 /storage
pattern:proxy_buffering off 串流大檔、X-Forwarded-Proto https、安全 header
re-add、cache public max-age=86400(preset 公用內容固定)。nginx -t 通過。

配套(同一交付):Dockerfile.stage preset COPY(1d4977a)+ .env.stage 設
VISIONA_PRESET_BASE_URL(git-ignored 不進)。stage e2e 驗證:
GET /preset-models/kl520-yolov5-detection.nef → 200 + 7506224 bytes(與原檔一致)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:52:11 +08:00
1d4977a974 fix(stage): Dockerfile.stage 補 preset 模型 COPY(B8 stage 修正)
B8 的 preset COPY 原本只加到 dev 的 Dockerfile.api-server,漏了 stage
實際用的 docker/Dockerfile.stage(multi-stage nginx runtime)→ stage image
無 preset 檔、/preset-models/* 下載 404。

runtime stage 補:
- COPY --from=backend-builder /src/assets/preset-models → /app/assets/preset-models
- ENV VISIONA_PRESET_MODELS_DIR=/app/assets/preset-models(baked 資產、隨 image 走)

docker build --check 通過。Reviewer 複審通過。
注意:VISIONA_PRESET_BASE_URL + nginx /preset-models/ location 由 devops 在
stage 部署時補(Reviewer 指出的兩個 DevOps 配套缺口)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:46:43 +08:00
cabbdde495 feat(visionA-backend): DB 接入後續 — OIDC/pairing FK 收尾 + B4 metadata + nginx healthz + 補測試
DB 接入塊 0-5 上主幹後的收尾工作,讓 DB-on 模式可真人使用 + 補齊功能與測試。

OIDC / pairing FK 修復(接 DB 上線必要):
- 新建 internal/user package(User + Store + InMemory + Postgres);OIDC callback
  驗證 id_token 成功後 fail-closed upsert users(sub 直接當 users.id,MC sub 為 UUID)
- pairing exchange 雲端自建 device(不動 local-tool)+ 同 tx 綁 session token;
  自建 device 空 serial 寫 NULL(避免撞 partial unique)
- device.SaveTx / session.CreateTx 新增 tx-aware 版本

B4 model metadata:
- 轉檔 result 的 analysis_info(input_shape/classes/framework)串進 model:
  converter_client → flow → adapter → model.Model → PG → ModelResponse DTO
- input_shape 優先用陣列、後備四維組 NCHW、缺一不亂組;全 optional 防禦性
- 前端詳細頁顯示(另 repo);轉檔端串接交接檔 b4-converter-handoff.md

nginx healthz(部署層):
- 新增 /healthz/deep 轉發 backend(ping PG+Redis、down 回 503)給 LB
- 修掉 default_server return 444 短路 bug(docker healthcheck 長期 unhealthy 真因)

storage error 統一映射(不洩漏 storage 後端細節)。

測試:補 internal/api(storage/errors handler)、cmd/api-server(seed/adapter)、
internal/db(redis)、relay/session 弱處,含 testcontainers integration。
DB 接入相關 package 真環境覆蓋達 88-94%。全程 Reviewer 審查 + 130 真 PG/Redis dbtest 綠。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 06:36:35 +08:00
700b7b08ba chore(stage): 新增 v2 deploy 流程(remote build via DOCKER_HOST)
v1 (deploy-stage.sh) 走 docker save | gzip | docker load 模式,需要把 81MB
tarball 一次性 POST 到 stage docker daemon /images/load API。5/4 / 5/9 兩次
驗證 VPN 下 docker daemon 對單一大 POST hang(卡 30+ 分鐘 / i/o timeout),
公司網段直連才可靠。

v2 仿 edge-ai-platform/scripts/deploy-docker.sh 改用 DOCKER_HOST=stage
docker build — multi-stage build 完全在 stage daemon 上執行:
- 跨網路只傳 build context(~44 MB streaming,VPN 友善)
- alpine base / nodejs / go mod / pnpm install 都由 stage daemon 自己 pull
- layer cache 留在 stage daemon,後續 incremental build 更快
- 5/9 VPN 下實測 work:first build ~3min、redeploy(layer cache) ~10s

連帶修:
- pnpm-workspace.yaml: 加 onlyBuiltDependencies (sharp / unrs-resolver /
  @tailwindcss/oxide / esbuild) — pnpm 10 預設拒跑依賴 build script、
  乾淨環境第一次 install 撞 ERR_PNPM_IGNORED_BUILDS
- package.json: 加 packageManager: pnpm@10.30.1 — 鎖 pnpm 版本,corepack
  在 stage daemon 第一次跑時不會拉到最新 pnpm 11(行為差異)
- Dockerfile.stage: COPY pnpm-workspace.yaml 進 builder context、否則
  容器內 install 看不到 trust list

v1 (deploy-stage.sh) 保留作為公司網段直連備援;v2 是 VPN / 預設模式。
2026-05-11 10:35:21 +08:00
eb66a7287a feat(deploy): visionA Cloud dev / stage docker compose + Caddy/nginx + 部署腳本
新增雲端版部署設定(Phase 0.6 dev + Phase 0.7 stage 分兩套):

dev 環境(docker-compose.dev.yml):
- 5 service all-in-one(postgres + member-center + visionA-backend + frontend + Caddy)
- Caddy 自動 HTTPS for localhost
- .env.dev.example 範本(使用者拷出 .env.dev 後 docker compose up -d)
- Makefile dev-with-mc 9 個 target

stage 環境(docker-compose.stage.yml + docker/Dockerfile.stage):
- multi-stage build(node22 frontend + go1.26 backend × 2 + nginx-alpine runtime)
  最終 image 319 MB,含 nginx + nodejs + tini + bash
- entrypoint.stage.sh 4 process 共命運(nginx + api-server + remote-proxy +
  next.js standalone)用 wait -n + SIGTERM trap
- nginx.stage.conf:白名單 server_name stage-9527.innovedus.com + 444 default_server
  + /healthz 例外(127.0.0.0/8 only)+ /api/ 與 /storage/ 強制 no-store
  + /tunnel/connect WS upgrade + 100M body / 3600s timeout
- 對外 mapping 0.0.0.0:9527:80(公司 host nginx 在外層處理 HTTPS termination
  — Let's Encrypt stage-9527.innovedus.com 自動續簽)
- named volume visiona-data(不用 bind mount,因 stage docker daemon 在 host root
  無 mkdir 權限)

部署腳本(scripts/deploy-stage.sh):
- 仿 edge-ai-platform/scripts/deploy-docker.sh 早期 save/load 模式
- 為什麼不用 internal registry:公司 192.168.0.130:5000 開了 auth、無帳密
- 流程:buildx --load → docker save | gzip → DOCKER_HOST docker load → compose up
- 含 --rollback &lt;tag&gt; / --skip-build / --no-push / --skip-deploy 選項
- timestamp + git SHA tag 留 rollback 餘地

文件(docs/):
- DEV-SETUP.md:dev 環境一鍵起步驟
- SMOKE-TEST.md:手動煙測 checklist(OIDC flow / pairing / tunnel)
- STAGE-DEPLOY.md:stage 完整手冊(架構圖 / 環境前置 / 部署 step / rollback /
  7 種故障排除 / 緊急救回 POC)

.env.stage.example 對齊 backend A1 改造:
- VISIONA_OIDC_CLIENT_SECRET 留空(PKCE-only public client)
- VISIONA_OIDC_SERVICE_CLIENT_ID/_SECRET 留空(Phase 1 預留鉤子)
- 所有 secret 用 placeholder(CHANGE_ME_OPENSSL_RAND_HEX_32)

.dockerignore:避免 node_modules / .next / .git 等進 build context

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 11:22:44 +08:00