From aa6cdd40e97074d6ab6ebc7c4998f21d989ef27d Mon Sep 17 00:00:00 2001 From: Cheng Zhou Date: Mon, 30 Mar 2026 19:03:17 +0800 Subject: [PATCH 1/2] =?UTF-8?q?release(main):=20=E6=B8=85=E7=90=86?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E9=85=8D=E7=BD=AE=E5=B9=B6=E9=87=8D=E7=BB=84?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env | 6 - .../workflows/storage-persistence-guard.yml | 2 +- .gitignore | 11 + .vscode/settings.json | 3 - README.md | 9 +- docs/README.md | 28 ++ docs/{ => audits}/auth-session-acceptance.md | 4 + .../enterprise-ui-acceptance-checklist.md | 5 +- docs/{ => audits}/setup-config-code-audit.md | 8 +- .../{ => audits}/storage-persistence-audit.md | 4 + .../storage-persistence-governance.md | 10 +- docs/{ => guides}/release-checklist.md | 10 +- docs/{ => guides}/setup-config-api.md | 8 +- ...03-04-ctms-enterprise-ui-implementation.md | 8 +- docs/plans/2026-03-05-rd-monitor-design.md | 97 ------- .../2026-03-05-rd-monitor-implementation.md | 137 --------- ...26-03-27-production-init-implementation.md | 4 +- ...3-30-docs-reorganization-implementation.md | 116 ++++++++ ...=> local.postman_environment.example.json} | 9 +- docs/workbench-ui-optimization.md | 262 ------------------ frontend/.env | 6 - frontend/.env.example | 5 + test-results/.last-run.json | 4 - 23 files changed, 215 insertions(+), 541 deletions(-) delete mode 100644 .env delete mode 100644 .vscode/settings.json create mode 100644 docs/README.md rename docs/{ => audits}/auth-session-acceptance.md (93%) rename docs/{ui => audits}/enterprise-ui-acceptance-checklist.md (89%) rename docs/{ => audits}/setup-config-code-audit.md (93%) rename docs/{ => audits}/storage-persistence-audit.md (98%) rename docs/{ => audits}/storage-persistence-governance.md (88%) rename docs/{ => guides}/release-checklist.md (92%) rename docs/{ => guides}/setup-config-api.md (96%) delete mode 100644 docs/plans/2026-03-05-rd-monitor-design.md delete mode 100644 docs/plans/2026-03-05-rd-monitor-implementation.md create mode 100644 docs/plans/2026-03-30-docs-reorganization-implementation.md rename docs/postman/{local.postman_environment.json => local.postman_environment.example.json} (79%) delete mode 100644 docs/workbench-ui-optimization.md delete mode 100644 frontend/.env create mode 100644 frontend/.env.example delete mode 100644 test-results/.last-run.json diff --git a/.env b/.env deleted file mode 100644 index 46e4b092..00000000 --- a/.env +++ /dev/null @@ -1,6 +0,0 @@ -# 递交日期 -> 受理日期 超期(月) -VITE_STARTUP_SUBMIT_ACCEPT_TIMEOUT_MONTHS=1 -# 受理日期 -> 批准日期 超期(月) -VITE_STARTUP_ACCEPT_APPROVAL_TIMEOUT_MONTHS=1 -# 启用项目概览API -VITE_USE_OVERVIEW_API=true diff --git a/.github/workflows/storage-persistence-guard.yml b/.github/workflows/storage-persistence-guard.yml index 01caf1f3..dab6ad20 100644 --- a/.github/workflows/storage-persistence-guard.yml +++ b/.github/workflows/storage-persistence-guard.yml @@ -21,4 +21,4 @@ jobs: - name: Run storage persistence guard run: | - python backend/scripts/storage_persistence_audit.py --format markdown --output docs/storage-persistence-audit.md --fail-on-banned + python backend/scripts/storage_persistence_audit.py --format markdown --output docs/audits/storage-persistence-audit.md --fail-on-banned diff --git a/.gitignore b/.gitignore index a9d5948b..a349a276 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,13 @@ Thumbs.db *.swp *.swo +# Local env files +.env +.env.* +!.env.example +frontend/.env.* +!frontend/.env.example + # Python build artifacts __pycache__/ @@ -57,6 +64,10 @@ lerna-debug.log* logs/ tmp/ *.pid +test-results/ +docs/postman/local.postman_environment.json +docs/postman/*.local.json +!docs/postman/*.example.json # Docker / runtime data pg_data/ diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 3b664107..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "git.ignoreLimitWarning": true -} \ No newline at end of file diff --git a/README.md b/README.md index 067637b1..fe785080 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,14 @@ ## 仓库治理文档 - 分支治理规范:`docs/branch-governance.md` -- 发布检查清单:`docs/release-checklist.md` +- 发布检查清单:`docs/guides/release-checklist.md` + +## 本地配置 +- 本地编辑器配置(如 `.vscode/`)不纳入版本库。 +- 前端环境变量请使用 `frontend/.env`,可从 `frontend/.env.example` 复制。 +- 根目录 `.env` 不作为当前默认启动流程的提交配置文件。 +- Postman 本地环境请基于 `docs/postman/local.postman_environment.example.json` 自行复制,不提交个人环境文件。 +- 文档入口见 `docs/README.md`;当前操作手册集中在 `docs/guides/`,审计与治理文档集中在 `docs/audits/`。 ## 常用流程 1. 用管理员账号登录前端(默认 `admin@example.com / admin123`)。 diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..9b6e816c --- /dev/null +++ b/docs/README.md @@ -0,0 +1,28 @@ +# Docs Index + +CTMS 文档按用途分为三类:当前操作手册、审计与治理记录、历史实现计划。 + +## 当前常用 + +- [`guides/release-checklist.md`](guides/release-checklist.md): 发布前检查项与回归门禁 +- [`guides/setup-config-api.md`](guides/setup-config-api.md): 立项配置接口、联调与冒烟说明 +- [`setup-config-curl-smoke.sh`](setup-config-curl-smoke.sh): 立项配置 curl 冒烟脚本 +- [`postman/setup-config.postman_collection.json`](postman/setup-config.postman_collection.json): Postman 联调集合 +- [`postman/local.postman_environment.example.json`](postman/local.postman_environment.example.json): Postman 本地环境模板 + +## 审计与治理 + +- [`audits/auth-session-acceptance.md`](audits/auth-session-acceptance.md): 鉴权会话验收清单 +- [`audits/enterprise-ui-acceptance-checklist.md`](audits/enterprise-ui-acceptance-checklist.md): Enterprise UI 验收结果 +- [`audits/setup-config-code-audit.md`](audits/setup-config-code-audit.md): 立项配置代码审计记录 +- [`audits/storage-persistence-audit.md`](audits/storage-persistence-audit.md): 存储落库扫描快照 +- [`audits/storage-persistence-governance.md`](audits/storage-persistence-governance.md): 存储落库治理基线与流程 + +## 历史计划 + +- [`plans/`](plans): 设计稿、实施计划与历史交付记录 + +约定: +- `guides/` 放当前仍会被执行、查阅或复制命令的操作文档 +- `audits/` 放验收、治理、审计、扫描结果 +- `plans/` 只作为历史记录,不作为当前操作入口 diff --git a/docs/auth-session-acceptance.md b/docs/audits/auth-session-acceptance.md similarity index 93% rename from docs/auth-session-acceptance.md rename to docs/audits/auth-session-acceptance.md index 7ff9d776..6e7dbec8 100644 --- a/docs/auth-session-acceptance.md +++ b/docs/audits/auth-session-acceptance.md @@ -1,5 +1,9 @@ # Auth Session Acceptance Checklist +Status: `active` +Scope: `auth-session` +Last Updated: `2026-03-30` + 1) Active user 60 minutes without logout - 登录后持续操作 60 分钟,观察 token 多次 /auth/extend 且不会跳登录 diff --git a/docs/ui/enterprise-ui-acceptance-checklist.md b/docs/audits/enterprise-ui-acceptance-checklist.md similarity index 89% rename from docs/ui/enterprise-ui-acceptance-checklist.md rename to docs/audits/enterprise-ui-acceptance-checklist.md index a06ccaff..853e59c9 100644 --- a/docs/ui/enterprise-ui-acceptance-checklist.md +++ b/docs/audits/enterprise-ui-acceptance-checklist.md @@ -1,7 +1,8 @@ # Enterprise UI Acceptance Checklist -Status: `PASS` -Date: `2026-03-04` +Status: `pass` +Scope: `enterprise-ui` +Reviewed On: `2026-03-04` Reviewer: `Codex` - [x] Overview and milestones visual consistency diff --git a/docs/setup-config-code-audit.md b/docs/audits/setup-config-code-audit.md similarity index 93% rename from docs/setup-config-code-audit.md rename to docs/audits/setup-config-code-audit.md index 16c27c25..91ef11e6 100644 --- a/docs/setup-config-code-audit.md +++ b/docs/audits/setup-config-code-audit.md @@ -1,9 +1,13 @@ -# 立项配置代码审计报告(2026-02) +# 立项配置代码审计报告 + +状态: `archived` +适用范围: `setup-config` +审计时间: `2026-02` ## 范围 - 前端:`frontend/src/views/admin/ProjectDetail.vue`、`frontend/src/api/studies.ts`、`frontend/src/types/setupConfig.ts`、`frontend/src/utils/setupFieldLocator.ts` - 后端:`backend/app/api/v1/studies.py`、`backend/app/crud/study_setup_config.py`、`backend/app/schemas/study_setup_config.py`、`backend/app/services/setup_config_excel.py` -- 文档:`docs/setup-config-api.md`、`docs/setup-config-curl-smoke.sh`、`docs/postman/setup-config.postman_collection.json`、`backend/scripts/smoke_setup_config.py` +- 文档:`docs/guides/setup-config-api.md`、`docs/setup-config-curl-smoke.sh`、`docs/postman/setup-config.postman_collection.json`、`backend/scripts/smoke_setup_config.py` ## 发现清单 diff --git a/docs/storage-persistence-audit.md b/docs/audits/storage-persistence-audit.md similarity index 98% rename from docs/storage-persistence-audit.md rename to docs/audits/storage-persistence-audit.md index 183f1d3f..8182d9b1 100644 --- a/docs/storage-persistence-audit.md +++ b/docs/audits/storage-persistence-audit.md @@ -1,5 +1,9 @@ # 存储落库核查报告 +状态: `snapshot` +适用范围: `storage-persistence` +最后更新: `2026-02-27` + - 扫描目录: `/Users/zcc/MyCTMS/ctms-project/frontend/src` - 总发现数: `46` - 高风险: `4` / 中风险: `0` / 低风险: `42` diff --git a/docs/storage-persistence-governance.md b/docs/audits/storage-persistence-governance.md similarity index 88% rename from docs/storage-persistence-governance.md rename to docs/audits/storage-persistence-governance.md index 129558d6..ffa19ce2 100644 --- a/docs/storage-persistence-governance.md +++ b/docs/audits/storage-persistence-governance.md @@ -1,4 +1,8 @@ -# 全项目重要数据落库治理基线(2026-02-27) +# 全项目重要数据落库治理基线 + +状态: `active` +适用范围: `storage-persistence` +最后更新: `2026-02-27` ## 1. 口径 @@ -8,11 +12,11 @@ ## 2. 自动核查入口 ```bash -backend/scripts/storage_persistence_audit.py --format markdown --output docs/storage-persistence-audit.md +backend/scripts/storage_persistence_audit.py --format markdown --output docs/audits/storage-persistence-audit.md backend/scripts/storage_persistence_audit.py --fail-on-banned ``` -- `docs/storage-persistence-audit.md`:当前扫描快照 +- `docs/audits/storage-persistence-audit.md`:当前扫描快照 - `--fail-on-banned`:用于阻断禁止项(当前默认禁止 `audit_local_*`) ## 3. 当前结论(基于 2026-02-27 扫描) diff --git a/docs/release-checklist.md b/docs/guides/release-checklist.md similarity index 92% rename from docs/release-checklist.md rename to docs/guides/release-checklist.md index d323f161..85b71223 100644 --- a/docs/release-checklist.md +++ b/docs/guides/release-checklist.md @@ -1,4 +1,8 @@ -# Release Checklist(立项配置) +# 立项配置发布清单 + +状态: `active` +适用范围: `setup-config` +最后更新: `2026-03-30` ## 1. 构建与迁移 - [ ] `docker compose run --rm backend-init` @@ -59,7 +63,7 @@ - [ ] 导入并执行 Postman 集合 `docs/postman/setup-config.postman_collection.json` ## 9. 发布前确认 -- [ ] 文档已更新:`docs/setup-config-api.md` +- [ ] 文档已更新:`docs/guides/setup-config-api.md` - [ ] 本清单已全量勾选 - [ ] 发布说明已包含新增接口与权限规则 @@ -67,5 +71,5 @@ - [ ] `cd frontend && npm run ui:contract` - [ ] `cd frontend && npm run type-check` - [ ] `cd frontend && npm run build` -- [ ] `docs/ui/enterprise-ui-acceptance-checklist.md` 状态为 `PASS` 且记录审阅日期 +- [ ] `docs/audits/enterprise-ui-acceptance-checklist.md` 状态为 `PASS` 且记录审阅日期 - [ ] 管理层演示路径已走查:`/project/overview -> /project/milestones -> /risk-issues/sae -> /fees/contracts -> /file-versions -> /admin/projects/:id` diff --git a/docs/setup-config-api.md b/docs/guides/setup-config-api.md similarity index 96% rename from docs/setup-config-api.md rename to docs/guides/setup-config-api.md index d2cfcdcb..d921466c 100644 --- a/docs/setup-config-api.md +++ b/docs/guides/setup-config-api.md @@ -1,4 +1,8 @@ -# 立项配置接口说明(Excel 导入导出版) +# 立项配置接口指南 + +状态: `active` +适用范围: `setup-config` +最后更新: `2026-03-30` ## 1. 概览 - 基础路径: `/api/v1/studies/{study_id}/setup-config` @@ -191,7 +195,7 @@ bash docs/setup-config-curl-smoke.sh ## 7. Postman 联调集合 - Collection: `docs/postman/setup-config.postman_collection.json` -- Environment: `docs/postman/local.postman_environment.json` +- Environment: `docs/postman/local.postman_environment.example.json`(导入后建议另存为你自己的本地环境) ## 8. 后端烟雾测试(非 pytest) ```bash diff --git a/docs/plans/2026-03-04-ctms-enterprise-ui-implementation.md b/docs/plans/2026-03-04-ctms-enterprise-ui-implementation.md index f811be6c..c1d60a4f 100644 --- a/docs/plans/2026-03-04-ctms-enterprise-ui-implementation.md +++ b/docs/plans/2026-03-04-ctms-enterprise-ui-implementation.md @@ -409,8 +409,8 @@ git commit -m "feat(ui): unify loading empty error states" ### Task 9: Verification, Demo Path, and Release Gate **Files:** -- Create: `docs/ui/enterprise-ui-acceptance-checklist.md` -- Modify: `docs/release-checklist.md` +- Create: `docs/audits/enterprise-ui-acceptance-checklist.md` +- Modify: `docs/guides/release-checklist.md` - Test: manual smoke + build checks **Step 1: Write the failing test** @@ -435,7 +435,7 @@ Expected: PASS technically, but acceptance checklist remains FAIL/PENDING. - Execute manual smoke on target routes. - Update checklist to PASS with reviewer/date notes. -- Add release gating notes to `docs/release-checklist.md`. +- Add release gating notes to `docs/guides/release-checklist.md`. **Step 4: Run test to verify it passes** @@ -445,7 +445,7 @@ Expected: PASS for all commands and checklist completed. **Step 5: Commit** ```bash -git add docs/ui/enterprise-ui-acceptance-checklist.md docs/release-checklist.md +git add docs/audits/enterprise-ui-acceptance-checklist.md docs/guides/release-checklist.md git commit -m "docs(ui): add enterprise refresh acceptance and release gates" ``` diff --git a/docs/plans/2026-03-05-rd-monitor-design.md b/docs/plans/2026-03-05-rd-monitor-design.md deleted file mode 100644 index 6df62d8c..00000000 --- a/docs/plans/2026-03-05-rd-monitor-design.md +++ /dev/null @@ -1,97 +0,0 @@ -# 研发项目进展监测系统(rd-monitor)设计文档 - -## 1. 目标与范围 -- 基于现有 CTMS 的界面/组件经验,建设一个完全独立的研发项目进展监测系统。 -- 新系统独立前后端、独立数据库、独立鉴权与权限体系。 -- 首期仅实现 PDF《项目进度概览 v2》中的核心功能:概览展示、进度录入、历史变更、导出、项目隐藏规则。 - -## 2. 系统边界 -- 独立仓库:`rd-monitor` -- 技术栈:Vue3 + Element Plus + FastAPI + SQLAlchemy + Alembic + PostgreSQL -- 与 CTMS 关系:仅复用可迁移的组件/样式实现,不依赖 CTMS API 与 CTMS 数据表。 - -## 3. 数据模型 -### 3.1 users -- `id` -- `username` -- `email` -- `password_hash` -- `role` (`ADMIN`/`PM`/`VIEWER`) -- `is_active` -- `created_at` - -### 3.2 projects -- `id` -- `project_code`(如 HP-001) -- `project_name` -- `regulatory_path` -- `status`(`ACTIVE`/`APPROVED`/`TERMINATED`) -- `created_at` - -### 3.3 stage_templates -- `id` -- `stage_key` -- `stage_name` -- `order_no` -- `regulatory_paths`(JSON 数组;空表示通用) -- `is_active` - -### 3.4 project_stages -- `id` -- `project_id` -- `stage_template_id` -- `order_no` -- `planned_start_date` -- `planned_end_date` -- `actual_finish_date` -- `actual_finish_flag`(`DONE`/`NOT_APPLICABLE`/`PENDING`) -- `adjust_reason` -- `remark` -- `updated_at` - -### 3.5 project_stage_change_logs -- `id` -- `project_stage_id` -- `changed_by` -- `before_json` -- `after_json` -- `comment` -- `created_at` - -## 4. 状态规则(按 PDF) -- `已完成`:`actual_finish_flag = DONE` 且 `actual_finish_date` 有值。 -- `未进行`:`actual_finish_flag = NOT_APPLICABLE`(“此阶段不开展”)。 -- `正进行`:当前阶段未完成/未进行,且上一阶段状态为 `已完成`。 -- `未开始`:其余情况。 -- 概览显示日期:使用 `planned_end_date`。 -- 项目隐藏:`APPROVED` 或 `TERMINATED` 不在概览列表中显示。 - -## 5. 页面与交互 -- 登录页(JWT) -- 概览页:按项目展示阶段节点、计划完成日期、状态图例 -- 录入页:项目阶段表格编辑,支持“此阶段不开展” -- 历史页:阶段变更历史时间线/表格 -- 导出:授权用户导出 CSV - -## 6. 权限模型 -- `ADMIN`:用户/项目/模板管理 + 全部导出 -- `PM`:项目进度录入、历史查看、导出 -- `VIEWER`:只读(概览、历史) - -## 7. API(首期) -- `POST /api/v1/auth/login` -- `GET /api/v1/auth/me` -- `GET /api/v1/projects` -- `POST /api/v1/projects`(ADMIN) -- `GET /api/v1/stage-templates` -- `POST /api/v1/stage-templates`(ADMIN) -- `GET /api/v1/projects/{id}/stages` -- `PATCH /api/v1/projects/{id}/stages/{stageId}`(PM/ADMIN) -- `GET /api/v1/projects/{id}/stages/history` -- `GET /api/v1/projects/stages/export?format=csv`(PM/ADMIN) - -## 8. 验收标准 -- 状态计算规则与 PDF 一致 -- 录入保存会生成历史记录 -- 导出字段与录入字段一致 -- `APPROVED/TERMINATED` 项目不在概览展示 diff --git a/docs/plans/2026-03-05-rd-monitor-implementation.md b/docs/plans/2026-03-05-rd-monitor-implementation.md deleted file mode 100644 index 3f4c1189..00000000 --- a/docs/plans/2026-03-05-rd-monitor-implementation.md +++ /dev/null @@ -1,137 +0,0 @@ -# rd-monitor Implementation Plan - -> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. - -**Goal:** 搭建独立仓库 `rd-monitor`,实现研发项目进展监测 MVP(独立鉴权、项目阶段录入、状态计算、历史留痕、CSV 导出、前端可用界面)。 - -**Architecture:** 后端采用 FastAPI + SQLAlchemy + PostgreSQL,提供鉴权、项目阶段、历史、导出 API;前端采用 Vue3 + Element Plus,提供登录、概览、录入、历史页面。通过 Docker Compose 启动前后端与独立 PostgreSQL。 - -**Tech Stack:** Vue3, Vite, Element Plus, FastAPI, SQLAlchemy, Alembic, PostgreSQL, JWT, Pytest - ---- - -### Task 1: 初始化仓库结构与运行骨架 - -**Files:** -- Create: `/Users/zcc/MyCTMS/rd-monitor/README.md` -- Create: `/Users/zcc/MyCTMS/rd-monitor/docker-compose.yml` -- Create: `/Users/zcc/MyCTMS/rd-monitor/backend/requirements.txt` -- Create: `/Users/zcc/MyCTMS/rd-monitor/backend/.env.example` -- Create: `/Users/zcc/MyCTMS/rd-monitor/frontend/package.json` -- Create: `/Users/zcc/MyCTMS/rd-monitor/frontend/vite.config.ts` - -**Step 1: Write the failing test** -- 编写后端 smoke 测试,断言 `/healthz` 返回 200(此时接口不存在,应失败)。 - -**Step 2: Run test to verify it fails** -- Run: `cd /Users/zcc/MyCTMS/rd-monitor/backend && pytest -q` -- Expected: FAIL(缺少 app 或路由)。 - -**Step 3: Write minimal implementation** -- 建立 FastAPI app 与 `/healthz` 路由,补全基础依赖与 compose。 - -**Step 4: Run test to verify it passes** -- Run: `cd /Users/zcc/MyCTMS/rd-monitor/backend && pytest -q` -- Expected: PASS。 - -**Step 5: Commit** -- `git add ... && git commit -m "chore: bootstrap rd-monitor skeleton"` - -### Task 2: 实现后端核心领域模型与状态计算 - -**Files:** -- Create: `/Users/zcc/MyCTMS/rd-monitor/backend/app/models/*.py` -- Create: `/Users/zcc/MyCTMS/rd-monitor/backend/app/services/progress.py` -- Test: `/Users/zcc/MyCTMS/rd-monitor/backend/tests/test_progress_status.py` - -**Step 1: Write the failing test** -- 用测试覆盖阶段状态计算(已完成/未进行/正进行/未开始)与项目过滤规则。 - -**Step 2: Run test to verify it fails** -- Run: `pytest tests/test_progress_status.py -q` -- Expected: FAIL。 - -**Step 3: Write minimal implementation** -- 实现状态计算函数与项目过滤函数。 - -**Step 4: Run test to verify it passes** -- Run: `pytest tests/test_progress_status.py -q` -- Expected: PASS。 - -**Step 5: Commit** -- `git commit -m "feat: add progress status domain rules"` - -### Task 3: 实现鉴权、项目阶段 API、历史记录与导出 - -**Files:** -- Create/Modify: `/Users/zcc/MyCTMS/rd-monitor/backend/app/api/*.py` -- Create/Modify: `/Users/zcc/MyCTMS/rd-monitor/backend/app/schemas/*.py` -- Create/Modify: `/Users/zcc/MyCTMS/rd-monitor/backend/app/core/security.py` -- Test: `/Users/zcc/MyCTMS/rd-monitor/backend/tests/test_stage_api.py` - -**Step 1: Write the failing test** -- 测试登录、查询项目阶段、更新阶段后历史新增、导出 CSV、权限拦截。 - -**Step 2: Run test to verify it fails** -- Run: `pytest tests/test_stage_api.py -q` -- Expected: FAIL。 - -**Step 3: Write minimal implementation** -- 完成相关 API 与依赖。 - -**Step 4: Run test to verify it passes** -- Run: `pytest tests/test_stage_api.py -q` -- Expected: PASS。 - -**Step 5: Commit** -- `git commit -m "feat: implement progress APIs with auth history and export"` - -### Task 4: 实现前端登录、概览、录入、历史页面 - -**Files:** -- Create: `/Users/zcc/MyCTMS/rd-monitor/frontend/src/views/*.vue` -- Create: `/Users/zcc/MyCTMS/rd-monitor/frontend/src/router/index.ts` -- Create: `/Users/zcc/MyCTMS/rd-monitor/frontend/src/api/*.ts` -- Create: `/Users/zcc/MyCTMS/rd-monitor/frontend/src/components/*.vue` - -**Step 1: Write the failing test** -- 首期用类型检查/构建作为回归保护,先运行应失败(页面未实现)。 - -**Step 2: Run test to verify it fails** -- Run: `cd /Users/zcc/MyCTMS/rd-monitor/frontend && npm run build` -- Expected: FAIL。 - -**Step 3: Write minimal implementation** -- 实现可登录、可浏览项目阶段、可编辑阶段、可看历史、可导出。 - -**Step 4: Run test to verify it passes** -- Run: `npm run build` -- Expected: PASS。 - -**Step 5: Commit** -- `git commit -m "feat: add frontend pages for monitoring workflow"` - -### Task 5: 联调与最终验证 - -**Files:** -- Modify: `/Users/zcc/MyCTMS/rd-monitor/README.md` - -**Step 1: Write the failing test** -- 先运行端到端 smoke(未配置好前应失败)。 - -**Step 2: Run test to verify it fails** -- Run: `docker compose up --build -d && curl -f http://localhost:8010/healthz` -- Expected: 初次 FAIL 或服务未就绪。 - -**Step 3: Write minimal implementation** -- 修正配置/环境变量/文档。 - -**Step 4: Run test to verify it passes** -- Run: `docker compose up --build -d` -- Run: `curl -f http://localhost:8010/healthz` -- Run: `cd backend && pytest -q` -- Run: `cd frontend && npm run build` -- Expected: 全部 PASS。 - -**Step 5: Commit** -- `git commit -m "docs: finalize rd-monitor setup and verification"` diff --git a/docs/plans/2026-03-27-production-init-implementation.md b/docs/plans/2026-03-27-production-init-implementation.md index 02233657..fc7a11c1 100644 --- a/docs/plans/2026-03-27-production-init-implementation.md +++ b/docs/plans/2026-03-27-production-init-implementation.md @@ -112,7 +112,7 @@ git commit -m "feat: add production init entrypoint" **Files:** - Modify: `docker-compose.yaml` - Modify: `README.md` -- Modify: `docs/release-checklist.md` +- Modify: `docs/guides/release-checklist.md` - Optionally modify: `database/init.sql` **Step 1: Write failing verification** @@ -136,7 +136,7 @@ Expected: PASS with the new init workflow represented in configuration or docume **Step 5: Commit** ```bash -git add docker-compose.yaml README.md docs/release-checklist.md database/init.sql +git add docker-compose.yaml README.md docs/guides/release-checklist.md database/init.sql git commit -m "docs: define production database init flow" ``` diff --git a/docs/plans/2026-03-30-docs-reorganization-implementation.md b/docs/plans/2026-03-30-docs-reorganization-implementation.md new file mode 100644 index 00000000..57c16d46 --- /dev/null +++ b/docs/plans/2026-03-30-docs-reorganization-implementation.md @@ -0,0 +1,116 @@ +# Docs Reorganization Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** Reorganize `docs/` into stable long-lived sections, remove obsolete files, normalize document headers, and repair repository references. + +**Architecture:** Keep `docs/plans/` as historical implementation records, move active operating material into `docs/guides/`, move review and governance material into `docs/audits/`, keep `docs/postman/` for collection assets, and add `docs/README.md` as the top-level navigation entrypoint. + +**Tech Stack:** Markdown, shell file operations, ripgrep + +--- + +### Task 1: Create the target docs structure + +**Files:** +- Create: `/Users/zcc/MyCTMS/ctms-dev/.worktrees/main/docs/README.md` +- Create: `/Users/zcc/MyCTMS/ctms-dev/.worktrees/main/docs/guides/` +- Create: `/Users/zcc/MyCTMS/ctms-dev/.worktrees/main/docs/audits/` + +**Step 1: Write the failing test** + +Manual expectation: `docs/README.md`, `docs/guides/`, and `docs/audits/` do not yet exist. + +**Step 2: Run test to verify it fails** + +Run: `find docs -maxdepth 1 -type d -o -type f | sort` +Expected: FAIL to show the new structure. + +**Step 3: Write minimal implementation** + +Create the new directories and the docs index file. + +**Step 4: Run test to verify it passes** + +Run: `find docs -maxdepth 2 | sort` +Expected: PASS with `docs/README.md`, `docs/guides`, and `docs/audits`. + +### Task 2: Move active docs into semantic directories + +**Files:** +- Modify: `/Users/zcc/MyCTMS/ctms-dev/.worktrees/main/docs/guides/release-checklist.md` +- Modify: `/Users/zcc/MyCTMS/ctms-dev/.worktrees/main/docs/guides/setup-config-api.md` +- Modify: `/Users/zcc/MyCTMS/ctms-dev/.worktrees/main/docs/audits/auth-session-acceptance.md` +- Modify: `/Users/zcc/MyCTMS/ctms-dev/.worktrees/main/docs/audits/setup-config-code-audit.md` +- Modify: `/Users/zcc/MyCTMS/ctms-dev/.worktrees/main/docs/audits/storage-persistence-audit.md` +- Modify: `/Users/zcc/MyCTMS/ctms-dev/.worktrees/main/docs/audits/storage-persistence-governance.md` +- Modify: `/Users/zcc/MyCTMS/ctms-dev/.worktrees/main/docs/audits/enterprise-ui-acceptance-checklist.md` + +**Step 1: Write the failing test** + +Manual expectation: the documents still live in mixed root paths. + +**Step 2: Run test to verify it fails** + +Run: `find docs -maxdepth 2 -type f | sort` +Expected: FAIL to show the desired grouping. + +**Step 3: Write minimal implementation** + +Move each document into `guides/` or `audits/`. + +**Step 4: Run test to verify it passes** + +Run: `find docs -maxdepth 2 -type f | sort` +Expected: PASS with the regrouped files. + +### Task 3: Remove obsolete docs and local artifacts + +**Files:** +- Delete: `/Users/zcc/MyCTMS/ctms-dev/.worktrees/main/docs/workbench-ui-optimization.md` +- Delete: `/Users/zcc/MyCTMS/ctms-dev/.worktrees/main/docs/plans/2026-03-05-rd-monitor-design.md` +- Delete: `/Users/zcc/MyCTMS/ctms-dev/.worktrees/main/docs/plans/2026-03-05-rd-monitor-implementation.md` + +**Step 1: Write the failing test** + +Manual expectation: the obsolete files still appear in `git status`. + +**Step 2: Run test to verify it fails** + +Run: `git status --short docs` +Expected: FAIL because the obsolete docs are still present in tracked history. + +**Step 3: Write minimal implementation** + +Remove the obsolete files from the working tree and index. + +**Step 4: Run test to verify it passes** + +Run: `find docs -maxdepth 2 -type f | sort` +Expected: PASS without the removed files. + +### Task 4: Normalize titles, metadata, and references + +**Files:** +- Modify: `/Users/zcc/MyCTMS/ctms-dev/.worktrees/main/docs/README.md` +- Modify: `/Users/zcc/MyCTMS/ctms-dev/.worktrees/main/README.md` +- Modify: `/Users/zcc/MyCTMS/ctms-dev/.worktrees/main/.gitignore` +- Modify: moved docs under `docs/guides/` and `docs/audits/` + +**Step 1: Write the failing test** + +Manual expectation: old paths are still referenced and several docs use inconsistent headings. + +**Step 2: Run test to verify it fails** + +Run: `rg -n "docs/(release-checklist|setup-config-api|storage-persistence|auth-session-acceptance|ui/enterprise-ui-acceptance-checklist)" README.md docs backend frontend .github` +Expected: FAIL with old path references. + +**Step 3: Write minimal implementation** + +Update headings, add concise metadata blocks where useful, write `docs/README.md`, and fix references to the new paths. + +**Step 4: Run test to verify it passes** + +Run: `rg -n "docs/(release-checklist|setup-config-api|storage-persistence|auth-session-acceptance|ui/enterprise-ui-acceptance-checklist)" README.md docs backend frontend .github` +Expected: PASS with only the new organized paths. diff --git a/docs/postman/local.postman_environment.json b/docs/postman/local.postman_environment.example.json similarity index 79% rename from docs/postman/local.postman_environment.json rename to docs/postman/local.postman_environment.example.json index 1d109194..89b3263c 100644 --- a/docs/postman/local.postman_environment.json +++ b/docs/postman/local.postman_environment.example.json @@ -1,10 +1,9 @@ { - "id": "9f9bb57a-6de8-4e31-a7a4-e0c0e7c0d119", - "name": "CTMS Local", + "name": "CTMS Local Example", "values": [ { "key": "base_url", "value": "http://localhost", "type": "default", "enabled": true }, { "key": "email", "value": "admin@example.com", "type": "default", "enabled": true }, - { "key": "password", "value": "admin123", "type": "secret", "enabled": true }, + { "key": "password", "value": "admin123", "type": "default", "enabled": true }, { "key": "study_id", "value": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "type": "default", "enabled": true }, { "key": "token", "value": "", "type": "default", "enabled": true }, { "key": "setup_version", "value": "1", "type": "default", "enabled": true }, @@ -18,7 +17,5 @@ "enabled": true } ], - "_postman_variable_scope": "environment", - "_postman_exported_at": "2026-02-09T00:00:00.000Z", - "_postman_exported_using": "Codex" + "_postman_variable_scope": "environment" } diff --git a/docs/workbench-ui-optimization.md b/docs/workbench-ui-optimization.md deleted file mode 100644 index b72ef215..00000000 --- a/docs/workbench-ui-optimization.md +++ /dev/null @@ -1,262 +0,0 @@ -# 工作台UI优化文档 - -## 📅 优化日期 -2026-01-20 - -## 🎯 优化目标 -提升工作台界面的视觉吸引力和用户体验,使其更加现代化、专业且富有活力,同时保持后端功能不变。 - -## ✨ 主要优化内容 - -### 1. 头部区域全面升级 - -#### 优化前 -- 简单的白色背景 -- 基础的文字标题 -- 单色角色徽章 - -#### 优化后 -- **渐变背景**:采用紫色渐变(#667eea → #764ba2),增强品牌感 -- **装饰图案**:添加SVG网格图案背景,增加层次感 -- **视觉效果**: - - 标题字体更大(32px),加粗(800),白色文字带阴影 - - 副标题使用半透明白色 - - 玻璃态角色徽章(backdrop-filter: blur) - - 整体阴影提升(0 8px 32px) -- **动画入场**:添加fadeIn动画,页面加载更流畅 - -```css -.workbench-header { - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - border-radius: 16px; - box-shadow: 0 8px 32px rgba(102, 126, 234, 0.2); -} -``` - -### 2. 卡片组件视觉增强 - -#### SectionCard (任务列表卡片) - -**新增功能图标**: -- 今日待办:日历图标 📅 -- 已逾期事项:警告图标 ⚠️ -- 需要处理的事项:文档图标 📄 -- 图标采用渐变背景,圆角设计,带动态旋转效果 - -**样式优化**: -- 卡片背景渐变(#ffffff → #fafcff) -- 边框透明度处理(rgba(102, 126, 234, 0.12)) -- Hover效果:上浮2px + 阴影加深 -- 圆角增大至16px - -**列表项交互**: -- 左侧渐变色条指示器(hover时从0变为4px) -- 背景渐变hover效果 -- 标题颜色变化(hover时变为#667eea) -- 整体右移6px的动画 -- 状态标签缩放效果(scale 1.05) - -```css -.list-item:hover::before { - width: 4px; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -} -``` - -### 3. 快捷入口美化 - -#### 优化前 -- 小图标(40px) -- 单色边框 -- 简单hover效果 - -#### 优化后 -- **卡片整体**: - - 渐变背景(#ffffff → #f8f9ff) - - 悬浮提升效果 - - 头部渐变装饰 - -- **图标设计**: - - 尺寸增大至56px - - 紫色渐变背景 - - 白色图标(26px) - - 光晕阴影效果 - - 边框高光(::before伪元素) - -- **交互动效**: - - Hover时图标旋转5度并放大 - - 背景色反转(白底紫字) - - 整体卡片上浮4px并缩放1.02倍 - - 文字变白色并放大1.05倍 - - 缓动函数:cubic-bezier(0.22, 1, 0.36, 1) - -```css -.quick-item:hover .quick-icon-box { - background: #ffffff; - color: #667eea; - transform: scale(1.1) rotate(5deg); -} -``` - -### 4. 通知卡片精细化 - -#### 样式升级 -- 渐变背景(#ffffff → #fef7ff,偏粉紫色) -- 标题渐变文字效果 -- 分隔线设计(底部2px边框) -- 卡片整体hover上浮 - -#### 通知项优化 -- 白色背景 + 淡紫色边框 -- Hover效果: - - 渐变背景色 - - 右移4px - - 边框颜色加深 - - 阴影出现 -- 版本号徽章:渐变背景 + 白色文字 + 阴影 - -```css -.notification-version { - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - color: #ffffff; - box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3); -} -``` - -### 5. 状态标签优化 - -#### 差异化设计 -- **危险状态**(逾期): - - 渐变背景:rgba(194, 75, 75, 0.12) → rgba(194, 75, 75, 0.08) - - 红色文字 + 红色边框 - -- **信息状态**(普通): - - 渐变背景:rgba(100, 116, 139, 0.12) → rgba(100, 116, 139, 0.08) - - 灰蓝色文字 + 灰蓝色边框 - -- Hover时标签缩放1.05倍并添加阴影 - -### 6. 动画与过渡 - -#### 全局动画 -- 页面入场fadeIn动画(0.5s) -- 所有交互元素使用cubic-bezier缓动 -- 过渡时间统一为0.3s或0.4s - -#### 微交互 -- 按钮hover时右移(transform: translateX(4px)) -- 卡片hover时上浮(transform: translateY(-2px)) -- 图标旋转和缩放组合 - -## 🎨 设计系统 - -### 颜色方案 -```css -/* 主渐变色 */ ---gradient-primary: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - -/* 卡片背景 */ ---card-bg-1: linear-gradient(135deg, #ffffff 0%, #fafcff 100%); ---card-bg-2: linear-gradient(135deg, #ffffff 0%, #f8f9ff 100%); ---card-bg-3: linear-gradient(135deg, #ffffff 0%, #fef7ff 100%); - -/* 透明边框 */ ---border-primary: rgba(102, 126, 234, 0.12); ---border-primary-hover: rgba(102, 126, 234, 0.2); -``` - -### 圆角规范 -- 小元素:10px - 12px -- 卡片:16px -- 徽章/标签:12px(pill shape) - -### 阴影层级 -```css -/* 默认 */ ---shadow-card: 0 4px 20px rgba(0, 0, 0, 0.04); - -/* Hover */ ---shadow-card-hover: 0 8px 30px rgba(0, 0, 0, 0.08); - -/* 图标 */ ---shadow-icon: 0 8px 20px rgba(102, 126, 234, 0.3); -``` - -## 📊 优化效果对比 - -### 视觉层次 -- ✅ 头部从单调变为吸引眼球的焦点 -- ✅ 卡片从扁平变为有层次感的立体设计 -- ✅ 图标从普通变为品牌化的视觉元素 - -### 用户体验 -- ✅ 所有交互元素都有明确的视觉反馈 -- ✅ Hover效果统一且流畅 -- ✅ 功能区域通过图标和颜色快速识别 - -### 品牌感 -- ✅ 统一的紫色渐变主题贯穿始终 -- ✅ 现代化的glassmorphism和渐变设计 -- ✅ 从B端管理系统升级为专业且有设计感的应用 - -## 🔧 技术实现 - -### 关键技术 -1. **CSS渐变**:linear-gradient实现丰富的色彩层次 -2. **Backdrop Filter**:玻璃态效果(需浏览器支持) -3. **CSS Transform**:实现流畅的动画效果 -4. **Cubic-bezier**:自然的缓动曲线 -5. **伪元素**:::before实现装饰性元素 - -### 兼容性 -- 主要浏览器现代版本均支持 -- backdrop-filter在Safari和Chrome中效果最佳 -- 渐变文字需要-webkit前缀 - -### 性能优化 -- 使用transform代替position动画(GPU加速) -- 合理使用will-change(仅在必要时) -- 阴影使用透明度而非模糊半径过大的值 - -## 📁 修改文件清单 - -1. **MyWorkbench.vue** - - 优化整体布局和间距 - - 添加头部渐变背景 - - 美化快捷入口和通知卡片 - - 统一样式主题 - -2. **SectionCard.vue** - - 添加功能图标 - - 优化卡片样式和hover效果 - - 增强列表项交互 - - 差异化状态标签 - -## 🎯 后续优化建议 - -1. **响应式优化**:针对平板和手机端进一步优化布局 -2. **深色模式**:添加dark mode支持 -3. **骨架屏**:优化loading状态的显示 -4. **空状态**:美化空数据时的占位图 -5. **数据可视化**:添加统计图表展示项目进度 - -## ✅ 验证清单 - -- [x] 头部渐变背景正常显示 -- [x] 卡片图标正确显示 -- [x] 快捷入口hover动画流畅 -- [x] 列表项交互反馈明确 -- [x] 通知卡片样式优化 -- [x] 所有动画性能良好 -- [x] 响应式布局正常工作 -- [x] 后端功能完全不受影响 - -## 🌟 总结 - -此次UI优化在**不改动后端代码**的前提下,通过纯前端样式优化,将工作台从普通的管理界面提升为具有现代感和专业度的高品质应用界面。 - -主要成就: -- 🎨 视觉吸引力提升80%+ -- ⚡ 用户体验优化显著 -- 🏷️ 品牌识别度大幅增强 -- 💯 保持100%功能完整性 diff --git a/frontend/.env b/frontend/.env deleted file mode 100644 index 46e4b092..00000000 --- a/frontend/.env +++ /dev/null @@ -1,6 +0,0 @@ -# 递交日期 -> 受理日期 超期(月) -VITE_STARTUP_SUBMIT_ACCEPT_TIMEOUT_MONTHS=1 -# 受理日期 -> 批准日期 超期(月) -VITE_STARTUP_ACCEPT_APPROVAL_TIMEOUT_MONTHS=1 -# 启用项目概览API -VITE_USE_OVERVIEW_API=true diff --git a/frontend/.env.example b/frontend/.env.example new file mode 100644 index 00000000..73a9682d --- /dev/null +++ b/frontend/.env.example @@ -0,0 +1,5 @@ +# Frontend feature flags and timeline overrides +VITE_STARTUP_SUBMIT_ACCEPT_TIMEOUT_MONTHS=3 +VITE_STARTUP_ACCEPT_TIMEOUT_MONTHS=3 +VITE_STARTUP_ACCEPT_APPROVAL_TIMEOUT_MONTHS=6 +VITE_USE_OVERVIEW_API=false diff --git a/test-results/.last-run.json b/test-results/.last-run.json deleted file mode 100644 index 5fca3f84..00000000 --- a/test-results/.last-run.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "status": "failed", - "failedTests": [] -} \ No newline at end of file From 956c47218e1cfeea87bbae0020687289967b664f Mon Sep 17 00:00:00 2001 From: Cheng Zhou Date: Mon, 30 Mar 2026 20:15:06 +0800 Subject: [PATCH 2/2] feat: automate tencent private registry publishing --- .github/workflows/publish-images.yml | 83 ++++++++++ README.md | 8 + docker-compose.yaml | 3 + docs/guides/release-checklist.md | 8 + ...26-03-30-tcloud-private-registry-design.md | 82 ++++++++++ .../2026-03-30-tcloud-private-registry.md | 146 ++++++++++++++++++ scripts/build-and-push-registry.sh | 66 ++++++++ 7 files changed, 396 insertions(+) create mode 100644 .github/workflows/publish-images.yml create mode 100644 docs/plans/2026-03-30-tcloud-private-registry-design.md create mode 100644 docs/plans/2026-03-30-tcloud-private-registry.md create mode 100644 scripts/build-and-push-registry.sh diff --git a/.github/workflows/publish-images.yml b/.github/workflows/publish-images.yml new file mode 100644 index 00000000..1eb3186e --- /dev/null +++ b/.github/workflows/publish-images.yml @@ -0,0 +1,83 @@ +name: Publish Images + +on: + push: + branches: + - dev + - release + - release/** + - main + +permissions: + contents: read + +concurrency: + group: publish-images-${{ github.ref }} + cancel-in-progress: true + +jobs: + publish: + runs-on: ubuntu-latest + env: + REMOTE_BASE_DIR: /opt/ctms-build + SSH_KEY_PATH: /tmp/tcloud_ci_key + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Prepare remote path metadata + id: meta + shell: bash + run: | + echo "repo_name=${GITHUB_REPOSITORY#*/}" >> "$GITHUB_OUTPUT" + echo "branch_name=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" + echo "short_sha=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT" + + - name: Install SSH key + shell: bash + run: | + printf '%s\n' '${{ secrets.TCLOUD_SSH_KEY }}' > "${{ env.SSH_KEY_PATH }}" + chmod 600 "${{ env.SSH_KEY_PATH }}" + + - name: Sync repository to Tencent Cloud host + shell: bash + env: + TCLOUD_HOST: ${{ secrets.TCLOUD_HOST }} + TCLOUD_PORT: ${{ secrets.TCLOUD_PORT }} + TCLOUD_USER: ${{ secrets.TCLOUD_USER }} + REMOTE_REPO_DIR: ${{ env.REMOTE_BASE_DIR }}/${{ steps.meta.outputs.repo_name }} + run: | + ssh -i "${{ env.SSH_KEY_PATH }}" -p "${TCLOUD_PORT}" -o StrictHostKeyChecking=no "${TCLOUD_USER}@${TCLOUD_HOST}" \ + "mkdir -p '${REMOTE_REPO_DIR}' && find '${REMOTE_REPO_DIR}' -mindepth 1 -maxdepth 1 -exec rm -rf {} +" + tar --exclude=.git -cf - . | \ + ssh -i "${{ env.SSH_KEY_PATH }}" -p "${TCLOUD_PORT}" -o StrictHostKeyChecking=no "${TCLOUD_USER}@${TCLOUD_HOST}" \ + "tar -xf - -C '${REMOTE_REPO_DIR}'" + + - name: Build and push images on Tencent Cloud host + shell: bash + env: + TCLOUD_HOST: ${{ secrets.TCLOUD_HOST }} + TCLOUD_PORT: ${{ secrets.TCLOUD_PORT }} + TCLOUD_USER: ${{ secrets.TCLOUD_USER }} + BRANCH_NAME: ${{ steps.meta.outputs.branch_name }} + COMMIT_SHA: ${{ github.sha }} + REGISTRY_HOST: ${{ secrets.REGISTRY_HOST }} + REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }} + REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} + REMOTE_REPO_DIR: ${{ env.REMOTE_BASE_DIR }}/${{ steps.meta.outputs.repo_name }} + run: | + BRANCH_NAME_B64="$(printf '%s' "${BRANCH_NAME}" | base64)" + COMMIT_SHA_B64="$(printf '%s' "${COMMIT_SHA}" | base64)" + REGISTRY_HOST_B64="$(printf '%s' "${REGISTRY_HOST}" | base64)" + REGISTRY_USERNAME_B64="$(printf '%s' "${REGISTRY_USERNAME}" | base64)" + REGISTRY_PASSWORD_B64="$(printf '%s' "${REGISTRY_PASSWORD}" | base64)" + ssh -i "${{ env.SSH_KEY_PATH }}" -p "${TCLOUD_PORT}" -o StrictHostKeyChecking=no "${TCLOUD_USER}@${TCLOUD_HOST}" " + cd '${REMOTE_REPO_DIR}' + chmod +x scripts/build-and-push-registry.sh + export BRANCH_NAME=\$(printf '%s' '${BRANCH_NAME_B64}' | base64 -d) + export COMMIT_SHA=\$(printf '%s' '${COMMIT_SHA_B64}' | base64 -d) + export REGISTRY_HOST=\$(printf '%s' '${REGISTRY_HOST_B64}' | base64 -d) + export REGISTRY_USERNAME=\$(printf '%s' '${REGISTRY_USERNAME_B64}' | base64 -d) + export REGISTRY_PASSWORD=\$(printf '%s' '${REGISTRY_PASSWORD_B64}' | base64 -d) + ./scripts/build-and-push-registry.sh + " diff --git a/README.md b/README.md index fe785080..b8ecf344 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,14 @@ - `curl -i http://127.0.0.1/` - `curl -i http://127.0.0.1/health` +## 腾讯云私有镜像仓库 +- GitHub Actions 会在推送到 `dev`、`release`、`release/*` 和 `main` 时,通过 SSH 连接腾讯云服务器,在服务器本机完成 `backend` 和 `nginx` 镜像的构建与推送。 +- 私有仓库地址默认使用 `${REGISTRY_HOST}`,仓库命名为 `${REGISTRY_HOST}/ctms/ctms-backend` 和 `${REGISTRY_HOST}/ctms/ctms-nginx`。 +- `dev` 分支发布 `dev-latest` 和 `dev-`,`release` 分支发布 `rc-release` 和 `rc-`,`release/*` 分支发布 `rc-` 和 `rc-`,`main` 分支发布 `latest` 和 `sha-`。 +- 部署机需要先 `docker login :5000`,并使用私有仓库的 `htpasswd` 账号密码完成认证。 +- `backend-init` 复用 `BACKEND_IMAGE`,所以生产机可在设置 `REGISTRY_HOST`,或直接指定 `BACKEND_IMAGE` 和 `NGINX_IMAGE` 后执行 `docker compose pull && docker compose run --rm backend-init && docker compose up -d`。 +- 本地开发仍可继续使用 `docker compose up -d --build` 走本地构建。 + ## 账号与注册 - 初始化管理员:`admin@huapont.cn / admin123`(通过生产初始化命令显式创建) - 自助注册:前端 `/register` 提交邮箱、密码、姓名、角色(CRA/PV/IMP/PM)、部门,状态为 PENDING。 diff --git a/docker-compose.yaml b/docker-compose.yaml index a37303b9..0cc84fcd 100755 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -21,6 +21,7 @@ services: - ctms_net backend: + image: ${BACKEND_IMAGE:-${REGISTRY_HOST:-127.0.0.1:5000}/ctms/ctms-backend:latest} build: context: ./backend dockerfile: Dockerfile @@ -37,6 +38,7 @@ services: - ctms_net backend-init: + image: ${BACKEND_IMAGE:-${REGISTRY_HOST:-127.0.0.1:5000}/ctms/ctms-backend:latest} build: context: ./backend dockerfile: Dockerfile @@ -51,6 +53,7 @@ services: - ctms_net nginx: + image: ${NGINX_IMAGE:-${REGISTRY_HOST:-127.0.0.1:5000}/ctms/ctms-nginx:latest} build: context: . dockerfile: nginx/Dockerfile diff --git a/docs/guides/release-checklist.md b/docs/guides/release-checklist.md index 85b71223..a98a5efa 100644 --- a/docs/guides/release-checklist.md +++ b/docs/guides/release-checklist.md @@ -9,6 +9,14 @@ - [ ] `cd backend && python3 -m compileall app scripts` - [ ] `cd frontend && npm run build` +## 1.1 腾讯云私有镜像校验 +- [ ] `dev` 推送后,`:5000/ctms/ctms-backend` 和 `ctms-nginx` 的 `dev-latest` / `dev-` 标签已出现在私有仓库 +- [ ] `release` 推送后,`:5000/ctms/ctms-backend` 和 `ctms-nginx` 的 `rc-release` / `rc-` 标签已出现在私有仓库 +- [ ] `release/*` 推送后,`:5000/ctms/ctms-backend` 和 `ctms-nginx` 的 `rc-` / `rc-` 标签已出现在私有仓库 +- [ ] `main` 推送后,`:5000/ctms/ctms-backend` 和 `ctms-nginx` 的 `latest` / `sha-` 标签已出现在私有仓库 +- [ ] GitHub Actions 已成功 SSH 登录腾讯云服务器并执行远程构建脚本 +- [ ] 部署机已执行 `docker login :5000`,且使用的是私有仓库 `htpasswd` 账号密码 + ## 2. 接口与权限回归 - [ ] ADMIN 账号可 `GET/PUT/PUBLISH/IMPORT-EXCEL/EXPORT-EXCEL` - [ ] PM 账号可 `GET/PUT/PUBLISH/IMPORT-EXCEL/EXPORT-EXCEL` diff --git a/docs/plans/2026-03-30-tcloud-private-registry-design.md b/docs/plans/2026-03-30-tcloud-private-registry-design.md new file mode 100644 index 00000000..8509bfc1 --- /dev/null +++ b/docs/plans/2026-03-30-tcloud-private-registry-design.md @@ -0,0 +1,82 @@ +# Tencent Cloud Private Registry Design + +**Goal:** Add CI that automatically builds and pushes private `backend` and `nginx` images to a self-hosted Docker Registry running on a Tencent Cloud CVM, with `dev` publishing test tags, `release` and `release/*` publishing release-candidate tags, and `main` publishing formal tags. + +**Decisions** +- Publish only two runtime images: `/ctms/ctms-backend` and `/ctms/ctms-nginx`. +- Keep the private registry on the Tencent Cloud CVM as a self-hosted `registry:2` instance protected by `htpasswd`. +- Trigger automation on pushes to `dev`, `release`, `release/*`, and `main`. +- Use GitHub Actions only as the orchestrator. Actual Docker build and push happen on the Tencent Cloud server over SSH. +- Keep `docker-compose.yaml` compatible with both local `build` workflows and private registry pulls. + +**Approaches Considered** +- Recommended: GitHub Actions connects to the Tencent Cloud server over SSH and runs a server-local build-and-push script. This avoids GitHub-hosted runner limitations around insecure or self-signed private registries and keeps registry access local to the server. +- Alternative: GitHub Actions builds and pushes directly to `:5000`. This is simpler on paper but is fragile when the registry is exposed only as an IP endpoint and may use insecure or non-public TLS. +- Alternative: move first to a domain-backed HTTPS registry and then push directly from GitHub Actions. This is the clean long-term path but adds infrastructure work that is not required for the current goal. + +**Architecture** +- A new GitHub Actions workflow triggers on pushes to `dev`, `release`, `release/*`, and `main`. +- The workflow authenticates to the Tencent Cloud server using SSH credentials stored in GitHub Secrets. +- The workflow syncs the repository contents to a fixed build directory such as `/opt/ctms-build/`. +- A server-local script logs in to the private registry, builds `backend` and `nginx`, applies branch-specific tags, and pushes the images to the registry. + +**Registry Naming** +- Backend image: `/ctms/ctms-backend` +- Nginx image: `/ctms/ctms-nginx` +- `frontend` is intentionally not published because the current runtime topology already builds the frontend assets into the `nginx` image. + +**Tagging Strategy** +- `dev` branch pushes publish: + - `/ctms/ctms-backend:dev-latest` + - `/ctms/ctms-backend:dev-` + - `/ctms/ctms-nginx:dev-latest` + - `/ctms/ctms-nginx:dev-` +- `release` branch pushes publish: + - `/ctms/ctms-backend:rc-release` + - `/ctms/ctms-backend:rc-` + - `/ctms/ctms-nginx:rc-release` + - `/ctms/ctms-nginx:rc-` +- `release/*` branch pushes publish: + - `/ctms/ctms-backend:rc-` + - `/ctms/ctms-backend:rc-` + - `/ctms/ctms-nginx:rc-` + - `/ctms/ctms-nginx:rc-` +- `main` branch pushes publish: + - `/ctms/ctms-backend:latest` + - `/ctms/ctms-backend:sha-` + - `/ctms/ctms-nginx:latest` + - `/ctms/ctms-nginx:sha-` + +**Server Requirements** +- Docker installed on the Tencent Cloud server. +- A private `registry:2` instance listening on `:5000`. +- `htpasswd` authentication configured for the registry. +- SSH access from GitHub Actions to the server. +- A writable build directory such as `/opt/ctms-build`. + +**GitHub Secrets** +- `TCLOUD_HOST` +- `TCLOUD_PORT` +- `TCLOUD_USER` +- `TCLOUD_SSH_KEY` +- `REGISTRY_HOST` +- `REGISTRY_USERNAME` +- `REGISTRY_PASSWORD` + +**Compose Integration** +- `docker-compose.yaml` should define `image:` for `backend`, `backend-init`, and `nginx`, with defaults based on private registry variables such as `REGISTRY_HOST`. +- Existing `build:` blocks stay in place so local `docker compose up -d --build` continues to work. +- Deployment hosts can export `REGISTRY_HOST`, then run `docker login`, `docker compose pull`, `docker compose run --rm backend-init`, and `docker compose up -d`. + +**Operational Notes** +- This design assumes the server-local script runs on the same machine that can log in to the private registry reliably. +- The GitHub workflow should not embed long shell logic inline; the repository should own a script under `scripts/` so the build logic stays versioned and testable. +- Direct verification of actual image publication depends on GitHub Actions reaching the Tencent Cloud server and cannot be proven locally without those secrets and network access. + +**Verification** +- Push to `dev` and confirm both images appear with `dev-latest` and `dev-`. +- Push to `release` and confirm both images appear with `rc-release` and `rc-`. +- Push to `release/*` and confirm both images appear with `rc-` and `rc-`. +- Push to `main` and confirm both images appear with `latest` and `sha-`. +- Run `docker compose config` after compose changes and confirm the private registry defaults render correctly. +- Parse the workflow YAML successfully and inspect the remote build script for the expected tag logic and registry login behavior. diff --git a/docs/plans/2026-03-30-tcloud-private-registry.md b/docs/plans/2026-03-30-tcloud-private-registry.md new file mode 100644 index 00000000..55a063c2 --- /dev/null +++ b/docs/plans/2026-03-30-tcloud-private-registry.md @@ -0,0 +1,146 @@ +# Tencent Cloud Private Registry Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** Add CI that triggers remote builds on a Tencent Cloud CVM and pushes private `backend` and `nginx` images into a self-hosted Docker Registry protected by `htpasswd`, for `dev`, `release`, `release/*`, and `main`. + +**Architecture:** GitHub Actions runs on pushes to `dev`, `release`, `release/*`, and `main`, connects to the Tencent Cloud server over SSH, syncs the repository into a fixed build directory, and invokes a repository-owned shell script that logs in to the private registry, builds the images locally on the server, tags them according to branch, and pushes them. + +**Tech Stack:** GitHub Actions, SSH, Docker, self-hosted `registry:2`, Docker Compose, FastAPI, Nginx + +--- + +### Task 1: Replace GHCR Workflow with Tencent Registry Publish Workflow + +**Files:** +- Modify: `.github/workflows/publish-images.yml` + +**Step 1: Define push triggers and remote execution secrets** + +Ensure the workflow triggers on pushes to `dev`, `release`, `release/*`, and `main`, and uses repository secrets for SSH host, port, user, SSH key, registry host, registry username, and registry password. + +**Step 2: Sync repository content to the Tencent Cloud server** + +Use an SSH-capable action or shell step to create the remote build directory and copy the current repository contents into `/opt/ctms-build/`. + +**Step 3: Invoke the remote publish script** + +Run the repository-owned remote script over SSH with environment values for: +- branch name +- commit SHA +- registry host +- registry credentials + +**Step 4: Verify workflow structure** + +Run: `ruby -e 'require "yaml"; YAML.load_file(".github/workflows/publish-images.yml")'` +Expected: PASS + +### Task 2: Add Remote Build-And-Push Script + +**Files:** +- Create: `scripts/build-and-push-registry.sh` + +**Step 1: Implement branch-aware tag logic** + +For `dev`, compute: +- `dev-latest` +- `dev-` + +For `release`, compute: +- `rc-release` +- `rc-` + +For `release/*`, compute: +- `rc-` +- `rc-` + +For `main`, compute: +- `latest` +- `sha-` + +Fail fast for unsupported branches. + +**Step 2: Implement registry login and image builds** + +Log in to `${REGISTRY_HOST}` using the supplied username and password, then build: +- `${REGISTRY_HOST}/ctms/ctms-backend` +- `${REGISTRY_HOST}/ctms/ctms-nginx` + +**Step 3: Push both tags for both images** + +Push every computed tag explicitly so the branch and immutable tags are both published. + +**Step 4: Verify script syntax** + +Run: `bash -n scripts/build-and-push-registry.sh` +Expected: PASS + +### Task 3: Point Compose Defaults at the Private Registry + +**Files:** +- Modify: `docker-compose.yaml` + +**Step 1: Replace GHCR defaults with private registry defaults** + +Set: +- `backend.image` to `${BACKEND_IMAGE:-${REGISTRY_HOST:-127.0.0.1:5000}/ctms/ctms-backend:latest}` +- `backend-init.image` to `${BACKEND_IMAGE:-${REGISTRY_HOST:-127.0.0.1:5000}/ctms/ctms-backend:latest}` +- `nginx.image` to `${NGINX_IMAGE:-${REGISTRY_HOST:-127.0.0.1:5000}/ctms/ctms-nginx:latest}` + +Keep the current `build:` blocks intact. + +**Step 2: Verify rendered compose** + +Run: `docker compose config` +Expected: PASS with private registry image defaults rendered. + +### Task 4: Update Deployment Documentation + +**Files:** +- Modify: `README.md` +- Modify: `docs/guides/release-checklist.md` + +**Step 1: Document the Tencent registry flow** + +Explain that GitHub Actions triggers remote builds on the Tencent Cloud server and publishes to the private registry at `:5000`. + +**Step 2: Document deployment commands** + +Show that deployment hosts must run: +- `docker login :5000` +- `docker compose pull` +- `docker compose run --rm backend-init` +- `docker compose up -d` + +**Step 3: Update release checklist** + +Add checks for remote publish success on `dev`, `release`, `release/*`, and `main`, and for deployment-host registry authentication. + +### Task 5: End-To-End Local Verification + +**Files:** +- Verify only + +**Step 1: Parse the workflow YAML** + +Run: `ruby -e 'require "yaml"; YAML.load_file(".github/workflows/publish-images.yml")'` +Expected: PASS + +**Step 2: Verify script syntax** + +Run: `bash -n scripts/build-and-push-registry.sh` +Expected: PASS + +**Step 3: Render compose** + +Run: `docker compose config` +Expected: PASS + +**Step 4: Inspect documentation** + +Run: `sed -n '1,120p' README.md` +Expected: PASS with Tencent private registry deployment steps present. + +Run: `sed -n '1,120p' docs/guides/release-checklist.md` +Expected: PASS with private registry release verification present. diff --git a/scripts/build-and-push-registry.sh b/scripts/build-and-push-registry.sh new file mode 100644 index 00000000..b38f945d --- /dev/null +++ b/scripts/build-and-push-registry.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash + +set -euo pipefail + +required_vars=( + BRANCH_NAME + COMMIT_SHA + REGISTRY_HOST + REGISTRY_USERNAME + REGISTRY_PASSWORD +) + +for var_name in "${required_vars[@]}"; do + if [[ -z "${!var_name:-}" ]]; then + echo "Missing required environment variable: ${var_name}" >&2 + exit 1 + fi +done + +short_sha="${COMMIT_SHA:0:7}" + +case "${BRANCH_NAME}" in + dev) + mutable_tag="dev-latest" + immutable_tag="dev-${short_sha}" + ;; + release) + mutable_tag="rc-release" + immutable_tag="rc-${short_sha}" + ;; + release/*) + release_name="${BRANCH_NAME#release/}" + release_slug="${release_name//\//-}" + mutable_tag="rc-${release_slug}" + immutable_tag="rc-${short_sha}" + ;; + main) + mutable_tag="latest" + immutable_tag="sha-${short_sha}" + ;; + *) + echo "Unsupported branch for publishing: ${BRANCH_NAME}" >&2 + exit 1 + ;; +esac + +backend_image="${REGISTRY_HOST}/ctms/ctms-backend" +nginx_image="${REGISTRY_HOST}/ctms/ctms-nginx" + +echo "${REGISTRY_PASSWORD}" | docker login "${REGISTRY_HOST}" --username "${REGISTRY_USERNAME}" --password-stdin + +docker build \ + -t "${backend_image}:${mutable_tag}" \ + -t "${backend_image}:${immutable_tag}" \ + ./backend + +docker build \ + -t "${nginx_image}:${mutable_tag}" \ + -t "${nginx_image}:${immutable_tag}" \ + -f ./nginx/Dockerfile \ + . + +docker push "${backend_image}:${mutable_tag}" +docker push "${backend_image}:${immutable_tag}" +docker push "${nginx_image}:${mutable_tag}" +docker push "${nginx_image}:${immutable_tag}"