diff --git a/README.md b/README.md index d138dc5..380f9aa 100644 --- a/README.md +++ b/README.md @@ -1,369 +1,241 @@ # LIMS · 雲原生實驗室資訊管理系統 -> Cloud-Native Laboratory Information Management System — NYCU 雲原生課程學期專案。 -> 涵蓋委託單建立 → 主管簽核 → 收樣分貨 → WIP/派工排程 → 實驗執行 → 結果與報告 → 取件結案 → 主管儀表板 / 告警 / 通知 的完整流程。 - -5 人分工請看 [`docs/team_work_split.md`](docs/team_work_split.md),跨組整合規範請看 [`docs/integration_contract.md`](docs/integration_contract.md)。Claude Code 操作慣例與 subagent 對應請看 [`CLAUDE.md`](CLAUDE.md)。 - ---- - -## Quick start +![Version](https://img.shields.io/badge/version-v0.1.0-blue.svg) +![Frontend](https://img.shields.io/badge/frontend-Next.js%2016%20%2B%20React%2019-111827.svg) +![Backend](https://img.shields.io/badge/backend-FastAPI%20%2B%20Python%203.12-059669.svg) +![Deploy](https://img.shields.io/badge/deploy-Docker%20%7C%20K3s%20%7C%20Argo%20CD-f97316.svg) +![Tests](https://img.shields.io/badge/tests-pytest%20%7C%20Vitest%20%7C%20Playwright-7c3aed.svg) + +> Cloud-Native Laboratory Information Management System,NYCU 雲原生課程學期專案。 + +本專案是一套以完整實驗室流程為核心的 LIMS:從委託單建立、主管簽核、收樣與 WIP 管理、派工排程、實驗執行、結果報告,到取件結案、主管儀表板、異常告警與通知中心。系統採前後端分離與容器化部署,後端提供 FastAPI/OpenAPI 文件,前端提供角色導向操作介面,並以 PostgreSQL、Redis、Celery、Docker Compose、K3s 與 Argo CD 串起本地開發到雲原生部署的路徑。 + +- Frontend README: [frontend/README.md](frontend/README.md) +- Backend README: [backend/README.md](backend/README.md) +- 團隊分工: [docs/team_work_split.md](docs/team_work_split.md) +- 整合規範: [docs/integration_contract.md](docs/integration_contract.md) + +## 系統架構 + +```text +Browser + | + v +Frontend: Next.js 16 + React 19 + | + v +Backend API: FastAPI + JWT cookie auth + OpenAPI + | + +--> PostgreSQL 16: orders, samples, WIP, machines, reports, users... + +--> Redis 7: Celery broker, cache, SSE pub/sub + +--> Celery worker: notifications, escalation, async jobs + +--> Celery beat: scheduled escalation checks + +--> TAS MQTT listener: optional phone-alert acknowledgement pipeline +``` -從零到「在 browser 看到 dashboard」的 5 個步驟。 +部署與開發支援三種情境: -```bash -# 1. 啟動 Postgres + Redis (docker) -make infra +| 情境 | 用途 | 入口 | +| -------------- | -------------------------- | -------------------------------------------------------- | +| Docker Compose | 快速跑完整 stack | [docker-compose.yml](docker-compose.yml) | +| 本地開發 | 分別啟動前後端,方便 debug | [Makefile](Makefile) | +| K3s / Argo CD | 雲原生部署與環境推進 | [deploy/k3s](deploy/k3s), [deploy/argocd](deploy/argocd) | -# 2. 安裝 backend Python 依賴 + 跑 migration + seed -cd backend -python -m venv venv && source venv/bin/activate -make -C .. install-backend # = pip install -r requirements.txt -r requirements-dev.txt -make -C .. revision msg="0001 e initial e tables" # 第一次才需要 -make -C .. migrate -make -C .. seed # 灌入 4 個示範帳號 +## Tech Stack -# 3. 啟動 backend (port 8000) -make -C .. dev-backend +| 層 | 技術 | +| ----------------------- | ---------------------------------------------------------------------------- | +| Frontend | TypeScript, React 19, Next.js 16 App Router, TanStack Query, axios, Recharts | +| Backend | Python 3.12, FastAPI, Pydantic v2, SQLAlchemy 2 async, Alembic | +| Database | PostgreSQL 16 | +| Background jobs | Celery 5, Redis 7, Celery Beat | +| Auth | JWT access/refresh token, httpOnly cookie, bcrypt | +| Realtime / notification | SSE, Redis pub/sub, in-app notifications, optional email/TAS phone callout | +| Tests | pytest, httpx, pytest-asyncio, Vitest, Testing Library, Playwright | +| CI / Deploy | GitHub Actions, Docker Compose, K3s manifests, Argo CD applications | -# 4. 另一個 shell:啟動 frontend (port 3000) -cd ../frontend && make -C .. install-frontend && make -C .. dev-frontend +## 專案結構 -# 5. 打開 http://localhost:3000 +```text +Cloud-Native-Development-Project/ +├── README.md # 專案總覽 +├── Makefile # install/dev/test/lint/docker/ci 常用指令 +├── docker-compose.yml # 完整本地 stack +├── docker-compose.ci.yml # CI compose overlay +├── backend/ # FastAPI 後端服務 +│ ├── README.md +│ ├── app/ +│ ├── alembic/ +│ ├── scripts/ +│ └── tests/ +├── frontend/ # Next.js 前端應用 +│ ├── README.md +│ ├── app/ +│ ├── components/ +│ ├── src/ +│ └── tests/ +├── docs/ # 需求、流程、整合規範與模組文件 +├── tests/e2e/ # Playwright 端到端測試 +├── deploy/k3s/ # Kubernetes/K3s manifests +└── deploy/argocd/ # Argo CD Application manifests ``` -預設帳號(`scripts/seed_dev.py` 內定義): +## 快速啟動 -| Email | 密碼 | 角色 | -|---|---|---| -| `admin@example.com` | `Admin1234` | 系統管理者 (`*` 全權限) | -| `supervisor@example.com` | `Super1234` | 實驗室主管 | -| `engineer@example.com` | `Engin1234` | 實驗室人員 | -| `requester@example.com` | `Reque1234` | 廠區使用者 | +### Mode A: Docker 完整堆疊 -> 想看完整 docker-compose 版本(含 celery worker / beat),跳到 [Docker](#docker-完整堆疊) 一節。 +適合 reviewer 或組員快速看到完整系統。 ---- +```bash +# 第一次可先準備後端 env +cp backend/.env.example backend/.env -## Tech stack +# 建置並啟動 frontend、backend、postgres、redis、worker、beat、seed +make build +make up +``` -| 層 | 技術 | -|---|---| -| 前端 | TypeScript + React 19 + **Next.js 16** (App Router) · TanStack Query · axios · inline-style + CSS variables (不用 Tailwind utility class) | -| 後端 | **Python 3.12 + FastAPI** · uvicorn · pydantic v2 | -| DB | **PostgreSQL 16** + SQLAlchemy 2.0 (async) + Alembic 遷移 | -| 背景任務 | **Celery 5 + Redis 7** (Celery Beat 排程告警升級) | -| Auth | JWT (httpOnly cookie) + bcrypt | -| Realtime | SSE (`sse-starlette`) + Redis pub/sub | -| Email | `fastapi-mail` (file backend for demo, SMTP for prod) | -| 測試 | pytest + httpx + pytest-asyncio (BE) · vitest + Playwright (FE) | -| Lint | ruff + mypy (BE) · eslint + tsc (FE) | -| CI | GitHub Actions (`.github/workflows/ci.yml`) | -| 部署 | docker-compose(含 postgres / redis / celery worker / celery beat) | +啟動後: ---- +| Service | URL / Port | 說明 | +| ---------- | -------------------------------: | ----------------------- | +| Frontend | | Next.js 操作介面 | +| Backend | | FastAPI API | +| API docs | | Swagger UI | +| Health | | 後端健康檢查 | +| PostgreSQL | `localhost:5432` | 預設 `lims/lims` | +| Redis | `localhost:6379` | Celery broker + pub/sub | -## Repo 結構 +需要 pgAdmin 時: -``` -Cloud-Native-Development-Project/ -├── README.md ← 你正在看 -├── CLAUDE.md ← Claude Code 操作慣例 + subagent 對應表 -├── Makefile ← `make help` 看所有指令 -├── docker-compose.yml ← 全套服務拓樸(FE + BE + Postgres + Redis + Celery + pgAdmin) -├── .github/workflows/ci.yml ← CI:lint + test + docker build -├── docs/ ← 規範與需求文件 -├── backend/ ← FastAPI 應用 -└── frontend/ ← Next.js 應用 +```bash +docker compose --profile tools up pgadmin ``` -`docs/` 內的關鍵文件: +pgAdmin 預設在 ,帳密由 [docker-compose.yml](docker-compose.yml) 定義。 -| 文件 | 內容 | -|---|---| -| `total.md` | 跨模組總覽 | -| `flow.md` | 委託單 / WIP / Issue 的官方狀態機 | -| `team_work_split.md` | 5 人分工 (A: 委託單;B: 樣品/WIP;C: 機台/Recipe/排程;D: 實驗執行/報告;E: 帳號/設定/告警/儀表板/整合品質) | -| `integration_contract.md` | E 主導的跨模組規範:enum、response 包裝、auth、master-data、新增 module/model/migration 流程 | -| `development_standards.md` | 測試、PR、Definition of Done | -| `naming_and_class_conventions.md` | 檔名、類別、API、DB 命名規則 | -| `frontend_backend_structure.md` | 前後端目錄詳解 | -| `role.md`, `system_setting.md`, `warn.md`, `dashboard.md` | E 模組的需求文件 | -| `order_management.md`, `sample_management.md`, `machine_recipe.md`, `schedule.md`, `experiment_execute.md`, `result_manage.md` | A/B/C/D 模組的需求文件 | +### Mode B: 本地開發模式 ---- - -## Backend (`backend/`) - -### 啟動 +適合修改程式碼、debug、看 hot reload。 ```bash +# 1. 只啟動基礎設施 +make infra + +# 2. 安裝後端依賴、套 migration、灌 demo seed +python -m venv backend/.venv cd backend -python -m venv venv -source venv/bin/activate +source .venv/bin/activate pip install -r requirements.txt -r requirements-dev.txt -cp .env.example .env # 預設指向 localhost postgres / redis - -# DB -alembic revision --autogenerate -m "0001 e initial e tables" # 第一次 +cp .env.example .env alembic upgrade head -python scripts/seed_dev.py # 灌示範帳號 + 角色 + 部門 + 實驗室 - -# API -uvicorn app.main:app --reload --port 8000 # http://localhost:8000 - -# 背景任務(其他 shell) -celery -A app.core.celery_app worker --loglevel=info -celery -A app.core.celery_app beat --loglevel=info -``` - -打開 看 Swagger, 看健康檢查。 +python scripts/seed_dev.py -### 檔案夾用途 +# 3. 另一個 shell 啟動 backend +make -C .. dev-backend +# 4. 另一個 shell 啟動 frontend +cd ../frontend +npm ci +make -C .. dev-frontend ``` -backend/ -├── app/ -│ ├── main.py ← FastAPI factory + CORS + middleware + 例外處理 + /health -│ ├── routes.py ← 中央 router registry;新增 module 在這加一行 -│ │ -│ ├── core/ -│ │ ├── config.py ← Pydantic Settings — 讀 .env / 環境變數 -│ │ ├── database.py ← async SQLAlchemy engine + `get_db()` dependency -│ │ ├── security.py ← bcrypt 雜湊 + JWT 編解碼 -│ │ ├── celery_app.py ← Celery 實例 + beat 排程表 -│ │ └── logging.py -│ │ -│ ├── common/ ← 跨模組共用 -│ │ ├── enums/ ← 全部 status enum(OrderStatus, IssueStatus, ...) -│ │ ├── schemas/ ← ApiResponse / PageResponse / ErrorResponse 三種回傳包裝 -│ │ ├── dependencies/ ← get_current_user, require_permission(code), get_pagination -│ │ ├── middleware/ ← X-Request-ID, request logger -│ │ └── errors.py ← AppError + NotFoundError / ValidationError 等 -│ │ -│ ├── modules/ ← 22 個業務模組(每個都用 5 檔案結構) -│ │ ├── auth/ ← E:login / logout / /api/me -│ │ ├── users/ ← E:使用者 CRUD(這是範本模組) -│ │ ├── roles/ ← E:角色 + 權限 -│ │ ├── master_data/ ← E:給前端下拉的共用資料 -│ │ ├── system_settings/ ← E:系統設定(Phase 2) -│ │ ├── labs/ ← E -│ │ ├── departments/ ← E -│ │ ├── storage_locations/ ← E -│ │ ├── files/ ← E:檔案上傳 -│ │ ├── audit_logs/ ← E:稽核紀錄 -│ │ ├── issues/ ← E:異常 / 告警 / 中止申請(Phase 3) -│ │ ├── notifications/ ← E:通知中心(Phase 3) -│ │ ├── dashboard/ ← E:儀表板聚合 + SSE(Phase 4) -│ │ ├── orders/ ← A:委託單(placeholder) -│ │ ├── samples/, wips/ ← B -│ │ ├── machines/, recipes/, schedules/, dispatches/ ← C -│ │ └── experiment_runs/, reports/ ← D -│ │ -│ ├── db/ -│ │ ├── base.py ← DeclarativeBase + TimestampMixin -│ │ └── models/ ← SQLAlchemy ORM 模型;每個資源一個檔,於 __init__.py re-export -│ │ -│ └── workers/ ← Celery 背景任務 -│ ├── escalation.py ← 每 60s 掃描 open issue 並升級 -│ └── email_sender.py ← 寄送通知 email(file backend / SMTP) -│ -├── alembic/ ← async 遷移;版本檔放 versions/ -│ ├── env.py -│ ├── script.py.mako -│ └── versions/ -│ -├── scripts/ -│ ├── seed_dev.py ← 示範資料(角色 / 使用者 / 部門 / 實驗室) -│ └── sync_enums.py ← 把 app/common/enums/*.py 轉成 frontend enums.ts -│ -├── tests/ -│ ├── conftest.py ← session-scope DB 重建 + seed;提供 client / admin_client / plant_user_client -│ ├── test_health.py -│ └── e_tests/ ← E 的測試(test_auth, test_users, test_roles_master_data) -│ -├── uploads/ ← /api/files 的儲存位置(Phase 6 stretch: MinIO) -├── requirements.txt ← runtime deps -├── requirements-dev.txt ← pytest / ruff / mypy -├── pyproject.toml ← ruff / mypy / pytest 設定 -├── alembic.ini -├── dockerfile ← multi-stage Python image(給 API、worker、beat 共用) -├── .env.example -└── README.md -``` - -**Module pattern** — 每個 `modules//` 都用同樣 5 檔案結構: -| 檔案 | 職責 | -|---|---| -| `router.py` | FastAPI APIRouter — 只放路由、權限 deps | -| `schemas.py` | Pydantic DTO (`Create` / `Update` / `Response` / `Query`) | -| `service.py` | 商業邏輯 — 協調 repository + audit + notification | -| `repository.py` | 純 DB 查詢,不寫業務規則 | -| `dependencies.py` | FastAPI `Depends()` factory(建構 service 等) | - -開新模組請參考 `app/modules/users/` 範本。 - -### 測試 / Lint +### Mode C: CI / 部署重現 ```bash -make test-backend # = pytest --cov=app -make lint-backend # = ruff check + ruff format --check + mypy app -make format # 自動修正 +make ci-backend +make ci-frontend +make ci-build +make ci-e2e ``` -`backend/tests/conftest.py` 會在 session 開始時 drop+recreate schema 並重跑 seed。所以測試需要 Postgres 在跑(`make infra`)。 +K3s 與 Argo CD 文件入口: -### Alembic / migration +- [deploy/k3s/provision.sh](deploy/k3s/provision.sh) +- [deploy/k3s/base](deploy/k3s/base) +- [deploy/k3s/overlays/staging](deploy/k3s/overlays/staging) +- [deploy/k3s/overlays/prod](deploy/k3s/overlays/prod) +- [deploy/argocd/applications](deploy/argocd/applications) -```bash -make revision msg="add foo" # = alembic revision --autogenerate -m "..." -make migrate # = alembic upgrade head -cd backend && alembic downgrade -1 -cd backend && alembic history -``` +## 預設帳號 -遷移檔命名規則:`<順序>_<成員字母>_<簡述>.py`,例如 `0010_a_orders.py`(A 的第一個遷移)。詳見 `docs/integration_contract.md` §13。 +`backend/scripts/seed_dev.py` 會建立 demo 使用者,方便直接登入前端測試角色權限。 ---- +| Email | 密碼 | 角色 | +| ------------------------ | ----------- | ---------- | +| `admin@example.com` | `Admin1234` | 系統管理者 | +| `supervisor@example.com` | `Super1234` | 實驗室主管 | +| `engineer@example.com` | `Engin1234` | 實驗室人員 | +| `requester@example.com` | `Reque1234` | 廠區使用者 | -## Frontend (`frontend/`) +## 環境變數與安全 -### 啟動 +後端環境變數範本在 [backend/.env.example](backend/.env.example)。 ```bash -cd frontend -npm install # 第一次 -npm run dev # http://localhost:3000 +cp backend/.env.example backend/.env ``` -未登入會看到登入畫面(AuthGate 攔截)。用上面的示範帳號登入即可。 +重要設定: -環境變數(可選): +| 變數 | 用途 | +| ----------------------------------- | ----------------------------------- | +| `DATABASE_URL` | PostgreSQL async SQLAlchemy 連線 | +| `REDIS_URL` | Celery broker、cache、SSE pub/sub | +| `JWT_SECRET` | JWT 簽章金鑰,正式環境必須更換 | +| `CORS_ORIGINS` | 允許的前端來源 | +| `EMAIL_BACKEND` | `file` 或 `smtp` | +| `UPLOADS_DIR` | 檔案與 email outbox 儲存位置 | +| `CHT_API_KEY`, `CHT_SERVICE_NUMBER` | 中華電信 TAS phone callout,可留空 | +| `TAS_ENABLED`, `TAS_SN_KEY` | TAS MQTT listener,可留空或設 false | -```bash -export NEXT_PUBLIC_API_URL=http://localhost:8000/api # 預設值即此(Docker build 也用同名 build-arg) -``` +請勿提交 `.env`、真實密碼、API key 或個人電話。開發環境未設定 TAS/CHT credential 時,電話通知流程會 no-op,不影響一般功能。 -### 檔案夾用途 +## 核心功能 -``` -frontend/ -├── app/ ← Next.js 16 App Router 頁面 -│ ├── layout.tsx ← 全站根 layout — mount Providers + AuthGate -│ ├── page.tsx ← / 主管儀表板(Phase 4 改成 API-driven) -│ ├── globals.css ← CSS 變數(--bg, --s1, --blue, ...)— 設計系統的單一來源 -│ ├── login/page.tsx ← /login 登入頁(已登入會自動跳 /) -│ ├── account/page.tsx ← /account 使用者管理(含建立 modal) -│ ├── config/page.tsx ← /config 系統設定(Phase 2) -│ ├── orders/, approve/ ← A 模組頁面 -│ ├── sample/, wip/, transfer/ ← B -│ ├── dispatch/, machine/, recipe/ ← C -│ ├── storage/, exception/, alert/ ← D / E -│ └── 其餘為 placeholder stub(components/PlaceholderPage.tsx) -│ -├── components/ ← 根層級的 React 元件 -│ ├── Sidebar.tsx ← 左側導覽,依 permission 過濾 nav,footer 顯示登入者 -│ ├── AuthGate.tsx ← 根據 useAuth() 狀態渲染 loading / 登入表單 / Sidebar+主畫面 -│ ├── Providers.tsx ← QueryClientProvider + AuthProvider(mounted from layout) -│ ├── LoginForm.tsx ← 登入表單元件(被 AuthGate / /login 共用) -│ ├── PlaceholderPage.tsx ← 未實作頁面的「🚧 施工中」樣板 -│ └── ui/ ← 小型 UI 原件 -│ ├── KpiCard.tsx ← 儀表板 KPI 卡片 -│ └── Chip.tsx ← 狀態標籤 -│ -├── src/ -│ ├── api/ -│ │ └── httpClient.ts ← axios 實例(withCredentials: true 才能帶 cookie) -│ ├── lib/ -│ │ └── queryClient.ts ← TanStack Query client(4xx 不重試等預設) -│ ├── contexts/ -│ │ └── AuthContext.tsx ← useAuth() → { user, login, logout, hasPermission, refresh } -│ ├── services/ ← 每個模組一支型別化的 API client -│ │ ├── auth-api.ts -│ │ ├── user-api.ts -│ │ └── master-data-api.ts -│ ├── types/ -│ │ ├── api.ts ← ApiResponse / PageResponse / ApiErrorBody -│ │ └── user.ts ← User / Role / MeResponse / 等 -│ ├── constants/ -│ │ ├── enums.ts ← 由 backend/scripts/sync_enums.py 自動生成 — 不要手改 -│ │ └── status-labels.ts ← 手寫的中文顯示對照 -│ └── layouts/MainLayout.tsx ← (legacy, 目前未使用) -│ -├── public/ ← 靜態資源 -├── node_modules/ -├── package.json ← Next.js 16, React 19, axios, @tanstack/react-query -├── tsconfig.json ← `@/*` 同時解析 ./src/* 與 ./* -├── eslint.config.mjs -├── postcss.config.mjs -├── next.config.ts -├── next-env.d.ts -├── dockerfile ← (待補 — 目前用 docker-compose build 即可) -├── CLAUDE.md → AGENTS.md ← 「This is NOT the Next.js you know」提醒 -└── README.md -``` +| 模組 | 功能 | +| ---------------------- | -------------------------------------------------------------- | +| 帳號 / 角色 | 登入登出、目前使用者、帳號管理、角色權限、實驗室與 master data | +| 委託單 / 簽核 | 建立送測需求、草稿、送出、主管核准/退回/拒絕、配額檢核 | +| 收樣 / WIP / 轉送 | 樣品收樣、分貨、WIP 狀態、交接與流轉 | +| 機台 / Recipe / 派工 | 機台狀態、Recipe 管理、派工指派、排程策略 | +| 實驗執行 / 報告 / 結案 | 上下機、進度紀錄、結果上傳、報告管理、取件結案 | +| 異常 / 通知 / 儀表板 | Issue 管理、通知中心、告警升級、主管 dashboard、SSE 即時更新 | -**Styling 慣例**:用 `style={{ color: 'var(--blue)' }}` 形式的 inline style + CSS 變數,**不要**用 Tailwind utility class。色票全部在 `app/globals.css` 統一管。 +主要需求與流程文件: -**路徑別名**:`@/*` 同時解析 `./src/*` 和 `./*`,所以 `@/components/Sidebar`(在根 components/)和 `@/contexts/AuthContext`(在 src/contexts/)都能用。 +- [docs/total.md](docs/total.md) +- [docs/flow.md](docs/flow.md) +- [docs/development_standards.md](docs/development_standards.md) +- [docs/frontend_backend_structure.md](docs/frontend_backend_structure.md) +- [docs/order_management.md](docs/order_management.md) +- [docs/sample_management.md](docs/sample_management.md) +- [docs/machine_recipe.md](docs/machine_recipe.md) +- [docs/experiment_execute.md](docs/experiment_execute.md) +- [docs/result_manage.md](docs/result_manage.md) +- [docs/dashboard.md](docs/dashboard.md) -### 測試 / Lint +## API 與測試 -```bash -make test-frontend # vitest(vitest config 待補) -make lint-frontend # eslint + tsc --noEmit -``` +後端啟動後可使用: ---- +- Swagger UI: +- ReDoc: +- OpenAPI JSON: +- Health check: -## Docker 完整堆疊 +常用測試與品質檢查: ```bash -make build # 第一次或 Dockerfile 改後 -make up # 起 FE + BE + postgres + redis + celery worker + celery beat -make up profile=tools # 加上 pgAdmin (port 5050) -make down -make logs # 跟看所有 service log +make test-backend # pytest --cov=app +make test-frontend # vitest +make lint-backend # ruff + ruff format --check + mypy +make lint-frontend # eslint + tsc --noEmit +make ci-e2e # full stack + Playwright ``` -服務拓樸: - -| Service | Port | 用途 | -|---|---|---| -| `frontend` | 3000 | Next.js | -| `backend` | 8000 | FastAPI | -| `postgres` | 5432 | DB(`pgdata` volume 持久化) | -| `redis` | 6379 | Celery broker + cache + SSE pub/sub(AOF 持久化) | -| `celery-worker` | — | 跑 Celery 任務 | -| `celery-beat` | — | 排程器(每分鐘觸發告警升級掃描) | -| `pgadmin` | 5050 | 只有 `--profile tools` 才會啟動 | - -預設帳號 / 密碼 / DB 名稱由 docker-compose 的環境變數控制(見 `docker-compose.yml`)。 - ---- - -## CI - -`.github/workflows/ci.yml` 在每個 push / PR 跑: - -- **backend** — ruff check + ruff format --check + mypy + alembic upgrade head + pytest(使用 postgres + redis service container) -- **frontend** — eslint + tsc --noEmit + next build + vitest (如果有) -- **docker** — `docker compose build` smoke test - ---- - -## 給組員的 onboarding 指引 - -第一次 clone 之後: - -1. 讀 [`docs/team_work_split.md`](docs/team_work_split.md) 確認自己負責哪幾個模組。 -2. 讀 [`docs/integration_contract.md`](docs/integration_contract.md) — enum / API / DB / migration 命名規範都在這。 -3. 讀 [`docs/flow.md`](docs/flow.md) 確認自己模組的狀態機。 -4. 用 Quick start 把 stack 起起來,登入 4 個角色看看 sidebar 差異。 -5. 看 `backend/app/modules/users/` 當作 backend module 範本;複製後改名實作自己的模組。 -6. 看 `frontend/app/account/page.tsx` 當作 frontend 頁面範本(TanStack Query + master-data + 權限判斷)。 -7. 開新 SQLAlchemy 模型時,記得在 `backend/app/db/models/__init__.py` re-export,然後 `make revision msg="0XYY__"`。 -8. 新增 enum 後,跑 `python backend/scripts/sync_enums.py` 把前端 `enums.ts` 重新生成。 +更多細節請看: -有問題優先看 `CLAUDE.md` 和 `docs/integration_contract.md`,或丟到組內群組讓 E 同步。 +- [backend/README.md](backend/README.md) +- [frontend/README.md](frontend/README.md) +- [tests/README.md](tests/README.md) diff --git a/backend/README.md b/backend/README.md index 57049d6..1cd713d 100644 --- a/backend/README.md +++ b/backend/README.md @@ -1,87 +1,256 @@ -# LIMS Backend (FastAPI) +# LIMS Backend -Python 3.12 + FastAPI + SQLAlchemy 2.0 (async) + Alembic + Celery + Redis + PostgreSQL. +![Version](https://img.shields.io/badge/version-v0.1.0-blue.svg) +![Python](https://img.shields.io/badge/Python-3.12-3776ab.svg) +![FastAPI](https://img.shields.io/badge/FastAPI-0.128.8-009688.svg) +![Database](https://img.shields.io/badge/PostgreSQL-16-4169e1.svg) +![Tests](https://img.shields.io/badge/tests-pytest%20%2B%20httpx-7c3aed.svg) -See repo-level `CLAUDE.md` and `docs/integration_contract.md` for the team-wide conventions. +LIMS 後端是以 FastAPI 建立的 API 服務,負責驗證授權、委託單流程、樣品/WIP、派工、實驗執行、報告、結案、異常、通知、儀表板與背景任務。資料層使用 SQLAlchemy 2 async 與 Alembic,背景工作由 Redis + Celery + Celery Beat 處理,並支援可選的中華電信 TAS phone alert / MQTT acknowledgement pipeline。 -## Local development +- Repo README: [../README.md](../README.md) +- Frontend README: [../frontend/README.md](../frontend/README.md) +- Integration contract: [../docs/integration_contract.md](../docs/integration_contract.md) + +## Tech Stack + +| 類別 | 技術 | +| --------------- | ----------------------------------------------------------------- | +| Runtime | Python 3.12 | +| API | FastAPI, Uvicorn, Pydantic v2 | +| DB | PostgreSQL 16, SQLAlchemy 2 async, asyncpg, Alembic | +| Auth | JWT access/refresh token, bcrypt, httpOnly cookie | +| Background jobs | Celery 5, Redis 7, Celery Beat | +| Realtime | SSE, Redis pub/sub | +| Notification | in-app notifications, file/SMTP email, optional TAS phone callout | +| Tests | pytest, pytest-asyncio, httpx | +| Quality | ruff, mypy | + +## 快速啟動 + +從 repo 根目錄啟動 Postgres 與 Redis: ```bash -# 1. Bring up Postgres + Redis via docker-compose (one-off, in another shell) -docker compose up postgres redis +make infra +``` -# 2. Set up the Python venv -python -m venv venv -source venv/bin/activate -pip install -r requirements.txt -r requirements-dev.txt +建立後端環境: -# 3. Copy env file +```bash +cd backend +python -m venv .venv +source .venv/bin/activate +pip install -r requirements.txt -r requirements-dev.txt cp .env.example .env - -# 4. Generate the first migration from current models, then apply -alembic revision --autogenerate -m "0001 e initial schema" alembic upgrade head +python scripts/seed_dev.py +uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 +``` -# 5. Run the API -uvicorn app.main:app --reload --port 8000 +其他 shell 可啟動背景任務: -# 6. In other shells: Celery worker + beat +```bash +cd backend +source .venv/bin/activate celery -A app.core.celery_app worker --loglevel=info celery -A app.core.celery_app beat --loglevel=info ``` -## Layout +根目錄 Makefile 等價指令: + +```bash +make dev-backend +make worker +make beat +make migrate +make seed +``` + +## API 文件 + +啟動 `uvicorn app.main:app --reload --port 8000` 後: + +| Endpoint | 用途 | +| ------------------------------------ | ---------------- | +| | Swagger UI | +| | ReDoc | +| | OpenAPI JSON | +| | Health check | +| | API root summary | + +FastAPI app version 為 `0.1.0`。 + +## API 路由總覽 + +| Prefix | 模組 | +| --------------------------------------------------------------------- | -------------------- | +| `/api/auth/login`, `/api/auth/logout`, `/api/auth/refresh`, `/api/me` | Auth | +| `/api/users` | 使用者管理 | +| `/api/roles` | 角色與權限 | +| `/api/master-data` | 前端下拉與共用主資料 | +| `/api/labs` | 實驗室 | +| `/api/orders` | 委託單與簽核流程 | +| `/api/quotas` | 配額 | +| `/api/samples` | 樣品 | +| `/api/wips` | WIP | +| `/api/transfers` | 樣品轉送 | +| `/api/machines` | 機台 | +| `/api/recipes` | Recipe | +| `/api/dispatches` | 派工 | +| `/api/experiment-runs` | 實驗執行 | +| `/api/reports` | 報告 | +| `/api/closures` | 取件與結案 | +| `/api/issues` | 異常與告警 | +| `/api/notifications` | 通知中心 | +| `/api/dashboard` | 主管儀表板與即時資料 | +| `/api/workflow-*` | 跨模組流程視圖 | + +實際 route registry 位於 `backend/app/routes/registry.py`。 + +## 專案結構 + +```text +backend/ +├── app/ +│ ├── main.py # FastAPI app factory, middleware, error handlers, health +│ ├── routes/ # API routers 與中央 registry +│ ├── services/ # 既有服務層 +│ ├── repos/ # DB repository / mapper +│ ├── schemas/ # 既有 Pydantic schemas +│ ├── modules/ # 模組化 domains: dashboard, machines, recipes... +│ ├── db/ +│ │ ├── base.py # DeclarativeBase / mixins +│ │ ├── session.py # session factory +│ │ └── models/ # SQLAlchemy ORM models +│ ├── common/ +│ │ ├── enums/ # 共用 enum +│ │ ├── schemas/ # ApiResponse / PageResponse / ErrorResponse +│ │ ├── dependencies/ # auth, scope, pagination, lab scope +│ │ ├── middleware/ # request id, request logger +│ │ └── errors.py # AppError 與共用錯誤 +│ ├── core/ +│ │ ├── config.py # Pydantic settings +│ │ ├── database.py # async DB helpers +│ │ ├── security.py # JWT / password hashing +│ │ ├── celery_app.py # Celery app + beat schedule +│ │ └── error_handlers.py +│ └── workers/ # Celery tasks, TAS MQTT listener, email sender +├── alembic/ # migration env 與 versions +├── scripts/ # seed、enum sync、smoke scripts +├── sql/ # schema / bootstrap SQL +├── tests/ # pytest 測試 +├── requirements.txt +├── requirements-dev.txt +├── pyproject.toml +├── alembic.ini +└── .env.example +``` + +目前程式同時包含 `app/routes`、`app/services`、`app/repos` 與部分 `app/modules/` 的分層;新增或調整模組時請優先參考 [../docs/integration_contract.md](../docs/integration_contract.md) 的約定,並與既有路由 registry 對齊。 + +## Environment Variables +複製範本: + +```bash +cp .env.example .env ``` -app/ - main.py # FastAPI factory - routes.py # Central router registry (mounts every module) - core/ # config / database / security / celery_app / logging - common/ # enums, schemas, dependencies, middleware, errors - modules// # router.py, schemas.py, service.py, repository.py, dependencies.py - db/ # Base + TimestampMixin + SQLAlchemy models - workers/ # Celery tasks (escalation, email_sender) -alembic/ # Async migration setup; versions/ is .gitkept until first revision -tests/ # pytest + httpx; E's tests live in tests/e_tests/ + +主要設定: + +| 變數 | 預設 / 範例 | 說明 | +| ------------------------------------------------------ | ---------------------------------------------------- | ------------------------------------ | +| `ENV` | `development` | 執行環境 | +| `DATABASE_URL` | `postgresql+asyncpg://lims:lims@localhost:5432/lims` | async SQLAlchemy DB URL | +| `REDIS_URL` | `redis://localhost:6379/0` | Celery broker、cache、SSE pub/sub | +| `JWT_SECRET` | `change-me-in-prod-please` | JWT 簽章金鑰,正式環境必須更換 | +| `JWT_ALGORITHM` | `HS256` | JWT 演算法 | +| `JWT_ACCESS_EXPIRES_MINUTES` | `60` | access token 有效時間 | +| `JWT_REFRESH_EXPIRES_DAYS` | `7` | refresh token 有效天數 | +| `CORS_ORIGINS` | `http://localhost:3000` | 允許前端來源,逗號分隔 | +| `EMAIL_BACKEND` | `file` | `file` 或 `smtp` | +| `EMAIL_FROM` | `noreply@lims.local` | email 寄件人 | +| `SMTP_HOST`, `SMTP_PORT`, `SMTP_USER`, `SMTP_PASSWORD` | 空 / `587` | SMTP 設定 | +| `UPLOADS_DIR` | `./uploads` | 上傳檔案與 file email backend 位置 | +| `CHT_API_KEY`, `CHT_SERVICE_NUMBER` | 空 | TAS phone callout credential,可留空 | +| `CHT_BASE_URL` | `https://tasapi.cht.com.tw/apis/CHTIoT` | TAS REST API base URL | +| `TAS_ENABLED` | `false` | 是否啟用 TAS phone/MQTT pipeline | +| `TAS_SN_KEY` | 空 | MQTT topic key | +| `TAS_MQTT_BROKER_URL` | `tls://tasapi.cht.com.tw:2883` | TAS MQTT broker | +| `DEMO_PHONE` | 空 | seed users 共用 demo phone | + +未設定 TAS/CHT 時,電話通知任務會記錄並跳過,不影響 API、通知中心或 email demo。 + +## Migration 與 Seed + +```bash +alembic upgrade head +alembic revision --autogenerate -m "add foo" +alembic downgrade -1 +python scripts/seed_dev.py ``` -## Module pattern +根目錄 Makefile: -`app/modules/users/` is the canonical reference — copy its shape when starting a new module: +```bash +make migrate +make revision msg="add foo" +make seed +``` -| File | Purpose | -|---|---| -| `router.py` | FastAPI `APIRouter` — thin; declares routes + permission deps | -| `schemas.py` | Pydantic DTOs (`Create`, `Update`, `Response`, `Query`) | -| `service.py` | Business logic; orchestrates Repository + AuditLogService | -| `repository.py` | Async DB queries; takes `AsyncSession` | -| `dependencies.py` | FastAPI `Depends(...)` factories | +`scripts/seed_dev.py` 會建立 demo 角色、使用者、部門與實驗室;Docker Compose 的 `seed` service 也會自動執行。 -## Lint / Test +## 測試與品質檢查 ```bash -ruff check . # lint -ruff format --check . # format check -mypy app # type check -pytest # tests -pytest --cov=app # with coverage +ruff check . +ruff format --check . +mypy app +pytest +pytest --cov=app ``` -## API docs +根目錄 Makefile: -After `uvicorn app.main:app --reload`: +```bash +make lint-backend +make test-backend +make ci-backend +``` -- Swagger UI: -- ReDoc: -- OpenAPI JSON: -- Health: +測試目錄依模組分組,例如: -## Environment variables +```text +tests/ +├── a_tests/ # order 相關 +├── c_tests/ # machine / recipe / dispatch +├── d_tests/ # experiment / report +├── e_tests/ # auth / user / role / dashboard / notification +└── test_*.py # 跨模組或 regression tests +``` -See `.env.example`. Critical knobs: +## Docker Compose -- `DATABASE_URL` — async SQLAlchemy URL (`postgresql+asyncpg://...`) -- `REDIS_URL` — Celery broker + cache + SSE pub/sub -- `JWT_SECRET` — change in prod -- `EMAIL_BACKEND` — `file` (writes to `uploads/email_outbox.jsonl`) or `smtp` -- `UPLOADS_DIR` — where `app/modules/files` stores bytes +根目錄 [../docker-compose.yml](../docker-compose.yml) 會啟動: + +| Service | 用途 | +| ------------------- | --------------------------------- | +| `postgres` | PostgreSQL | +| `redis` | Redis | +| `migrate` | 一次性 Alembic migration | +| `seed` | 一次性 demo seed | +| `backend` | FastAPI API | +| `celery-worker` | 背景任務 | +| `celery-beat` | 排程任務 | +| `tas-mqtt-listener` | TAS MQTT listener,可選 | +| `frontend` | Next.js 前端 | +| `pgadmin` | DB 管理工具,需 `--profile tools` | + +常用指令: + +```bash +make build +make up +make logs +make down +``` diff --git a/frontend/README.md b/frontend/README.md index e215bc4..7293c1c 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,36 +1,165 @@ -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). +# LIMS Frontend -## Getting Started +![Version](https://img.shields.io/badge/version-v0.1.0-blue.svg) +![Next.js](https://img.shields.io/badge/Next.js-16.2.4-111827.svg) +![React](https://img.shields.io/badge/React-19.2.4-149eca.svg) +![TypeScript](https://img.shields.io/badge/TypeScript-5.x-3178c6.svg) +![Tests](https://img.shields.io/badge/tests-Vitest%20%2B%20Testing%20Library-7c3aed.svg) -First, run the development server: +LIMS 前端是以 Next.js App Router 建立的角色導向操作介面,負責登入、側邊欄權限控制、委託單、簽核、收樣、WIP、派工、實驗執行、報告、結案、通知與主管儀表板等頁面。後端 API 由 `NEXT_PUBLIC_API_URL` 指定,預設連到 `http://localhost:8000/api`。 + +- Repo README: [../README.md](../README.md) +- Backend README: [../backend/README.md](../backend/README.md) + +## Tech Stack + +| 類別 | 技術 | +| ------------- | -------------------------------------- | +| Framework | Next.js 16 App Router | +| UI runtime | React 19 | +| Language | TypeScript | +| Data fetching | TanStack Query, axios | +| Charts | Recharts | +| Tests | Vitest, Testing Library, jsdom | +| Quality | ESLint, TypeScript typecheck, Prettier | + +## 快速啟動 ```bash +cd frontend +npm ci npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +開啟 。若後端也在本機啟動,預設會呼叫 。 + +可選環境變數: + +```bash +NEXT_PUBLIC_API_URL=http://localhost:8000/api +``` -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. +Docker Compose 由根目錄控制: -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. +```bash +cd .. +make up +``` -## Learn More +## Scripts -To learn more about Next.js, take a look at the following resources: +| 指令 | 用途 | +| ----------------------- | ----------------------- | +| `npm run dev` | 啟動 Next.js dev server | +| `npm run build` | 建置 production bundle | +| `npm run start` | 啟動 production server | +| `npm run lint` | ESLint 檢查 | +| `npm run typecheck` | TypeScript 型別檢查 | +| `npm run test` | 執行 Vitest | +| `npm run test:coverage` | 執行 Vitest coverage | +| `npm run format` | Prettier 格式化 | +| `npm run format:check` | Prettier 檢查 | -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +根目錄 Makefile 也提供: -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! +```bash +make dev-frontend +make lint-frontend +make test-frontend +``` -## Deploy on Vercel +## 路由與功能 -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. +| Route | 功能 | +| ------------------- | --------------------------------------------- | +| `/` | 主管儀表板、KPI、WIP pipeline、告警與即時資料 | +| `/login` | 登入頁 | +| `/account` | 使用者與帳號管理 | +| `/orders` | 委託單建立、列表、明細與送出 | +| `/orders/templates` | 委託單範本 | +| `/approve` | 主管簽核、退回、拒絕與特批 | +| `/sample` | 收樣與樣品資訊 | +| `/wip` | WIP 建立、狀態與管理 | +| `/transfer` | 樣品轉送與交接 | +| `/dispatch` | 派工、機台/Recipe 指派 | +| `/machine` | 機台管理與狀態模擬 | +| `/recipe` | Recipe 管理 | +| `/execution` | 實驗執行與進度紀錄 | +| `/report` | 報告建立、編輯、下載與狀態 | +| `/closure` | 取件結案與結案條件檢查 | +| `/issues` | 異常事件 | +| `/notifications` | 通知中心 | +| `/others` | 暫存、入庫或其他流程輔助頁 | + +## 專案結構 + +```text +frontend/ +├── app/ # Next.js App Router pages +│ ├── layout.tsx # 根 layout,掛載 Providers/AuthGate +│ ├── page.tsx # Dashboard +│ ├── globals.css # CSS variables 與全域樣式 +│ ├── login/ +│ ├── account/ +│ ├── orders/ +│ ├── approve/ +│ ├── sample/ +│ ├── wip/ +│ ├── transfer/ +│ ├── dispatch/ +│ ├── machine/ +│ ├── recipe/ +│ ├── execution/ +│ ├── report/ +│ ├── closure/ +│ ├── issues/ +│ ├── notifications/ +│ └── others/ +├── components/ # 全域共用元件 +│ ├── AuthGate.tsx +│ ├── LoginForm.tsx +│ ├── Providers.tsx +│ ├── Sidebar.tsx +│ └── ui/ +├── src/ +│ ├── api/ # axios/http client 與部分 API wrapper +│ ├── constants/ # enum、狀態 label、樣式常數 +│ ├── contexts/ # AuthContext +│ ├── hooks/ # 共用 hooks +│ ├── lib/ # queryClient、錯誤處理、顯示名稱工具 +│ ├── services/ # 模組化 typed API clients +│ └── types/ # 前端共用型別 +├── tests/ # 前端測試 +├── public/ # 靜態資源 +├── package.json +├── vitest.config.ts +├── tsconfig.json +└── next.config.ts +``` + +## API 與資料流 + +- `src/api/httpClient.ts` 建立 axios instance,預設使用 `NEXT_PUBLIC_API_URL`。 +- `src/services/*-api.ts` 放各模組 typed API client,例如 auth、dashboard、dispatches、machines、reports、recipes、user。 +- `src/types/` 放 API response 與 domain types。 +- `src/contexts/AuthContext.tsx` 管理登入狀態、目前使用者、權限判斷、login/logout。 +- `components/AuthGate.tsx` 負責未登入攔截與登入後 layout。 +- `components/Sidebar.tsx` 依使用者權限顯示可用導覽項目。 + +## UI 與樣式慣例 + +- 全域色票與基礎樣式集中在 `app/globals.css`。 +- 共用小元件放在 `components/ui/`,例如 `Btn`、`Chip`、`DataState`、`KpiCard`、`Modal`、`Panel`。 +- 頁面邏輯優先拆到該頁 `hooks/`、`lib/`、`utils/` 或 `components/`,避免大型 page 元件難以測試。 +- 前端 enum 顯示文字與 API enum 要保持一致;必要時參考後端 `backend/scripts/sync_enums.py`。 + +## 開發檢查 + +```bash +npm run lint +npm run typecheck +npm run test +npm run build +``` -Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. +端到端測試在根目錄 [../tests/e2e](../tests/e2e),需啟動完整 stack 後執行。