
# 專案開發規則

## 語言
- 使用繁體中文回應
- 程式碼註解使用繁體中文

## 技術架構
- 前端：純 HTML5/CSS3/JavaScript（Vanilla JS，IIFE 模組化），無框架
- 後端：Python 3.11+ FastAPI + asyncpg（PostgreSQL），Pydantic 資料模型，Socket.IO 即時通訊
- 資料庫：PostgreSQL 16（Docker），Alembic migration 管理
- 套件管理：後端用 uv + hatchling，前端用 npm
- 其他：SMB/CIFS（NAS 檔案存取）、Line Bot SDK、Telegram Bot、Claude CLI、MCP Server

## 模組索引
- **修改功能前**，先查閱 `docs/module-index.md` 快速定位相關檔案
- 該檔案包含：後端/前端模組地圖、常見修改場景速查

## Dev Tools（ctos CLI 與 skills）

- **查正式機知識庫 / 圖書館**用 `ctos` CLI（不要直接 ssh 去讀檔）：
  - 安裝：`uv tool install ./cli`（或 `uv tool install "git+https://github.com/yazelin/ching-tech-os.git#subdirectory=cli"`）
  - 首次設定：`ctos login --url https://ching-tech.ddns.net/ctos`（互動式，請使用者自己在終端機執行；非互動環境用 `--username` + 環境變數 `CTOS_PASSWORD`）
  - 常用：`ctos kb get kb-182`、`ctos kb search "關鍵字"`、`ctos lib ls`、`ctos files ls projects`（NAS 圖面）、`ctos erp stock <料號>`（庫存/BOM）、`ctos kb add`（寫回知識庫，需 `--read-write` token），完整指令見 `cli/README.md`
- **本 repo 的 Claude Code project skills**（clone 即自動載入）：
  - `ctos-kb`：查知識庫 / 圖書館（使用者提到 kb-NNN 時）
  - `ctos-architecture`：加新功能 / 新 App / 新模組前的架構決策樹與逐檔 checklist
  - `ctos-deploy`：部署機更新 runbook（負責人用）
  - 想在任何資料夾都能用：複製 skill 目錄到 `~/.claude/skills/`
- **新功能骨架**：`python scripts/scaffold.py app|extends|skill|validate`
- **新同事環境設定**：`docs/dev-onboarding.md`
- **部署更新**：負責人在部署機跑 `scripts/update-service.sh`

## 主要目錄結構
- `frontend/`：前端資源（index.html、login.html、css、js、assets）
- `backend/`：後端程式（src/ching_tech_os/、migrations/、pyproject.toml）
  - `api/`：API 路由
  - `services/`：業務邏輯
  - `models/`：Pydantic 資料模型
  - `middleware/`：中介層
  - `skills/`：AI Skills 系統
  - `utils/`：工具函式
  - `migrations/versions/`：Alembic migration 檔案
- `extends/`：外部模組（git submodule），開發規範見 `docs/extends-module.md`
  - `his/`：展望 HIS 整合（private repo）
  - `law/`：律師事務所 AI 工作流（private repo）
- `docker/`：Docker Compose 設定
- `data/`：知識庫資料
- `docs/`：技術文件
- `openspec/`：功能規格與變更管理
- `~/SDD/external-skills/`：外部 Skills（external-first 載入，優先於內建 skills）

## Python 後端重要依賴
- `fastapi` + `uvicorn`：Web 框架與 ASGI server
- `asyncpg` + `sqlalchemy` + `alembic`：資料庫連線、ORM、migration
- `python-socketio`：即時通訊
- `pydantic` + `pydantic-settings`：資料驗證與設定管理
- `anthropic` + `mcp`：Claude AI 整合與 MCP Server
- `line-bot-sdk`：Line Bot 整合
- `python-telegram-bot`：Telegram Bot 整合
- `smbprotocol`：NAS 檔案存取
- `playwright`：瀏覽器自動化
- `python-docx` / `openpyxl` / `python-pptx` / `PyMuPDF`：文件讀寫
- `google-genai`：Google AI 整合
- `claude-code-acp`：Claude Code Agent Protocol

## 版本管理

版本號遵循 [Semantic Versioning](https://semver.org/)：`MAJOR.MINOR.PATCH`

### 版本號位置（需同步更新）
更新版本時，必須同時修改以下三個檔案：
- `backend/pyproject.toml` → `version = "x.x.x"`
- `backend/src/ching_tech_os/__init__.py` → `__version__ = "x.x.x"`
- `backend/src/ching_tech_os/main.py` → FastAPI `version="x.x.x"`

### 何時更新版本
- **MAJOR (x.0.0)**：破壞性變更（API 不相容、資料庫 schema 大改）
- **MINOR (0.x.0)**：新功能、重大整合（向下相容）
- **PATCH (0.0.x)**：Bug 修復、小改動、文件更新

### 版本更新指令
當用戶說「bump version」、「更新版本」或完成重大功能時，主動詢問是否需要更新版本號。

## 資料庫
- 資料庫 schema 變更必須使用 Alembic migration
- Migration 檔案放在 `backend/migrations/versions/`
- 檔案命名格式：`00X_description.py`
- `docker/init.sql` 已停用，所有表格由 Alembic migration 管理
- 執行 migration：`cd backend && uv run alembic upgrade head`
- 直接查詢資料庫：`docker exec ching-tech-os-db psql -U ching_tech -d ching_tech_os -c "SQL語句"`

### AI Logs 查詢
AI 對話記錄儲存在 `ai_logs` 表格（分區表）。常用查詢：

```bash
# 查詢最近 5 筆 AI logs（基本資訊）
docker exec ching-tech-os-db psql -U ching_tech -d ching_tech_os -c "SELECT id, context_type, model, success, duration_ms, created_at FROM ai_logs ORDER BY created_at DESC LIMIT 5"

# 查詢最近一筆的完整回應（raw_response 欄位）
docker exec ching-tech-os-db psql -U ching_tech -d ching_tech_os -c "SELECT raw_response FROM ai_logs ORDER BY created_at DESC LIMIT 1"

# 查詢失敗的請求
docker exec ching-tech-os-db psql -U ching_tech -d ching_tech_os -c "SELECT id, error_message, created_at FROM ai_logs WHERE success = false ORDER BY created_at DESC LIMIT 5"

# 查詢特定 context（如 Line 群組）
docker exec ching-tech-os-db psql -U ching_tech -d ching_tech_os -c "SELECT * FROM ai_logs WHERE context_type = 'line_group' ORDER BY created_at DESC LIMIT 5"
```

**重要欄位**：
- `raw_response`: AI 原始回應（注意：不是 `response_text`）
- `parsed_response`: 解析後的 JSON 結構
- `input_prompt`: 輸入的 prompt
- `context_type`: 來源類型（line_group, line_user, web 等）
- `allowed_tools`: 允許使用的工具列表

## 後端開發
- 使用 FastAPI + asyncpg
- Pydantic 資料模型放在 `models/` 目錄
- 業務邏輯放在 `services/` 目錄
- API 路由放在 `api/` 目錄
- 新增路由後記得在 `main.py` 註冊

### 服務日誌
後端以 systemd 服務運行，查看日誌使用：

```bash
# 查看最近 50 行日誌
journalctl -u ching-tech-os -n 50 --no-pager

# 即時追蹤日誌
journalctl -u ching-tech-os -f

# 查看特定時間範圍
journalctl -u ching-tech-os --since "10 minutes ago"

# 過濾特定關鍵字
journalctl -u ching-tech-os -n 100 --no-pager | grep -i "error"
```

## MCP 工具開發
MCP 工具定義在 `services/mcp_server.py`。

**重要**：MCP Server 是獨立執行的，不會經過 FastAPI 的啟動流程，因此：
- 需要資料庫操作時，**必須**先呼叫 `await ensure_db_connection()` 確保連線
- 參考現有的 `add_note`、`search_knowledge` 等工具的寫法

```python
@mcp.tool()
async def my_tool(param: str) -> str:
    await ensure_db_connection()  # 必須！確保資料庫連線
    # ... 資料庫操作 ...
```

**Prompt 更新**：新增 MCP 工具後，需要同步更新：
1. `bot/agents.py`（或 `linebot_agents.py`）- 程式碼中的 prompt 定義
2. 建立新的 migration 檔案更新資料庫中的 prompt
3. 執行 `uv run alembic upgrade head` 套用變更

## 前端開發
- 使用原生 JavaScript（無框架）
- 模組使用 IIFE 模式
- CSS/JS 檔案需在 `index.html` **和** `login.html` 引入（兩個頁面都需要）
- 桌面應用程式需在 `desktop.js` 的 `applications` 和 `openApp` 中註冊
- **不要**在 JS 或 CSS 檔案路徑後加 `?v=` 版本號（如 `script.js?v=123`），nginx 已設定正確的快取策略

### 圖示使用規則（重要）
**`getIcon()` 必須包在 `<span class="icon">` 裡面**，否則 SVG 大小和對齊會錯誤。

```javascript
// ❌ 錯誤：直接使用 getIcon()
`${getIcon('shield-edit')} 設定權限`

// ✅ 正確：包在 span.icon 裡面
`<span class="icon">${getIcon('shield-edit')}</span> 設定權限`
```

如果需要添加新圖示，在 `frontend/js/icons.js` 的 `Icons` 物件中新增 SVG。
圖示來源：[Material Design Icons](https://pictogrammers.com/library/mdi/)

## 子路徑部署（/ctos）注意事項

本專案支援部署在子路徑下（如 `https://ching-tech.ddns.net/ctos/`），由 `js/config.js` 統一處理。

### 運作原理
```
前端 JS           →  瀏覽器發送             →  nginx 代理        →  後端收到
/api/auth/login   →  /ctos/api/auth/login   →  去掉 /ctos/       →  /api/auth/login
```

- `config.js` 自動檢測路徑並設定 `window.API_BASE`
- `config.js` 覆寫 `fetch()`，自動為 `/api/` 開頭的請求加上 base path
- 後端程式碼**不需要任何修改**

### 需要手動處理的情況

**`fetch()` 呼叫**：自動處理，不需修改 ✅

**HTML 標籤的 `href` / `src` 屬性**：需要手動加 `API_BASE` ⚠️
```javascript
// ❌ 錯誤：不會被 config.js 攔截
`<a href="/api/files/${id}/download">下載</a>`
`<img src="/api/files/${id}/preview">`

// ✅ 正確：手動加上 API_BASE
`<a href="${window.API_BASE || ''}/api/files/${id}/download">下載</a>`
`<img src="${window.API_BASE || ''}/api/files/${id}/preview">`
```

**Socket.IO**：需要單獨處理（見 `socket-client.js`）
```javascript
const basePath = window.API_BASE || '';
const socketPath = basePath ? `${basePath}/socket.io/` : '/socket.io/';
socket = io(BACKEND_URL, { path: socketPath, ... });
```

**`window.open()`**：需要手動加 `API_BASE` ⚠️
```javascript
// ❌ 錯誤：直接使用 /api/... 路徑
window.open(`${API_BASE}/${id}/download`, '_blank');

// ✅ 正確：加上 window.API_BASE
const basePath = window.API_BASE || '';
window.open(`${basePath}${API_BASE}/${id}/download`, '_blank');
```

**`ImageViewerModule` / `TextViewerModule`**：自動處理，不需修改 ✅
```javascript
// 這些 viewer 會自動加上 base path，傳入 /api/... 開頭的路徑即可
ImageViewerModule.open(`/api/knowledge/attachments/${path}`);
TextViewerModule.open(`/api/knowledge/assets/${path}`, filename);
```

### 檢查清單
新增前端功能時，確認以下項目：
- [ ] 新的 JS 檔案已加入 `index.html` 和 `login.html`
- [ ] `<a href="/api/...">` 已加上 `${window.API_BASE || ''}`
- [ ] `<img src="/api/...">` 已加上 `${window.API_BASE || ''}`
- [ ] `window.open('/api/...')` 已加上 `${window.API_BASE || ''}`
- [ ] 其他 HTML 屬性中的 `/api/` 路徑已處理

## CSS 樣式注意事項

### CSS 變數命名規則（重要）
**撰寫 CSS 前，必須先查看 `frontend/css/main.css` 中的變數定義**，使用正確的變數名稱。

#### 命名慣例
- **文字顏色**：`--text-*`（如 `--text-primary`、`--text-secondary`）
- **背景顏色**：`--bg-*`（如 `--bg-surface`、`--bg-overlay`）
- **語義化顏色**：`--color-*`（如 `--color-primary`、`--color-success`）

常用變數對照：
| 用途 | 正確變數名稱 |
|------|-------------|
| 主要文字 | `--text-primary` |
| 次要文字 | `--text-secondary` |
| 靜音文字 | `--text-muted` |
| 主要顏色 | `--color-primary` |
| 主要顏色 hover | `--color-primary-hover` |
| 強調顏色 | `--color-accent` |
| 成功 | `--color-success` |
| 警告 | `--color-warning` |
| 錯誤 | `--color-error` |
| 背景 | `--color-background` |
| 表面背景 | `--bg-surface` |
| 深色表面 | `--bg-surface-dark` |
| 更深表面 | `--bg-surface-darker` |
| 遮罩 | `--bg-overlay-dark` |
| 邊框（輕） | `--border-light` |
| 邊框（中） | `--border-medium` |
| 邊框（強） | `--border-strong` |
| Modal 背景 | `--modal-bg` |
| Modal 邊框 | `--modal-border` |

**禁止**：
- 不要使用錯誤的變數名稱（如 `--color-text-primary`，應為 `--text-primary`）
- 不要硬編碼顏色值（如 `#1e1e2e`、`#4a9eff`）
- 不要使用 fallback 值（如 `var(--color-error, #e53935)`）

### 下拉選單（Select/Dropdown）樣式
**重要**：所有下拉選單必須同時為 `<select>` 和 `<option>` 元素定義樣式。
瀏覽器預設的 `<option>` 背景為白色，在深色主題下會造成顏色不協調。

範例：
```css
.xxx-filter-select {
  background: var(--bg-surface);
  color: var(--text-primary);
}

/* 重要：必須為 option 元素定義背景和文字顏色 */
.xxx-filter-select option {
  background-color: var(--color-background);
  color: var(--text-primary);
}
```

### 模態框（Modal）遮罩
- 模態框背景遮罩使用 `var(--bg-overlay-dark)` 變數
- 模態框內容區塊使用 `var(--modal-bg)` 變數
- 所有 overlay 類別應使用 CSS 變數，避免硬編碼 rgba 值

## 開發與建置指令

```bash
# 安裝依賴
cd frontend && npm install
cd backend && uv sync

# 前端建置
npm run build  # 或 node scripts/build-frontend.mjs

# 後端 migration
cd backend && uv run alembic upgrade head

# 啟動服務
uv run uvicorn ching_tech_os.main:socket_app --host 0.0.0.0 --port 8088
cd frontend && python3 -m http.server 8080
cd docker && docker compose up -d
```

## 測試
- 後端測試：`cd backend && uv run pytest`
- 前端無自動化測試（純 JS）

## 文件規範

### 文件架構
- `README.md` - 專案概覽、快速開始（保持簡潔）
- `docs/` - 所有詳細技術文件
- `openspec/` - 規格與變更管理

### 文件放置原則
- 詳細的技術設計文件放在 `docs/` 目錄
- **不要**在子目錄（如 `backend/`、`frontend/`）建立 README
- 功能規格使用 openspec 管理（`openspec/specs/`）

### 文件更新時機
- 新增重大功能後更新 `README.md` 功能總覽
- 技術設計變更後更新對應的 `docs/*.md`
- API 變更後更新 `docs/backend.md`

### docs/ 目錄結構
```
docs/
├── extends-module.md        # Extends 外部模組開發指南（contributes.yaml 規格、MCP 工具、Skills）
├── ai-agent-design.md       # AI Agent 架構設計
├── ai-management.md         # AI 管理系統
├── backend.md               # 後端開發指南、API 參考
├── database-design.md       # 資料庫設計
├── design-system.md         # CSS 設計系統
├── docker.md                # Docker 服務設定
├── file-manager.md          # 檔案管理器設計
├── frontend.md              # 前端開發指南
├── linebot.md               # Line Bot 整合
├── mcp-server.md            # MCP Server（AI 工具）
├── realtime.md              # Socket.IO 即時通訊
├── security.md              # 認證與安全
├── smb-nas-architecture.md  # SMB/NAS 架構
└── telegram-bot.md          # Telegram Bot 整合
```

## API 文件
- Swagger UI: `http://localhost:8088/docs`
- ReDoc: `http://localhost:8088/redoc`

## GitHub CLI 注意事項

### Projects (classic) 已棄用
`gh pr view` 等指令可能因 GitHub Projects (classic) 棄用而報錯：
```
GraphQL: Projects (classic) is being deprecated in favor of the new Projects experience
```
**解法**：加上 `--json` 參數指定需要的欄位，避免查詢已棄用的 projectCards：
```bash
# ❌ 會報錯
gh pr view 24

# ✅ 正確：指定欄位
gh pr view 24 --json title,body,state,url,reviews,comments
```

## 授權
- MIT License

## 真實客戶／廠商資料不得進 repo（2026-09-12 起）

這個 repo 是**公開**的。任何真實客戶、供應商、聯絡人的名稱、電話、email、地址、統編、料號、單號，都不得出現在規格、測試資料、fixture、seed、docstring、註解、文件、issue／PR 文字或 commit 訊息裡；範例一律用杜撰名（甲一、乙二、丙丁科技這類）。真實資料只能留在本機 scratchpad 或 NAS，不進版控。動到資料相關程式碼時，用 ERPNext 備份的名稱清單反向掃描一次再 commit（腳本見 `docs/decision-2026-09-real-names-in-history.md`）。2026-09-12 有兩個真實客戶名進了公開歷史，處理成本很高——不要再靠人自己想到這條規則。
