# 🚀 EwoooC 部署標準作業程序 (SOP)

> **版本日期**: 2026-05-05 (依 ADR-008 / ADR-011 修訂)
> **目標主機**: `ollama@192.168.0.188` (經 `192.168.0.110` 跳板)

## 🛠️ 開發同步流程
由於正式環境使用 Docker Compose + Volume Mount，部署邏輯如下：

### 1. 本地開發與測試
在 Mac 本地完成功能開發，並確認 `./app.py` 執行無誤。

### 2. 同步程式碼 (SCP)
使用 110 作為跳板機，將本地檔案推送至 188 正式目錄：
```bash
# 同步單一檔案
scp -o ProxyJump=wooo@192.168.0.110 app.py ollama@192.168.0.188:/home/ollama/momo-pro/

# 同步目錄
scp -o ProxyJump=wooo@192.168.0.110 -r services/ ollama@192.168.0.188:/home/ollama/momo-pro/
```

若使用 tar 打包差異檔，必須用 Git 物件建立部署包，避免 macOS / iCloud 工作目錄的 `600` 權限或 extended attributes 被帶到正式機，造成 `/static/*` 500：
```bash
BASE=<上一個已部署 commit>
HEAD=$(git rev-parse HEAD)
git diff --name-only "$BASE..$HEAD" > /tmp/momo-deploy-filelist.txt
git archive --format=tar.gz -o /tmp/momo-deploy-files.tar.gz "$HEAD" $(cat /tmp/momo-deploy-filelist.txt)
```

部署前本地必跑靜態檔可讀檢查：
```bash
.venv/bin/python -m pytest tests/test_frontend_v2_assets.py
```

若部署時在 110 → 188 的內層 `scp` 遇到 `Host key verification failed`，先在 110 修正 `known_hosts`，不要用 `StrictHostKeyChecking=no` 硬跳過：
```bash
ssh wooo@192.168.0.110 \
  "ssh-keygen -R 192.168.0.188 && ssh-keyscan -H 192.168.0.188 >> ~/.ssh/known_hosts"
```

修正後先做只寫 `/tmp` 的 smoke，確認 `scp` 與 `ssh` 都通再部署正式檔案：
```bash
ssh wooo@192.168.0.110 \
  "printf smoke > /tmp/momo_scp_smoke.txt && \
   scp /tmp/momo_scp_smoke.txt ollama@192.168.0.188:/tmp/momo_scp_smoke.txt && \
   ssh ollama@192.168.0.188 'cat /tmp/momo_scp_smoke.txt && rm -f /tmp/momo_scp_smoke.txt' && \
   rm -f /tmp/momo_scp_smoke.txt"
```

### 3. 重啟容器
檔案進入掛載目錄後，重啟容器以加載變更：
```bash
ssh -J wooo@192.168.0.110 ollama@192.168.0.188 \
  "cd /home/ollama/momo-pro && docker compose up -d --no-deps --force-recreate momo-app"
```

注意：
- 禁止使用 `docker compose ... --remove-orphans`。
- 禁止影響 `momo-db` 的資料與容器生命週期。
- 若只同步文件、QA script、非 runtime 檔案，不需要重啟容器。

## 🏗️ 重大變更 (Rebuild)
若修改了 `Dockerfile` 或新增了 `requirements.txt` 套件：
```bash
ssh -J wooo@192.168.0.110 ollama@192.168.0.188 \
  "cd /home/ollama/momo-pro && docker compose build momo-app && docker compose up -d --no-deps --force-recreate momo-app"
```

## 🎛️ AI 觀測台前端變更驗收
若修改以下任一類檔案，必須跑 AI 觀測台 QA 套件：
- `templates/admin/*observability*` 或任何 `/observability/*` 頁面 template。
- `templates/ewoooc_base.html` 或 `templates/components/_ewoooc_shell.html`。
- `static/css/observability-system.css` 或 `web/static/css/observability-system.css`。
- `routes/admin_observability_routes.py`。

本地先跑：
```bash
./scripts/quick_review.sh --sync-observability-css
./scripts/quick_review.sh --check-observability-css
./scripts/quick_review.sh --observability-qa
```

若要指定非 production 入口：

```bash
./scripts/quick_review.sh --observability-qa --base-url https://mo.wooo.work
```

部署後再跑：
```bash
./scripts/quick_review.sh --observability-qa
```

QA 套件會檢查：
- `/health` 必須 HTTP 200 且包含 healthy marker。
- CD deploy gate 正反案例 self-test 必須通過。
- 10 個觀測台頁面必須 HTTP 200。
- 每頁必須包含自己的內容 marker。
- 不得外露 `Traceback`、`ProgrammingError`、`UndefinedError`、`relation "`、`查詢失敗:`。
- `observability-system.css` 必須線上 HTTP 200，且包含核心 token/class。
- `static/css/observability-system.css` 與 `web/static/css/observability-system.css` 必須一致。

CD 也會自動判斷觀測台相關變更：

- Deploy 前跑 `./scripts/quick_review.sh --check-observability-css`，確認 CSS mirror 已提交一致，不在 runner 內偷偷修。
- Deploy 前跑 `./scripts/quick_review.sh --observability-qa --skip-production`。
- Deploy 後跑 `./scripts/quick_review.sh --observability-smoke --base-url https://mo.wooo.work --timeout 12`。
- 若變更與觀測台無關，CD 會跳過這組額外 QA，避免拖慢一般後端部署。
- 觸發範圍包含觀測台 templates、shell/topbar、觀測台 CSS、`routes/admin_observability_routes.py`、`quick_review.sh`、`check_observability_*`、`observability_contract.py`、`sync_observability_css.py`。
- 觸發判斷集中在 `scripts/check_observability_deploy_gate.py`，不要在 workflow 內新增第二份長 regex。

## 🔍 維運指令
- **查看日誌**: `docker logs -f momo-pro-system --tail 100`
- **進入資料庫**: `docker exec -it momo-db psql -U momo -d momo_analytics`
- **檢查磁碟**: `df -h`
