# taskflow **Repository Path**: jiangzhijie628/taskflow ## Basic Information - **Project Name**: taskflow - **Description**: 学习测试bmad - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-06 - **Last Updated**: 2026-05-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Taskflow 本仓库说明以中文编写(不维护 `README.en.md` 等英文镜像)。 单仓双工程:**`backend/`**(Spring Boot 3 + Java 17 + Maven)、**`frontend/`**(Vue 3 + Vite + pnpm)。目录边界与 `_bmad-output/planning-artifacts/architecture.md` 中「Project Structure & Boundaries」一致。 ## 先决条件 | 工具 | 说明 | |------|------| | **JDK 17+** | Spring Boot 3 要求 Java 17。请保证本机默认 `java -version` 为 17+(系统 `PATH` 与/或 `JAVA_HOME` 指向 JDK 17)。Windows 可使用 [Microsoft Build of OpenJDK 17](https://learn.microsoft.com/java/openjdk/download)。 | | **Maven 3.9+** | 用于 `backend` 构建与测试。 | | **Node.js** | 建议使用 **Current LTS**(如 20.x / 22.x);最低参见 `frontend/package.json` 的 `engines`。 | | **pnpm** | 与 `frontend/package.json` 中 `packageManager` 字段一致(当前为 **pnpm 10.x**)。启用 Corepack:`corepack enable`。 | | **MySQL 8** | 本机 **`127.0.0.1:3306`**,库 **`taskflow`**,用户 / 口令见 `backend/src/main/resources/application-dev.yml`(与 `docs/local-setup.md` 初始化示例一致)。 | | **Redis** | 本机 **`127.0.0.1:6379`**,开发约定**无密码**;配置见同上 `application-dev.yml`。 | 启动后端前请已创建数据库并授权(见 **`docs/local-setup.md`**),且 Redis 已监听;否则 Spring Boot 在 **dev** profile 下启动会失败。**库建好后无需手工建业务表**:Flyway 会在首次启动时迁移并创建 `users` / `roles` / `user_roles` 等(Story 1.2)。 在 **Cursor / VS Code** 中打开本仓库时,根目录 **`.vscode/settings.json`** 将 **`maven.terminal.useJavaHome`** 设为 **`false`**:Maven 侧栏与扩展在终端里执行目标时,使用**系统与当前终端**里的 Java(`PATH` / `JAVA_HOME`),而不会改用编辑器里单独配置的 JDK。若你曾在用户级把该项设为 `true`,在本仓库内也会被覆盖。命令行直接执行 `mvn` 时本来就不受此开关影响。 ## 仓库结构(摘要) - `backend/` — 单体后端;包根 `com.taskflow`,四层 `api` / `application` / `domain` / `infrastructure`;`mvn package` 产出可执行 **fat jar**。 - `frontend/` — Vue 工程;`pnpm build` 产出 **`frontend/dist/`**;业务 HTTP 仅通过 `src/api/` 扩展(见架构文档)。 - `docs/` — 本机环境等说明(见 `docs/local-setup.md`)。 ## 后端:构建与运行 若系统默认已是 JDK 17,可在任意终端直接执行下方 `mvn` 行。否则先为**当前会话**指定 JDK 17(将 **``** 换成本机安装根目录)。**Windows** 与 **macOS / Linux** 分别给出片段,避免混用 shell 语法。 **Windows(PowerShell)** ```powershell # 仅当 `java -version` 不是 17 时需要: $env:JAVA_HOME = "" $env:Path = "$env:JAVA_HOME\bin;$env:Path" mvn -f backend/pom.xml test pnpm --dir frontend test mvn -f backend/pom.xml package ``` **macOS / Linux(bash)** ```bash # 仅当默认 java 不是 17 时需要: export JAVA_HOME="" export PATH="$JAVA_HOME/bin:$PATH" mvn -f backend/pom.xml test pnpm --dir frontend test mvn -f backend/pom.xml package ``` - **产物**:`backend/target/` 下的 Spring Boot **fat jar**,文件名形如 `-.jar`,与 `backend/pom.xml` 中 `artifactId`、`version` 一致(修改坐标后文件名随之变化)。 - **运行**:`mvn -f backend/pom.xml spring-boot:run`(Maven 插件已为 `spring-boot:run` 附带 **`dev`** profile;`java -jar` 时请追加 `--spring.profiles.active=dev` 除非你另行配置)。 - **Profile**:默认 `application.yml` 中 `spring.profiles.active=dev`;单元测试使用 **`test`** profile:内嵌 **H2** + Flyway(不连本机 MySQL),**不**启用 Redis(refresh 状态用进程内降级实现)。 - **默认端口**:`8080`。 - **Servlet context-path**:`/api`(与前端 Vite 代理前缀一致;REST 无强制 `/api/v1` 版本前缀,见架构 **API-4B**)。 - **健康检查(经代理访问示例)**:后端启动后,在仅开前端开发服务器时,浏览器访问 `http://localhost:5173/api/actuator/health`(由 Vite 转发至 `http://localhost:8080/api/actuator/health`)。 - **可观测性(Story 1.4)**:**dev** 下控制台为 **JSON 行**日志(`logback-spring.xml`),MDC 含 **`traceId`**(与统一响应体一致);本机 **Prometheus** 抓取 **`/api/actuator/prometheus`** 的示例见 **`docs/monitoring-local.md`**。 ### 统一 JSON 外壳与 traceId(Story 1.3) 业务接口在 **`server.servlet.context-path=/api`** 之下返回 **`{ "code", "message", "data", "traceId" }`**,且 **`code` 与 HTTP 状态码一致**;Actuator **`/api/actuator/**`** 仍为 Spring 原生 JSON,不包此壳。可选透传网关请求头 **`X-Trace-Id`** 或 **`X-Request-Id`**(8–128 字符,`[A-Za-z0-9_-]`)。 后端已启动(**dev**)时,可在终端试: ```bash curl -s "http://localhost:8080/api/v1/demo/ping" curl -s "http://localhost:8080/api/v1/demo/ping" -H "X-Trace-Id: a1b2c3d4-e5f6-7890-abcd-ef1234567890" curl -s -X POST "http://localhost:8080/api/v1/demo/validate" -H "Content-Type: application/json" -d "{}" curl -s "http://localhost:8080/api/v1/demo/not-found" ``` ### JWT 登录与刷新(Story 1.5) - **契约与 Redis 键**:见 **`docs/jwt-session.md`**。 - **本机开发种子用户**(Flyway `V2`,**仅限开发**):用户名 **`devuser`**,密码 **`devpass123`**。生产环境勿依赖该账号。 - **管理员种子**(Flyway `V3`/`V6`,**仅限开发**):用户名 **`devadmin`**,密码与 **`devuser`** 相同(当前均为 **`devpass123`**),具备 **`ROLE_ADMIN`** 与 **`perm:project.manage`**;用于审计管理 API、**`/v1/projects`** 与前端 **`/admin/audit`**、**`/projects`** 烟测。 - **JWT 密钥**:通过环境变量 **`TASKFLOW_JWT_SECRET`** 覆盖(至少 32 字节随机串);示例文件 **`backend/src/main/resources/application-local.yml.example`**。 - **审计表(Story 1.8)**:Flyway 已创建 **`audit_events`**;开发库可抽查最近写入,例如 **`SELECT id, occurred_at, trace_id, action, outcome, actor_user_id, actor_username, resource_type, resource_id, client_ip, user_agent, detail_json FROM audit_events ORDER BY id DESC LIMIT 20;`**(按需增删列,避免 `SELECT *`)。契约见 **`docs/audit-log.md`**。 后端已启动(**dev**,MySQL/Redis 已就绪)时示例: ```bash curl -s -X POST "http://localhost:8080/api/v1/auth/login" -H "Content-Type: application/json" -d "{\"username\":\"devuser\",\"password\":\"devpass123\"}" # 将响应中 data.refreshToken 填入下方 curl -s -X POST "http://localhost:8080/api/v1/auth/refresh" -H "Content-Type: application/json" -d "{\"refreshToken\":\"\"}" # 将 data.accessToken 填入 curl -s "http://localhost:8080/api/v1/demo/me" -H "Authorization: Bearer " # 管理员:将登录用户名换为 devadmin 后,用返回的 access 拉取审计分页(需 ROLE_ADMIN) curl -s "http://localhost:8080/api/v1/admin/audit-events?page=0&size=10" -H "Authorization: Bearer " # Story 2.1 / 2.2 / 2.4:GET 列表任意已登录用户可用;devadmin 为全局列表,devuser 仅见本人参与的项目(须 project_members 有行) curl -s "http://localhost:8080/api/v1/projects?page=0&size=20" -H "Authorization: Bearer " # Story 2.5:项目详情(已登录;范围与列表同源,越权/不存在均为 404) curl -s "http://localhost:8080/api/v1/projects/1" -H "Authorization: Bearer " # Story 2.6:字段变更历史(仅 ROLE_ADMIN,需 devadmin) curl -s "http://localhost:8080/api/v1/projects/1/field-history?page=0&size=20" -H "Authorization: Bearer " # Story 3.1:应收费用条目(已登录;读=成员/全局,写=OWNER/全局;金额 amountMinor 为分;契约见 docs/billing.md) curl -s "http://localhost:8080/api/v1/projects//receivable-lines" -H "Authorization: Bearer " curl -s -X POST "http://localhost:8080/api/v1/projects//receivable-lines" -H "Authorization: Bearer " -H "Content-Type: application/json" -d '{"title":"服务费","amountMinor":9900,"notes":null}' # Story 2.1 / 2.2 写路径(需 devadmin;JWT 含 ROLE_ADMIN 与 perm:project.manage;契约见 docs/projects.md) curl -s -X POST "http://localhost:8080/api/v1/projects" -H "Authorization: Bearer " -H "Content-Type: application/json" -d "{\"name\":\"curl 烟测项目\"}" # 将创建响应 data.id 填入 ;将 GET /v1/demo/me 的 data.userId 填入 curl -s "http://localhost:8080/api/v1/projects//members" -H "Authorization: Bearer " curl -s -X PUT "http://localhost:8080/api/v1/projects//members" -H "Authorization: Bearer " -H "Content-Type: application/json" -d "{\"ownerUserId\":,\"collaboratorUserIds\":[]}" # Story 2.3:进度与计划节点(需已登录;负责人或管理员可写,契约见 docs/projects.md) curl -s -X PATCH "http://localhost:8080/api/v1/projects//progress" -H "Authorization: Bearer " -H "Content-Type: application/json" -d "{\"version\":0,\"workStatus\":\"IN_PROGRESS\",\"startPlannedAt\":null,\"deliveryPlannedAt\":null,\"nextPaymentDueAt\":null}" ``` ## 前端:构建与开发 以下命令在 **POSIX shell(bash / zsh)** 中书写;在 Windows 上可使用 Git Bash、WSL,或在 **PowerShell** 中直接执行相同 `pnpm` 行(需已安装 pnpm 并在 `PATH` 中)。 ```bash pnpm --dir frontend install pnpm --dir frontend build pnpm --dir frontend dev ``` - **开发服务器**:默认 `http://localhost:5173`(以终端输出为准)。 - **单元测试**:`pnpm --dir frontend test`(Vitest,`src/test/` 为测试根目录之一,与架构「Test Organization」一致)。 - **Element Plus**:按需引入(`unplugin-vue-components` + `ElementPlusResolver`),未使用全量 `app.use(ElementPlus)`。 - **可访问性基线与手工抽检**:见 [docs/a11y-baseline.md](docs/a11y-baseline.md)(Story 1.11)。 ### 前端烟测(Story 1.7) 浏览器任选 **Chrome、Edge 或 Safari**。后端 **`mvn -f backend/pom.xml spring-boot:run`(dev)** 与前端 **`pnpm --dir frontend dev`**(默认 **`http://localhost:5173`**)均已启动,且 **`/api`** 代理指向 **`http://localhost:8080`**。 1. 匿名打开 **`http://localhost:5173/`** → 应重定向到 **`/login`**,且 **`redirect`** query 携带原始路径(如 **`redirect=%2F`**)。 2. 在登录页使用种子账号 **`devuser`** / **`devpass123`** 登录 → 进入受保护壳主页 **`/`**,可见 **`GET /v1/demo/me`** 返回的 **用户 ID / 用户名**。 3. 点击壳主页上的 **「刷新」** → 再次请求 **`/v1/demo/me`** 并更新展示。 4. 在开发者工具中删除 **`localStorage`** 的 **`taskflow.accessToken`**(及必要时 **`taskflow.refreshToken`**,键名与 **`docs/jwt-session.md`** 一致),再访问 **`/`** → 应回到 **`/login`**(或先出现 **401** 再被清 token,最终落在登录页)。 5. (可选)已登录时直接访问 **`/login`** → 应回到 **`/`**(或合法 **`redirect`** 内路径)。 **说明**:顶栏 **「登出」** 为仅客户端清理 token 并 **`router.push('/login')`**;壳内卡片 **「登出」** 会先调用 **`POST /v1/auth/logout`** 再清理并跳转。 ### 管理员审计页(Story 1.9) 前后端均已启动时,使用 **`devadmin`** / **`devpass123`** 登录 → 顶栏出现 **「审计(管理)」** → 进入 **`/admin/audit`**,可筛选并分页查看 **`audit_events`**;**`devuser`** 访问该路径会被前端路由挡回首页并提示需要管理员权限(后端接口同样返回 **403**)。 ## 本地联调(Development Server Structure) 1. 启动后端:`mvn -f backend/pom.xml spring-boot:run`(需 JDK 17)。 2. 启动前端:`pnpm --dir frontend dev`。 3. `frontend/vite.config.ts` 已将路径 **`/api`** 代理到 **`http://localhost:8080`**;与后端 `server.servlet.context-path=/api` 组合后,浏览器通过前端 origin 访问 `/api/...` 即可落到后端。 打开前端首页后,控制台不应出现致命错误;若需验证后端连通,可访问上述 `/api/actuator/health`。 ## 后端构建常见问题 **报错「类文件具有错误的版本 61.0, 应为 52.0」或类似「应为 52.0」** 说明 **Maven 正在使用 JDK 8**(class 52)去编译/解析依赖,而 Spring Boot 3.x 依赖为 **JDK 17**(class 61)。请让 **`java -version` 与 `mvn -v` 中的 Java 版本均为 17+**: 1. Windows:**设置 → 系统 → 关于 → 高级系统设置 → 环境变量**,将 **`JAVA_HOME`** 设为 JDK 17 安装根目录(例如 `C:\Program Files\Microsoft\jdk-17.x.x`),并在 **Path** 中把 **`%JAVA_HOME%\bin`** 移到列表靠前(高于旧 JDK 或 `javapath`)。改完后**重新打开** PowerShell,再执行 `java -version` 与 `mvn -v` 确认。 2. 若暂时不改系统变量,可在当前 PowerShell 会话临时指定 JDK 17(路径换成本机): ```powershell $env:JAVA_HOME = "C:\Program Files\Microsoft\jdk-17.0.13.11-hotspot" $env:Path = "$env:JAVA_HOME\bin;$env:Path" mvn -f backend/pom.xml test ``` `backend/pom.xml` 已配置 **Maven Enforcer**:在 **validate** 阶段若检测到运行 Maven 的 Java 低于 17,会直接失败并提示,避免只看到依赖里的「61 / 52」类文件版本错误。 ## 更多文档 - 本机 MySQL / Redis 等:**`docs/local-setup.md`**(与根 README 互链;Story 1.2 起与 Flyway 对齐)。 - 本机 Prometheus / Grafana 与 **`prometheus`** 端点说明:**`docs/monitoring-local.md`**。 - 产品 / 架构 / 史诗:`_bmad-output/planning-artifacts/`。