# B8 預設模型(簡單版:寫死常數 + 打包 + 不簽 token) 模型庫「預設模型」原本實際是空的(舊 seed 是 demo 假資料、production 不啟用)。 補 7 個公用預設模型(kl520×4 + kl720×3,來源 local-tool models.json): - metadata 寫死成 Go 常數(presets.go),不進 DB → 公用、不可刪、無 seed 重複 - 7 個 .nef 打包進 image(assets/preset-models/,~61MB;Dockerfile COPY) - download 走 visionA 自己(簡單版不簽 token,preset 公用本不需授權): download handler 三分支 preset→visionA URL / converted→FAA / uploaded→501 - 新 GET /preset-models/*filepath 靜態 serve(無 auth、Content-Disposition attachment 用 mime.FormatMediaType、path-traversal 防禦) - list/get 含 preset(對所有人可見) # B5 詳細頁下載按鈕 + preset 可下載 - model-detail-client.tsx 補下載按鈕(行為對齊列表卡片) - isModelDownloadable 加 preset(source==="preset" → true) - normalizeModelSummary 對 target_chip toLowerCase(修 preset 大寫 KL520 在小寫晶片篩選下被隱藏的 bug;收斂所有來源大小寫) # 測試 backend:presets/preset 下載三分支/靜態 serve/path-traversal/條件對稱 全綠 frontend:詳細頁下載鈕 + preset 可下載 + target_chip 大小寫篩選回歸 38 PASS Reviewer 兩輪通過(Major-1 + Minor-1/2 修畢、複審 0 問題) # backlog(未做的優化) preset 下載改 HMAC presigned / preset .nef 改放 FAA 減 image / metadata 後台可管理 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
78 lines
3.1 KiB
Docker
78 lines
3.1 KiB
Docker
# syntax=docker/dockerfile:1.6
|
||
#
|
||
# visionA-backend / api-server — multi-stage Docker image
|
||
#
|
||
# 設計原則(對齊 build-deploy.md §2 與 backend CLAUDE.md §9):
|
||
# - Multi-stage:builder 階段負責編譯,runtime 階段只帶 binary(image 最小化)
|
||
# - CGO_ENABLED=0:產出 static binary,可直接放進 alpine/distroless
|
||
# - Non-root user:降低 container escape 風險
|
||
# - HEALTHCHECK:container 層級健康檢查(K8s / docker-compose 會用到)
|
||
#
|
||
# Build:
|
||
# docker build -f docker/Dockerfile.api-server -t visiona/api-server:dev .
|
||
# 執行目錄為 visionA-backend/,因此 COPY . . 會把整個 backend 帶進 builder。
|
||
|
||
# ---- Stage 1: builder ----------------------------------------------------
|
||
FROM golang:1.26-alpine AS builder
|
||
|
||
# git 給 go mod download 用(部分 module path 會需要)
|
||
RUN apk add --no-cache git ca-certificates
|
||
|
||
WORKDIR /src
|
||
|
||
# 先 COPY go.mod / go.sum,讓 dependency layer 可以被 cache(只有改依賴才重跑)
|
||
COPY go.mod go.sum ./
|
||
RUN go mod download
|
||
|
||
# 複製其餘原始碼
|
||
COPY . .
|
||
|
||
# 編譯 api-server:
|
||
# - CGO_ENABLED=0:pure Go static binary(alpine 可以直接跑)
|
||
# - -ldflags="-s -w":strip debug info,縮小 binary 大小
|
||
# - -trimpath:去掉原始碼路徑,避免洩漏 builder 主機資訊
|
||
ENV CGO_ENABLED=0 GOOS=linux
|
||
RUN go build -trimpath -ldflags="-s -w" -o /out/api-server ./cmd/api-server
|
||
|
||
# ---- Stage 2: runtime ----------------------------------------------------
|
||
FROM alpine:3.19
|
||
|
||
# 安裝 curl 給 HEALTHCHECK 用 + ca-certificates 給未來 HTTPS out-bound 用
|
||
# (Phase 0 雛形沒 outbound HTTPS,但預裝不增加太多體積,避免日後踩雷)
|
||
RUN apk add --no-cache ca-certificates curl tzdata && \
|
||
addgroup -S -g 1001 visiona && \
|
||
adduser -S -u 1001 -G visiona visiona
|
||
|
||
WORKDIR /app
|
||
|
||
# 建立 storage 目錄(讓 LocalFS backend 預設路徑可寫)
|
||
RUN mkdir -p /app/data/storage && chown -R visiona:visiona /app
|
||
|
||
# 複製 binary
|
||
COPY --from=builder --chown=visiona:visiona /out/api-server /app/api-server
|
||
|
||
# B8:7 個系統預設模型 .nef 打包進 image(GET /preset-models/* 直接串流,不簽 token)。
|
||
# 對齊 config.StorageConfig.PresetModelsDir 預設 ./assets/preset-models(容器內 /app/assets/preset-models)。
|
||
COPY --chown=visiona:visiona assets/preset-models /app/assets/preset-models
|
||
|
||
# 切到非 root
|
||
USER visiona:visiona
|
||
|
||
# api-server 預設 listen 3721(對齊 local-tool,見 config/config.go ServerConfig.Port)
|
||
EXPOSE 3721
|
||
|
||
# 預設環境變數:容器內的儲存路徑。
|
||
# 實際部署時由 docker-compose 或 K8s ConfigMap / Secret 覆蓋。
|
||
ENV VISIONA_HOST=0.0.0.0 \
|
||
VISIONA_API_PORT=3721 \
|
||
VISIONA_STORAGE_LOCALFS_ROOT=/app/data/storage \
|
||
VISIONA_PRESET_MODELS_DIR=/app/assets/preset-models \
|
||
VISIONA_LOG_LEVEL=info
|
||
|
||
# Container 層級 healthcheck — docker / compose 會用。
|
||
# 30s 週期、3s timeout、連續 3 次失敗視為 unhealthy。
|
||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||
CMD curl -fsS http://localhost:3721/healthz || exit 1
|
||
|
||
ENTRYPOINT ["/app/api-server"]
|