Browse Source

docs: 补充系统架构、业务流程与项目开发历程文档

- 04-系统架构与业务流程图: 分层架构、ER图、状态机、认证时序、部署拓扑等16个Mermaid图表
- 05-数据流与模块交互详图: CRUD数据流、费用统计、JWT生命周期、路由守卫等12个时序/流程图
- 06-项目开发历程整理: 5个会话记录整合、Better Harness改进闭环、完整提交历史
C 1 week ago
parent
commit
fd9e1a6f5a

+ 761 - 0
docs/04-系统架构与业务流程图.md

@@ -0,0 +1,761 @@
+# 系统架构与业务流程图
+
+> 基于项目源码自动生成,所有图表均使用 Mermaid 语法,可在支持 Mermaid 的 Markdown 编辑器中渲染。
+
+---
+
+## 一、系统整体架构
+
+### 1.1 分层架构总览
+
+```mermaid
+graph TB
+    subgraph 用户层
+        Browser["浏览器<br/>(Chrome / Edge)"]
+    end
+
+    subgraph 前端["前端 · Vue 3 + Vite"]
+        Router["Vue Router<br/>路由守卫 / 权限控制"]
+        Views["页面组件<br/>Dashboard / Resource / Project ..."]
+        Store["Pinia Store<br/>用户状态 / Token"]
+        API["Axios API 层<br/>request.js 统一拦截"]
+    end
+
+    subgraph 反向代理["Nginx 反向代理"]
+        Static["静态资源托管<br/>dist/"]
+        Proxy["/api/ → :8080<br/>API 反代"]
+    end
+
+    subgraph 后端["后端 · Spring Boot 3"]
+        Controller["Controller 层<br/>REST 接口"]
+        Security["Spring Security<br/>JWT 认证 + 权限"]
+        Service["Service 层<br/>核心业务逻辑"]
+        Mapper["Mapper 层<br/>MyBatis-Plus"]
+        Task["定时任务<br/>ResourceExpireTask"]
+        Mail["邮件服务<br/>EmailService"]
+    end
+
+    subgraph 数据层
+        MySQL["MySQL 8.0+<br/>resource_platform"]
+        SMTP["SMTP 邮件服务器"]
+    end
+
+    Browser -->|HTTP| 反向代理
+    反向代理 -->|静态文件| Static
+    反向代理 -->|/api/*| Controller
+    Router --> Views
+    Views --> Store
+    Views --> API
+    API -->|Bearer Token| Controller
+    Controller --> Security
+    Security --> Service
+    Service --> Mapper
+    Mapper --> MySQL
+    Task --> Service
+    Service --> Mail
+    Mail --> SMTP
+```
+
+### 1.2 后端内部分层
+
+```mermaid
+graph LR
+    subgraph 接入层
+        A["AuthController"]
+        RC["ResourceController"]
+        PC["ProjectController"]
+        DC["DashboardController"]
+        UC["UserController"]
+        RTC["ResourceTypeController"]
+        PRC["ProviderController"]
+        LC["OperationLogController"]
+    end
+
+    subgraph 安全层
+        JWT["JwtAuthenticationFilter"]
+        SC["SecurityConfig<br/>CORS / 权限规则"]
+        SU["SecurityUtils"]
+    end
+
+    subgraph 业务层
+        RS["ResourceServiceImpl"]
+        PS["ProjectServiceImpl"]
+        US["SysUserServiceImpl"]
+        RRS["ResourceRenewalServiceImpl"]
+        DS["DashboardServiceImpl"]
+        OLS["OperationLogServiceImpl"]
+        ES["EmailServiceImpl"]
+    end
+
+    subgraph 数据层
+        RM["ResourceMapper"]
+        PM["ProjectMapper"]
+        UM["SysUserMapper"]
+        RRM["ResourceRenewalMapper"]
+        PRM["ProjectResourceMapper"]
+        OLM["OperationLogMapper"]
+        ENLM["ExpireNotifyLogMapper"]
+    end
+
+    A --> US
+    RC --> RS
+    RC --> RRS
+    PC --> PS
+    DC --> DS
+    UC --> US
+    RTC --> RS
+    PRC --> RS
+    LC --> OLS
+
+    RS --> RM
+    RS --> PRM
+    PS --> PM
+    PS --> PRM
+    US --> UM
+    RRS --> RRM
+    RRS --> RM
+    DS --> RM
+    DS --> PM
+    OLS --> OLM
+    RS --> OLS
+    ES --> SMTP["SMTP"]
+
+    JWT --> SC
+```
+
+---
+
+## 二、数据模型关系图
+
+### 2.1 ER 图
+
+```mermaid
+erDiagram
+    sys_user ||--o{ resource : "负责"
+    sys_user ||--o{ project : "负责"
+    sys_user ||--o{ operation_log : "操作"
+
+    project ||--o{ project : "父子(两层)"
+    project ||--o{ project_resource : "关联"
+    resource ||--o{ project_resource : "关联"
+    resource ||--o{ resource_renewal : "续费"
+    resource ||--o{ expire_notify_log : "提醒"
+    resource }o--|| resource_type : "类型"
+    resource }o--|| provider : "服务商"
+
+    sys_user {
+        int id PK
+        varchar username
+        varchar password
+        varchar real_name
+        varchar email
+        int role "1=管理员 2=普通"
+        int status "0=禁用 1=启用"
+    }
+
+    resource {
+        int id PK
+        varchar name
+        int type_id FK
+        int provider_id FK
+        int owner_id FK
+        date start_date
+        date expire_date
+        decimal cost
+        int cost_cycle "1=月 2=年 3=一次性"
+        int status "0停用 1使用中 2即将到期 3已过期"
+        int purchase_duration
+        varchar account_info
+        varchar remark
+    }
+
+    project {
+        int id PK
+        varchar name
+        int parent_id FK "NULL=顶层"
+        int owner_id FK
+        int status "0=下线 1=进行中"
+        varchar remark
+    }
+
+    project_resource {
+        int id PK
+        int project_id FK
+        int resource_id FK
+        decimal allocation_percent "分摊占比"
+    }
+
+    resource_type {
+        int id PK
+        varchar name
+        int sort
+        varchar remark
+    }
+
+    provider {
+        int id PK
+        varchar name
+        varchar remark
+    }
+
+    resource_renewal {
+        int id PK
+        int resource_id FK
+        date old_expire_date
+        date new_expire_date
+        int duration_code
+        decimal cost
+        varchar remark
+        int operator_id FK
+    }
+
+    expire_notify_log {
+        int id PK
+        int resource_id FK
+        varchar stage "far/near/expired"
+        date notify_date
+        varchar send_to
+    }
+
+    operation_log {
+        int id PK
+        int user_id FK
+        varchar module
+        varchar operation
+        varchar detail
+    }
+```
+
+### 2.2 核心关联关系说明
+
+| 关系 | 类型 | 说明 |
+|------|------|------|
+| resource ↔ resource_type | 多对一 | 每个资源属于一个类型 |
+| resource ↔ provider | 多对一 | 每个资源属于一个服务商 |
+| resource ↔ sys_user (owner) | 多对一 | 每个资源有一个负责人 |
+| resource ↔ project | 多对多 | 通过 project_resource 关联,支持费用分摊 |
+| project_resource.allocation_percent | 分摊占比 | 同一资源在不同项目间按比例分摊费用 |
+| project ↔ project (parent) | 自关联 | 两层结构:顶层项目 + 子项目 |
+| resource ↔ resource_renewal | 一对多 | 一个资源可有多条续费记录 |
+| resource ↔ expire_notify_log | 一对多 | 三阶段提醒记录(far/near/expired) |
+
+---
+
+## 三、核心业务流程图
+
+### 3.1 用户认证流程
+
+```mermaid
+sequenceDiagram
+    participant U as 浏览器
+    participant F as 前端 (Vue)
+    participant S as 后端 (Spring Boot)
+    participant DB as MySQL
+
+    U->>F: 输入用户名/密码
+    F->>S: POST /auth/login {username, password}
+    S->>DB: 查询用户信息
+    DB-->>S: sys_user 记录
+
+    alt 账号不存在 / 已禁用
+        S-->>F: {code: 401, message: "账号不存在或已禁用"}
+    end
+
+    alt 连续失败 ≥ 5 次(15 分钟内)
+        S-->>F: {code: 401, message: "账号已锁定,请 15 分钟后重试"}
+    end
+
+    alt 密码错误
+        S->>DB: 记录失败次数
+        S-->>F: {code: 401, message: "密码错误"}
+    end
+
+    alt 认证成功
+        S->>S: 生成 JWT Token (HS256, 24h)
+        S->>DB: 清除失败计数
+        S-->>F: {code: 200, data: {token, userId, username, role}}
+        F->>F: 存储 token 到 localStorage
+        F->>F: Pinia store 更新用户状态
+        F-->>U: 跳转至 Dashboard
+    end
+
+    Note over U,DB: 后续请求
+    U->>F: 操作页面
+    F->>S: 请求头 Authorization: Bearer <token>
+    S->>S: JwtAuthenticationFilter 校验 Token
+    alt Token 有效
+        S->>S: 设置 SecurityContext
+        S-->>F: 返回业务数据
+    else Token 过期/无效
+        S-->>F: 401 Unauthorized
+        F->>F: 清除 token,跳转登录页
+    end
+```
+
+### 3.2 权限控制模型
+
+```mermaid
+graph TD
+    Login["用户登录"] --> JWT["获取 JWT Token"]
+    JWT --> Filter["JwtAuthenticationFilter"]
+    Filter -->|每次请求| Check{"Token 有效?"}
+    Check -->|否| Reject["401 → 跳转登录"]
+    Check -->|是| Load["加载 LoginUser<br/>(role, status)"]
+    Load --> SecConfig["SecurityConfig 规则匹配"]
+
+    SecConfig --> R1["/auth/login → 公开"]
+    SecConfig --> R2["/user/enabled-list → 登录即可"]
+    SecConfig --> R3["/user/** → ROLE_ADMIN"]
+    SecConfig --> R4["POST/DELETE /resource-type/** → ROLE_ADMIN"]
+    SecConfig --> R5["POST/DELETE /provider/** → ROLE_ADMIN"]
+    SecConfig --> R6["其他接口 → 登录即可"]
+
+    R1 --> Pass["放行"]
+    R2 --> Pass
+    R3 --> Admin{"isAdmin?"}
+    R4 --> Admin
+    R5 --> Admin
+    R6 --> Pass
+    Admin -->|是| Pass
+    Admin -->|否| Deny["403 Forbidden"]
+```
+
+### 3.3 资源生命周期
+
+```mermaid
+stateDiagram-v2
+    [*] --> 使用中: 创建资源<br/>(expire_date > 今天)
+    [*] --> 已过期: 创建资源<br/>(expire_date ≤ 今天)
+
+    使用中 --> 即将到期: 定时任务扫描<br/>(距到期 ≤ 30 天)
+    即将到期 --> 即将到期: 定时任务扫描<br/>(距到期 ≤ 7 天)
+    即将到期 --> 已过期: 超过到期日
+    使用中 --> 已过期: 超过到期日
+
+    已过期 --> 使用中: 续费<br/>(新到期日 > 今天)
+    已过期 --> 即将到期: 续费<br/>(新到期日在 30 天内)
+
+    使用中 --> 已停用: 手动停用
+    即将到期 --> 已停用: 手动停用
+    已停用 --> 使用中: 重新启用<br/>(更新到期日)
+
+    使用中 --> [*]: 删除资源
+    即将到期 --> [*]: 删除资源
+    已过期 --> [*]: 删除资源
+    已停用 --> [*]: 删除资源
+```
+
+### 3.4 资源续费流程
+
+```mermaid
+sequenceDiagram
+    participant U as 用户
+    participant F as 前端
+    participant C as ResourceController
+    participant RRS as ResourceRenewalService
+    participant RS as ResourceService
+    participant DB as MySQL
+
+    U->>F: 点击"续费",填写续费表单
+    Note over U,F: 续费日期、新到期日、时长、金额、备注
+
+    F->>C: POST /resource/{id}/renew
+    C->>RRS: renewResource(id, dto)
+
+    RRS->>DB: 查询当前资源信息
+    DB-->>RRS: Resource 记录
+
+    RRS->>RRS: 校验:新到期日 > 当前到期日
+
+    alt 校验失败
+        RRS-->>C: 抛出 BusinessException
+        C-->>F: {code: 400, message: "新到期日必须晚于当前到期日"}
+    end
+
+    RRS->>DB: INSERT resource_renewal
+    RRS->>DB: UPDATE resource.expire_date = 新到期日
+    RRS->>RS: 刷新资源状态
+
+    RS->>DB: 根据新到期日计算 status
+    Note over RS,DB: 使用中 / 即将到期
+
+    RRS-->>C: 续费成功
+    C->>C: 记录操作日志
+    C-->>F: {code: 200}
+    F->>F: 刷新详情页 + 续费历史列表
+```
+
+### 3.5 到期提醒定时任务
+
+```mermaid
+flowchart TD
+    Start["定时触发<br/>每天 08:00<br/>cron: 0 0 8 * * ?"] --> Refresh["刷新所有资源状态<br/>refreshExpireStatus()"]
+    Refresh --> Scan["扫描需要提醒的资源"]
+
+    Scan --> Check30{"距到期 ≤ 30 天<br/>且 > 7 天?"}
+    Scan --> Check7{"距到期 ≤ 7 天<br/>且 > 0 天?"}
+    Scan --> CheckExpired{"已过期<br/>expire_date < 今天?"}
+
+    Check30 -->|是| Log30{"已发过 far 提醒?"}
+    Check30 -->|否| Skip1["跳过"]
+    Check7 -->|是| Log7{"已发过 near 提醒?"}
+    Check7 -->|否| Skip2["跳过"]
+    CheckExpired -->|是| LogExp{"已发过 expired 提醒?"}
+    CheckExpired -->|否| Skip3["跳过"]
+
+    Log30 -->|未发| Send30["发送邮件<br/>stage=far<br/>普通提醒"]
+    Log30 -->|已发| Skip1
+    Log7 -->|未发| Send7["发送邮件<br/>stage=near<br/>紧急提醒"]
+    Log7 -->|已发| Skip2
+    LogExp -->|未发| SendExp["发送邮件<br/>stage=expired<br/>过期通知"]
+    LogExp -->|已发| Skip3
+
+    Send30 --> Record30["INSERT expire_notify_log<br/>stage=far"]
+    Send7 --> Record7["INSERT expire_notify_log<br/>stage=near"]
+    SendExp --> RecordExp["INSERT expire_notify_log<br/>stage=expired"]
+
+    Record30 --> End["完成"]
+    Record7 --> End
+    RecordExp --> End
+    Skip1 --> End
+    Skip2 --> End
+    Skip3 --> End
+```
+
+### 3.6 费用分摊计算流程
+
+```mermaid
+flowchart TD
+    Start["资源关联多个项目"] --> Input["用户选择关联项目"]
+    Input --> Mode{"分摊模式"}
+
+    Mode -->|均分| Calc1["每个项目 = 100% / N<br/>尾差加到最后一个"]
+    Mode -->|自定义| Calc2["用户手动输入各占比<br/>合计必须 = 100%"]
+
+    Calc1 --> Save["保存到 project_resource<br/>allocation_percent"]
+    Calc2 --> Validate{"合计 = 100%?"}
+    Validate -->|否| Error["提示:分摊占比合计必须为 100%"]
+    Validate -->|是| Save
+
+    Save --> Stat["费用统计时"]
+    Stat --> Formula["分摊费用 = 资源总费用 ×<br/>allocation_percent / 100"]
+    Formula --> Report["生成费用报表<br/>按项目 / 按类型"]
+```
+
+---
+
+## 四、项目管理流程
+
+### 4.1 项目树形结构
+
+```mermaid
+graph TD
+    subgraph 两层项目模型
+        P1["顶层项目 A"]
+        P1 --> C1["子项目 A-1"]
+        P1 --> C2["子项目 A-2"]
+
+        P2["顶层项目 B"]
+        P2 --> C3["子项目 B-1"]
+
+        P3["顶层项目 C<br/>(无子项目)"]
+    end
+
+    C1 --> R1["资源 1"]
+    C1 --> R2["资源 2"]
+    C2 --> R3["资源 3"]
+    C3 --> R4["资源 4"]
+    P3 --> R5["资源 5"]
+
+    style P1 fill:#409eff,color:#fff
+    style P2 fill:#409eff,color:#fff
+    style P3 fill:#409eff,color:#fff
+    style C1 fill:#67c23a,color:#fff
+    style C2 fill:#67c23a,color:#fff
+    style C3 fill:#67c23a,color:#fff
+```
+
+> **规则**:资源只挂在叶子节点(子项目或无子项目的顶层项目)。父项目的资源统计 = 所有子项目资源的聚合。
+
+### 4.2 项目新增/编辑流程
+
+```mermaid
+flowchart TD
+    Start["用户点击新增/编辑"] --> Form["弹窗表单"]
+    Form --> Fields["名称 / 父项目 / 负责人 / 状态 / 备注"]
+    Fields --> Submit["提交"]
+    Submit --> Check{"有父项目?"}
+
+    Check -->|是| Leaf["标记为子项目<br/>parent_id = 选中值"]
+    Check -->|否| Root["标记为顶层项目<br/>parent_id = NULL"]
+
+    Leaf --> Save["保存到 project 表"]
+    Root --> Save
+
+    Save --> Edit{"编辑模式?"}
+    Edit -->|是| Update["UPDATE + 保留子项目关系"]
+    Edit -->|否| Insert["INSERT"]
+
+    Update --> Done["刷新列表"]
+    Insert --> Done
+```
+
+---
+
+## 五、前端页面结构
+
+### 5.1 页面导航树
+
+```mermaid
+graph TD
+    App["App.vue"] --> Login["/login<br/>Login.vue"]
+    App --> Layout["Layout.vue<br/>侧边栏 + 顶栏"]
+
+    Layout --> Dashboard["/dashboard<br/>工作台"]
+    Layout --> Resource["/resource<br/>资源台账"]
+    Layout --> ResourceDetail["/resource/:id<br/>资源详情"]
+    Layout --> Project["/project<br/>项目管理"]
+    Layout --> ProjectDetail["/project/:id<br/>项目详情"]
+    Layout --> CostStat["/cost-stat<br/>费用统计"]
+    Layout --> ProcurementCost["/procurement-cost<br/>采购费用"]
+    Layout --> Dict["/dict<br/>字典管理"]
+    Layout --> User["/user<br/>用户管理 🔒"]
+    Layout --> Log["/log<br/>操作日志"]
+
+    Dashboard --> KPI["6 个 KPI 卡片"]
+    Dashboard --> Chart1["项目状态环形图"]
+    Dashboard --> Chart2["资源类型分布条形图"]
+    Dashboard --> Table["风险清单表格"]
+
+    CostStat --> Chart3["资源类型费用环形图"]
+    CostStat --> Chart4["项目预算消耗排行"]
+    CostStat --> Chart5["各类型费用条形图"]
+    CostStat --> Chart6["项目资源数对比"]
+
+    Dict --> Tab1["资源类型 Tab"]
+    Dict --> Tab2["服务商 Tab"]
+
+    style User fill:#e6a23c,color:#fff
+```
+
+### 5.2 前端组件依赖
+
+```mermaid
+graph LR
+    subgraph 页面组件
+        RL["ResourceList"]
+        RF["ResourceForm"]
+        RD["ResourceDetail"]
+        PL["ProjectList"]
+        PD["ProjectDetail"]
+        DSH["Dashboard"]
+        CS["CostStat"]
+        PC["ProcurementCost"]
+    end
+
+    subgraph 组合式函数
+        UC["useChart()<br/>ECharts 封装"]
+        USR["useScrollRestore()<br/>滚动恢复"]
+    end
+
+    subgraph 工具
+        CSV["exportCsv()"]
+        CC["getChartColors()"]
+        SC["statusClass()"]
+    end
+
+    subgraph API
+        RA["api/resource"]
+        PA["api/project"]
+        DA["api/dashboard"]
+    end
+
+    subgraph Store
+        ST["store/user"]
+    end
+
+    RL --> RF
+    RL --> RA
+    RL --> SC
+    RD --> RA
+    PL --> PA
+    PD --> PA
+    DSH --> DA
+    DSH --> UC
+    DSH --> CSV
+    CS --> RA
+    CS --> UC
+    CS --> CSV
+    PC --> RA
+    PC --> CSV
+    UC --> CC
+    RL --> USR
+```
+
+---
+
+## 六、部署架构
+
+### 6.1 生产部署拓扑
+
+```mermaid
+graph TB
+    subgraph 客户端
+        Browser2["浏览器"]
+    end
+
+    subgraph Nginx["Nginx (resource.mizentech.com:80)"]
+        Frontend["前端静态资源<br/>/opt/resource-platform/frontend/dist/"]
+        APIProxy["/api/ 反代<br/>→ 127.0.0.1:8080"]
+    end
+
+    subgraph Backend["Spring Boot (127.0.0.1:8080)"]
+        App["resource-platform.jar<br/>--spring.profiles.active=prod"]
+    end
+
+    subgraph Data["数据层"]
+        RDS["MySQL 8.0+<br/>resource_platform"]
+        Mail2["SMTP 邮件服务器<br/>smtp.qiye.aliyun.com:465"]
+    end
+
+    subgraph 配置
+        Env[".env (chmod 600)<br/>DB_URL / JWT_SECRET<br/>MAIL_* / CORS_ORIGINS"]
+        Systemd["systemd 服务<br/>自动重启 / 开机自启"]
+    end
+
+    Browser2 -->|HTTP| Nginx
+    Nginx -->|/| Frontend
+    Nginx -->|/api/*| APIProxy
+    APIProxy --> App
+    App --> RDS
+    App --> Mail2
+    Env --> App
+    Systemd --> App
+```
+
+### 6.2 环境配置对比
+
+```mermaid
+graph LR
+    subgraph 开发环境
+        Dev["application-dev.yml"]
+        DevDB["阿里云 RDS<br/>明文密码"]
+        DevMail["smtp.example.com<br/>占位配置"]
+        DevLog["日志级别: DEBUG"]
+        DevCORS["CORS: localhost:5173"]
+    end
+
+    subgraph 生产环境
+        Prod["application-prod.yml"]
+        ProdDB["环境变量注入<br/>DB_URL / DB_PASSWORD"]
+        ProdMail["smtp.qiye.aliyun.com<br/>企业邮箱"]
+        ProdLog["日志级别: INFO"]
+        ProdCORS["CORS: resource.mizentech.com"]
+    end
+
+    Dev --> DevDB
+    Dev --> DevMail
+    Dev --> DevLog
+    Dev --> DevCORS
+    Prod --> ProdDB
+    Prod --> ProdMail
+    Prod --> ProdLog
+    Prod --> ProdCORS
+```
+
+---
+
+## 七、API 接口全景
+
+### 7.1 接口分组总览
+
+```mermaid
+graph TD
+    subgraph 认证模块
+        A1["POST /auth/login"]
+        A2["GET /auth/me"]
+        A3["PUT /auth/password"]
+    end
+
+    subgraph 资源管理
+        R1["GET /resource/page"]
+        R2["GET /resource/{id}"]
+        R3["POST /resource"]
+        R4["DELETE /resource/{id}"]
+        R5["POST /resource/relate"]
+        R6["DELETE /resource/unrelate"]
+        R7["POST /resource/{id}/renew"]
+        R8["GET /resource/{id}/renewals"]
+        R9["DELETE /resource/{id}/renewals/{rid}"]
+        R10["GET /resource/export"]
+    end
+
+    subgraph 费用统计
+        C1["GET /resource/cost-stat/project"]
+        C2["GET /resource/cost-stat/type"]
+        C3["GET /resource/procurement-cost"]
+        C4["GET /resource/procurement-cost/export"]
+    end
+
+    subgraph 项目管理
+        P1["GET /project/page"]
+        P2["GET /project/tree"]
+        P3["GET /project/{id}"]
+        P4["POST /project"]
+        P5["DELETE /project/{id}"]
+        P6["GET /project/active-list"]
+        P7["GET /project/parent-options"]
+    end
+
+    subgraph 工作台
+        D1["GET /dashboard"]
+    end
+
+    subgraph 系统管理 🔒
+        U1["GET /user/list"]
+        U2["GET /user/enabled-list"]
+        U3["POST /user"]
+        U4["DELETE /user/{id}"]
+        T1["GET /resource-type/list"]
+        T2["POST /resource-type"]
+        T3["DELETE /resource-type/{id}"]
+        V1["GET /provider/list"]
+        V2["POST /provider"]
+        V3["DELETE /provider/{id}"]
+        L1["GET /operation-log/page"]
+    end
+```
+
+---
+
+## 八、技术栈依赖关系
+
+```mermaid
+graph TD
+    subgraph 前端依赖
+        Vue["Vue 3.4"] --> VRouter["Vue Router 4.3"]
+        Vue --> Pinia["Pinia 2.1"]
+        Vue --> EP["Element Plus 2.6"]
+        Vue --> ECharts["ECharts 6.1"]
+        Vue --> Axios["Axios 1.6"]
+        Vue --> DayJS["Day.js 1.11"]
+    end
+
+    subgraph 后端依赖
+        SB["Spring Boot 3.2.5"] --> SS["Spring Security 6.2"]
+        SB --> MBP["MyBatis-Plus 3.5.5"]
+        SB --> SM["Spring Mail"]
+        SB --> SV["Spring Validation"]
+        SS --> JWT["JJWT 0.11.5"]
+        MBP --> MySQL["MySQL Connector 8.3"]
+        SB --> EE["EasyExcel 3.3.2"]
+        SB --> Lombok["Lombok 1.18.32"]
+    end
+
+    subgraph 构建工具
+        Vite["Vite 5.1"]
+        Maven["Maven"]
+        Vitest["Vitest 4.1"]
+        JUnit["JUnit 5 + Mockito"]
+    end
+```

+ 471 - 0
docs/05-数据流与模块交互详图.md

@@ -0,0 +1,471 @@
+# 数据流与模块交互详图
+
+> 本文档补充系统各模块之间的数据流转细节和交互时序。
+
+---
+
+## 一、资源管理全链路数据流
+
+### 1.1 资源 CRUD 完整数据流
+
+```mermaid
+sequenceDiagram
+    participant U as 用户
+    participant V as ResourceList.vue
+    participant A as api/resource.js
+    participant C as ResourceController
+    participant S as ResourceServiceImpl
+    participant M as ResourceMapper
+    participant DB as MySQL
+
+    Note over U,DB: ── 分页查询 ──
+    U->>V: 输入筛选条件 / 翻页
+    V->>A: resourcePageApi(params)
+    A->>C: GET /resource/page?keyword=&typeId=&status=&page=&size=
+    C->>S: page(query)
+    S->>M: selectPage + 条件构造
+    M->>DB: SELECT * FROM resource WHERE ...
+    DB-->>M: 分页结果
+    S->>S: 批量组装 VO<br/>(关联类型名、服务商名、负责人名、关联项目)
+    S-->>C: IPage<ResourceVO>
+    C-->>A: Result.ok(data)
+    A-->>V: 渲染表格
+
+    Note over U,DB: ── 新增资源 ──
+    U->>V: 点击"新增",填写表单
+    V->>A: resourceSaveApi(dto)
+    A->>C: POST /resource {name, typeId, providerId, ...}
+    C->>S: save(dto)
+    S->>S: DTO → Entity 转换
+    S->>S: 计算初始状态<br/>(根据 expire_date)
+    S->>M: insert(resource)
+    M->>DB: INSERT INTO resource
+    S->>S: 关联项目 + 设置分摊比例
+    S->>M: batch insert project_resource
+    S->>S: 记录操作日志
+    S-->>C: 成功
+    C-->>A: Result.ok()
+    A-->>V: 关闭弹窗,刷新列表
+
+    Note over U,DB: ── 编辑资源 ──
+    U->>V: 点击"编辑"
+    V->>A: resourceDetailApi(id)
+    A->>C: GET /resource/{id}
+    C->>S: getDetail(id)
+    S->>M: selectById + 关联查询
+    M->>DB: SELECT ...
+    S-->>C: ResourceVO
+    C-->>A: Result.ok(data)
+    A-->>V: 回填表单
+    U->>V: 修改后提交
+    V->>A: resourceSaveApi(dto)
+    A->>C: POST /resource {id, name, ...}
+    C->>S: save(dto)
+    S->>M: updateById
+    M->>DB: UPDATE resource SET ...
+    S->>S: 更新项目关联 + 分摊比例
+    S-->>C: 成功
+    C-->>A: Result.ok()
+
+    Note over U,DB: ── 删除资源 ──
+    U->>V: 点击"删除",确认
+    V->>A: resourceDeleteApi(id)
+    A->>C: DELETE /resource/{id}
+    C->>S: delete(id)
+    S->>M: deleteById (逻辑删除)
+    M->>DB: UPDATE resource SET deleted=1
+    S->>M: 删除关联的 project_resource
+    S->>S: 记录操作日志
+    S-->>C: 成功
+    C-->>A: Result.ok()
+```
+
+### 1.2 资源导出 Excel 数据流
+
+```mermaid
+sequenceDiagram
+    participant U as 用户
+    participant V as ResourceList.vue
+    participant A as api/resource.js
+    participant C as ResourceController
+    participant S as ResourceServiceImpl
+    participant EE as EasyExcel
+    participant DB as MySQL
+
+    U->>V: 点击"导出 Excel"
+    V->>A: resourceExportApi(params)
+    A->>C: GET /resource/export?keyword=&typeId=&status=
+    C->>S: list(query)
+    S->>DB: 查询全量数据(不分页)
+    DB-->>S: List<Resource>
+    S->>S: Entity → ResourceExportVO<br/>(状态转文字、类型名、服务商名)
+    S-->>C: List<ResourceExportVO>
+    C->>EE: EasyExcel.write(response, ResourceExportVO.class)
+    EE->>C: 生成 .xlsx 字节流
+    C-->>A: Content-Type: application/octet-stream<br/>Content-Disposition: attachment
+    A-->>V: Blob 响应
+    V->>V: 创建下载链接<br/>触发浏览器下载
+    V-->>U: 文件保存对话框
+```
+
+---
+
+## 二、项目管理数据流
+
+### 2.1 项目树形查询
+
+```mermaid
+sequenceDiagram
+    participant V as ProjectList.vue
+    participant A as api/project.js
+    participant C as ProjectController
+    participant S as ProjectServiceImpl
+    participant DB as MySQL
+
+    V->>A: projectTreeApi()
+    A->>C: GET /project/tree
+    C->>S: tree()
+    S->>DB: SELECT * FROM project WHERE deleted=0
+    DB-->>S: List<Project>
+
+    S->>S: 分离顶层/子项目
+    S->>S: 构建树形结构:<br/>顶层项目 → children[]
+
+    loop 每个顶层项目
+        S->>DB: 查询关联资源数
+        S->>DB: 查询子项目列表
+        loop 每个子项目
+            S->>DB: 查询子项目关联资源数
+        end
+    end
+
+    S-->>C: List<ProjectVO> (树形)
+    C-->>A: Result.ok(data)
+    A-->>V: el-table tree 模式渲染
+```
+
+### 2.2 项目详情与资源关联
+
+```mermaid
+sequenceDiagram
+    participant U as 用户
+    participant V as ProjectDetail.vue
+    participant A as api/project.js
+    participant RA as api/resource.js
+    participant C as ProjectController
+    participant S as ProjectServiceImpl
+    participant DB as MySQL
+
+    U->>V: 进入项目详情页
+    V->>A: projectDetailApi(id)
+    A->>C: GET /project/{id}
+    C->>S: getDetail(id)
+    S->>DB: 查询项目 + 子项目 + 关联资源
+    DB-->>S: 聚合数据
+    S-->>C: ProjectVO
+    C-->>A: Result.ok(data)
+    A-->>V: 渲染基本信息 + 资源列表
+
+    U->>V: 点击"关联资源"
+    V->>RA: resourcePageApi(未关联筛选)
+    RA-->>V: 可选资源列表
+    U->>V: 多选资源 + 设置分摊比例
+    V->>A: POST /resource/relate
+    Note over V,A: {resourceIds: [1,2,3],<br/>projectId: 5,<br/>allocations: [{resourceId:1, percent:50},...]}
+    A->>C: POST /resource/relate
+    C->>S: 批量插入 project_resource
+    S->>DB: INSERT INTO project_resource
+    DB-->>S: 成功
+    S-->>C: 成功
+    C-->>A: Result.ok()
+    A-->>V: 刷新资源列表
+```
+
+---
+
+## 三、费用统计数据流
+
+### 3.1 按项目维度统计
+
+```mermaid
+flowchart LR
+    subgraph 查询
+        Q["GET /resource/cost-stat/project<br/>?days=30"]
+    end
+
+    subgraph SQL["ResourceMapper.xml"]
+        SQL1["SELECT<br/>  p.name AS projectName,<br/>  COUNT(DISTINCT r.id) AS resourceCount,<br/>  SUM(r.cost * pr.allocation_percent / 100) AS totalCost<br/>FROM project p<br/>LEFT JOIN project_resource pr ON ...<br/>LEFT JOIN resource r ON ...<br/>GROUP BY p.id"]
+    end
+
+    subgraph 结果
+        R1["CostStatVO<br/>{projectName, resourceCount, totalCost}"]
+    end
+
+    Q --> SQL1
+    SQL1 --> R1
+```
+
+### 3.2 采购费用台账数据流
+
+```mermaid
+flowchart TD
+    subgraph 数据来源
+        R["resource 表<br/>初始采购记录"]
+        RR["resource_renewal 表<br/>续费记录"]
+    end
+
+    subgraph 合并逻辑["ResourceServiceImpl.mergeProcurementCosts()"]
+        Q["ProcurementCostQuery<br/>名称/类型/服务商/费用类型/月份"]
+        Merge["合并初始采购 + 续费记录<br/>UNION ALL"]
+        Filter["按条件筛选"]
+        Page["分页"]
+    end
+
+    subgraph 输出
+        VO["ProcurementCostVO<br/>资源名、类型、服务商、项目、占比、<br/>分摊费用、计费周期、购买时长、<br/>类型标签(初始采购/续费)、<br/>发生日期、到期日期"]
+    end
+
+    R --> Merge
+    RR --> Merge
+    Q --> Filter
+    Merge --> Filter
+    Filter --> Page
+    Page --> VO
+```
+
+---
+
+## 四、认证授权数据流
+
+### 4.1 JWT Token 生命周期
+
+```mermaid
+sequenceDiagram
+    participant C as 客户端
+    participant F as JwtAuthenticationFilter
+    participant J as JwtUtil
+    participant US as UserDetailsServiceImpl
+    participant DB as MySQL
+
+    Note over C,DB: ── Token 生成 ──
+    C->>F: POST /auth/login
+    F->>US: loadUserByUsername()
+    US->>DB: SELECT * FROM sys_user WHERE username=?
+    DB-->>US: SysUser
+    US-->>F: LoginUser (UserDetails)
+    F->>J: generateToken(userId, username)
+    J->>J: HS256 签名<br/>payload: {userId, username, iat, exp}
+    J-->>F: JWT String
+    F-->>C: {token, userId, username, role}
+
+    Note over C,DB: ── Token 校验 (每次请求) ──
+    C->>F: GET /resource/page<br/>Authorization: Bearer eyJhbG...
+    F->>F: 提取 Header 中的 Token
+    F->>J: parseToken(token)
+    J->>J: 验签 + 检查过期
+    alt Token 有效
+        J-->>F: Claims {userId, username}
+        F->>US: loadUserByUsername()
+        US->>DB: 查询用户
+        DB-->>US: SysUser
+        US-->>F: LoginUser
+        F->>F: SecurityContextHolder.setContext()
+        F-->>F: chain.doFilter() → Controller
+    else Token 过期
+        J-->>F: ExpiredJwtException
+        F-->>C: 401 Unauthorized
+    else Token 无效
+        J-->>F: SignatureException
+        F-->>C: 401 Unauthorized
+    end
+```
+
+### 4.2 登录安全防护
+
+```mermaid
+flowchart TD
+    Login["登录请求"] --> CheckUser{"用户存在?"}
+    CheckUser -->|否| Fail1["返回: 账号或密码错误"]
+    CheckUser -->|是| CheckStatus{"账号已启用?"}
+    CheckStatus -->|否| Fail2["返回: 账号已禁用"]
+    CheckStatus -->|是| CheckLock{"15 分钟内失败 ≥ 5 次?"}
+    CheckLock -->|是| Fail3["返回: 账号已锁定"]
+    CheckLock -->|否| CheckPwd{"密码正确?"}
+    CheckPwd -->|否| IncFail["失败计数 + 1"]
+    IncFail --> Fail4["返回: 密码错误"]
+    CheckPwd -->|是| ResetFail["清除失败计数"]
+    ResetFail --> GenToken["生成 JWT Token"]
+    GenToken --> Log["记录登录日志"]
+    Log --> Success["返回 token + 用户信息"]
+```
+
+---
+
+## 五、定时任务数据流
+
+### 5.1 资源状态刷新 + 到期提醒
+
+```mermaid
+flowchart TD
+    subgraph 定时触发
+        Cron["cron: 0 0 8 * * ?<br/>每天 08:00"]
+    end
+
+    subgraph 阶段一["阶段一:状态刷新"]
+        Cron --> Refresh["refreshExpireStatus()"]
+        Refresh --> Q1["查询所有未停用资源"]
+        Q1 --> Loop1{"遍历每个资源"}
+        Loop1 --> Calc["计算 daysUntilExpiry<br/>= expire_date - today"]
+        Calc --> S1{"expire_date < today?"}
+        S1 -->|是| Set1["status = 3 (已过期)"]
+        S1 -->|否| S2{"daysUntilExpiry ≤ 30?"}
+        S2 -->|是| Set2["status = 2 (即将到期)"]
+        S2 -->|否| Set3["status = 1 (使用中)"]
+        Set1 --> Update["UPDATE resource SET status"]
+        Set2 --> Update
+        Set3 --> Update
+        Update --> Loop1
+    end
+
+    subgraph 阶段二["阶段二:邮件提醒"]
+        Update --> Scan["扫描需要提醒的资源"]
+        Scan --> Q2["查询 status IN (2, 3) 的资源"]
+        Q2 --> CheckLog{"查 expire_notify_log<br/>是否已发过?"}
+        CheckLog -->|已发| Skip["跳过"]
+        CheckLog -->|未发| Stage{"判断阶段"}
+        Stage -->|≤30天 >7天| Far["stage=far<br/>普通提醒"]
+        Stage -->|≤7天 >0天| Near["stage=near<br/>紧急提醒"]
+        Stage -->|已过期| Expired["stage=expired<br/>过期通知"]
+        Far --> Send["发送邮件给负责人"]
+        Near --> Send
+        Expired --> Send
+        Send --> LogNotify["INSERT expire_notify_log"]
+    end
+```
+
+---
+
+## 六、前端状态管理数据流
+
+### 6.1 用户状态管理 (Pinia)
+
+```mermaid
+flowchart TD
+    subgraph 登录流程
+        Input["输入账号密码"] --> CallLogin["userStore.login()"]
+        CallLogin --> API["loginApi() → POST /auth/login"]
+        API --> Resp["响应: {token, userId, role}"]
+        Resp --> SetToken["setToken(token)"]
+        SetToken --> LS["localStorage.setItem('token', ...)"]
+        SetToken --> State["state.token = token"]
+        State --> FetchMe["fetchMe() → GET /auth/me"]
+        FetchMe --> SetInfo["state.userInfo = {...}"]
+        SetInfo --> Redirect["router.push(redirect || '/dashboard')"]
+    end
+
+    subgraph 请求拦截
+        Req["Axios 请求"] --> GetToken["localStorage.getItem('token')"]
+        GetToken --> AddHeader["headers.Authorization = 'Bearer ' + token"]
+        AddHeader --> Send["发送请求"]
+    end
+
+    subgraph 响应拦截
+        Res["Axios 响应"] --> CheckCode{"code === 200?"}
+        CheckCode -->|否| Error["ElMessage.error(msg)"]
+        CheckCode -->|是| Return["返回 data"]
+        Error --> Check401{"code === 401?"}
+        Check401 -->|是| ClearToken["clearToken()"]
+        ClearToken --> GoLogin["router.push('/login')"]
+    end
+```
+
+### 6.2 路由守卫流程
+
+```mermaid
+flowchart TD
+    Nav["用户导航"] --> Guard["router.beforeEach()"]
+    Guard --> HasToken{"localStorage<br/>有 token?"}
+    HasToken -->|是| IsLogin{"目标是 /login?"}
+    IsLogin -->|是| Redirect["→ /dashboard<br/>(已登录不显示登录页)"]
+    IsLogin -->|否| Allow["放行"]
+    HasToken -->|否| IsPublic{"是公开页?<br/>(/login)"}
+    IsPublic -->|是| Allow
+    IsPublic -->|否| ToLogin["→ /login?redirect=当前路径"]
+```
+
+---
+
+## 七、模块间交互矩阵
+
+```mermaid
+graph TD
+    subgraph 资源模块
+        Res["Resource"]
+        Renew["ResourceRenewal"]
+        Expire["ExpireNotify"]
+    end
+
+    subgraph 项目模块
+        Proj["Project"]
+        ProjRes["ProjectResource"]
+    end
+
+    subgraph 用户模块
+        User["SysUser"]
+        Auth["Auth/JWT"]
+    end
+
+    subgraph 系统模块
+        Log["OperationLog"]
+        Dict["ResourceType/Provider"]
+        Dash["Dashboard"]
+    end
+
+    Res -->|owner_id| User
+    Res -->|type_id| Dict
+    Res -->|provider_id| Dict
+    Res -->|续费| Renew
+    Res -->|关联| ProjRes
+    Res -->|到期提醒| Expire
+    Res -->|操作日志| Log
+
+    Proj -->|owner_id| User
+    Proj -->|父子| Proj
+    Proj -->|关联| ProjRes
+
+    ProjRes -->|project_id| Proj
+    ProjRes -->|resource_id| Res
+
+    Renew -->|resource_id| Res
+    Renew -->|operator_id| User
+
+    Expire -->|resource_id| Res
+
+    Log -->|user_id| User
+
+    Dash -->|统计| Res
+    Dash -->|统计| Proj
+
+    Auth -->|认证| User
+```
+
+---
+
+## 八、关键设计决策
+
+| 决策 | 方案 | 理由 |
+|------|------|------|
+| 认证方式 | JWT (无状态) | 前后端分离,无需服务端 session |
+| 密码存储 | BCrypt 哈希 | Spring Security 内置支持,安全性高 |
+| 登录锁定 | 内存计数 + 15 分钟过期 | 简单有效,防暴力破解 |
+| 项目结构 | 两层(顶层 + 子项目) | 满足业务需求,避免过深嵌套 |
+| 费用分摊 | project_resource 表存储百分比 | 灵活支持均分/自定义,尾差修正 |
+| 续费记录 | 独立表,不回写主表金额 | 保留完整历史,支持删除回滚 |
+| 到期提醒 | 三阶段 + 日志表去重 | 避免重复发送,提醒有梯度 |
+| 资源状态 | 定时任务刷新 + 操作时即时刷新 | 双保险,数据一致性 |
+| 逻辑删除 | MyBatis-Plus @TableLogic | 数据可恢复,审计友好 |
+| 配置分离 | dev/prod profile | 开发便利 + 生产安全 |
+| 敏感信息 | 环境变量注入 | 不进代码仓库 |
+| Excel 导出 | EasyExcel | 内存友好,大数据量不 OOM |
+| 前端图表 | ECharts + useChart 封装 | 主题切换支持,代码复用 |
+| 前端状态 | Pinia (Composition API) | Vue 3 官方推荐,类型安全 |

+ 214 - 0
docs/06-项目开发历程与聊天记录整理.md

@@ -0,0 +1,214 @@
+# 项目聊天记录整理 — resource-platform 开发历程
+
+> 整理时间:2026-08-13
+> 涵盖会话:5 个(按时间顺序)
+
+---
+
+## 一、开发时间线总览
+
+```
+阶段 1  项目基础引导        → 创建 AGENTS.md,建立项目知识索引
+阶段 2  Better Harness 洞察  → 自动化分析发现 2 个改进点
+阶段 3  测试基建             → 前后端最小验证路径(Vitest + JUnit 5)
+阶段 4  Better Harness 复评  → 构建脚本累积问题被识别并解决
+阶段 5  构建脚本统一         → 合并 15 个版本脚本为统一入口
+阶段 6  架构文档生成         → 系统架构图 + 业务流程图 + 数据流图
+```
+
+---
+
+## 二、各会话详情
+
+### 会话 1:Better Harness 洞察生成
+
+| 字段 | 值 |
+|------|------|
+| 会话 ID | `ad7d6948-2a20-42d9-9068-6deb6f09f46f` |
+| 时间 | 2026-08-13 04:08 |
+| 触发方式 | `/better-harness` 自动分析 |
+
+#### 分析结论
+
+**项目状态**:Bootstrap (0→1) 阶段 — 基础导航和验证路径缺失
+
+| 维度 | 得分 | 说明 |
+|------|------|------|
+| 任务理解 | 30 | 无项目级 Agent 引导指令 |
+| 可控执行 | 35 | 清单存在但无 Commands/Skills/Hooks |
+| 改动验证 | 20 | 零测试文件,无验证路径 |
+| 可靠交付 | 25 | 无 CI/CD 或验收机制 |
+| 经验沉淀 | 35 | 无 Memory/事件/学习闭环 |
+
+#### 发现的 2 个问题
+
+1. **[Medium] Agent 缺少项目架构引导** — 项目无 AGENTS.md,Agent 每次交互必须从零推断全栈架构
+2. **[Medium] 代码变更无自动化验证路径** — 17 个前端源文件对应 0 个测试文件
+
+---
+
+### 会话 2:创建根目录 AGENTS.md 文档
+
+| 字段 | 值 |
+|------|------|
+| 会话 ID | `fca35392-9342-4068-a283-5c8a32dafd44` |
+| 时间 | 2026-08-13 04:59 |
+| 解决问题 | "Agent 缺少项目架构引导" |
+
+#### 完成内容
+
+创建 `AGENTS.md`,涵盖:项目结构、核心模块、技术栈、构建命令、关键约定(Java 包路径、前后端目录分工)。
+
+---
+
+### 会话 3:核心模块最小验证路径
+
+| 字段 | 值 |
+|------|------|
+| 会话 ID | `d23d1e6d-4cb4-4b89-b933-84e9b75203b0` |
+| 时间 | 2026-08-13 04:59 ~ 06:01 |
+| 解决问题 | "代码变更无自动化验证路径" |
+| 提交 | `dc4b720` — `test: 建立前后端最小验证路径` |
+
+#### 完成内容
+
+**前端测试(Vitest)— 33 个测试**
+
+| 文件 | 测试数 | 覆盖范围 |
+|------|--------|---------|
+| `src/api/__tests__/resource.test.js` | 14 | 所有 resource API 函数 |
+| `src/api/__tests__/auth.test.js` | 3 | auth API |
+| `src/router/__tests__/router.test.js` | 16 | 路由定义和导航守卫 |
+
+**后端测试(JUnit 5 + Mockito)— 18 个测试**
+
+| 文件 | 测试数 | 覆盖范围 |
+|------|--------|---------|
+| `ResourceServiceImplTest.java` | 18 | getDetail、saveOrUpdate、delete、refreshExpireStatus、costStat |
+
+**提交统计**:8 个文件变更(+3257 / -134)
+
+---
+
+### 会话 4:Better Harness 复评
+
+| 字段 | 值 |
+|------|------|
+| 会话 ID | `ee0e7282-b70d-441c-89fa-b0b27c7c80d6` |
+| 时间 | 2026-08-13 07:13 |
+
+#### 评分提升
+
+| 维度 | 首次 | 复评 | 变化 |
+|------|------|------|------|
+| 任务理解 | 30 | 58 | +28 |
+| 可控执行 | 35 | 55 | +20 |
+| 改动验证 | 20 | 52 | +32 |
+| 可靠交付 | 25 | 42 | +17 |
+| 经验沉淀 | 35 | 38 | +3 |
+
+#### 新发现问题
+
+**[Low] 构建脚本版本累积** — backend/ 下 6 个编号构建脚本 + 2 个 repack 变体全部在 git 中跟踪,无文档指明当前推荐版本。
+
+---
+
+### 会话 5:构建脚本版本清理与统一(当前会话)
+
+| 字段 | 值 |
+|------|------|
+| 会话 ID | `72d8b134-7a64-4713-a85f-d87106991c0d` |
+| 时间 | 2026-08-13 12:08 ~ 12:59 |
+| 提交 | `ad31bc1` — `refactor: 合并后端构建脚本为统一入口` |
+
+#### 版本演进链
+
+```
+v5.jar → build_v6.py → v6.jar(基础编译+替换)
+         ↓
+       build_v7.py → v7.jar(+资源注入、lombok、自动解压依赖)
+         ↓
+       build_v8.py → v8.jar(+新增类自动补打)
+         ↓
+       build_v9~v11.py(核心逻辑同 v8,仅校验类名不同 → 版本膨胀)
+```
+
+#### 清理结果
+
+| 清理前 | 清理后 |
+|--------|--------|
+| 6 个 build_v*.py | 1 个 build.py |
+| 5 个 start_v*.sh | 1 个 start.sh |
+| 3 个 repack*.py | 删除 |
+| 1 个 extract_deps.py | 删除 |
+| **15 个文件** | **2 个文件** |
+
+**提交统计**:5 files changed, 329 insertions(+), 7 deletions(-)
+
+---
+
+### 附加:架构文档生成
+
+| 文件 | 行数 | 图表数 |
+|------|------|--------|
+| `docs/04-系统架构与业务流程图.md` | 761 | 16 个 Mermaid |
+| `docs/05-数据流与模块交互详图.md` | 471 | 12 个 Mermaid |
+
+---
+
+## 三、Git 提交历史(完整开发周期)
+
+```
+ad31bc1  refactor: 合并后端构建脚本为统一入口
+dc4b720  test: 建立前后端最小验证路径
+b0831f7  chore: 清理中间构建脚本,完善.gitignore安全规则
+b6b078a  fix(renew): 删除按钮无响应-补导入 ElMessageBox
+d6e2636  feat(renew): 支持删除续费记录并按剩余续费回滚资源到期日
+febfcd2  feat(cost): 资源费用按项目分摊
+d9aac2c  feat(cost): 采购费用支持按月份筛选并导出Excel
+ae6d465  feat: 采购费用统一台账 + 资源续费
+72cff05  feat(cost): 费用统计本月/本季/本年筛选生效
+ffab4b3  feat(project): 主项目详情增加「涉及的子系统」字段
+ac9513e  fix(project): 树形子行序号垂直居中
+75a4a78  feat(project): 列表序号改为层级化编号
+6a00717  feat(project): 项目管理支持两层结构
+2b188b1  feat(resource): 购买时长新增「按量」选项
+7894f8a  feat(resource): 购买时长选项改为月/年
+f6b79ba  fix(web): 修复简单类型入参缺参数名导致500
+6605ea8  fix & chore: 费用统计SQL修正 + 仓库安全加固
+a0943f6  feat(resource): 新增「购买时长」字段
+b097a92  feat(frontend): 列表行序号 + keep-alive缓存
+54a6ebf  feat(frontend): UI全面升级 — 科技蓝主题 + 暗色模式 + ECharts
+```
+
+---
+
+## 四、改进闭环
+
+```
+首次分析 (会话1)
+  ├─ 问题1: 无 AGENTS.md ─────→ 会话2 解决 ✓
+  └─ 问题2: 无测试验证路径 ───→ 会话3 解决 ✓
+                                   ↓
+复评 (会话4)                     评分全面提升
+  └─ 新问题: 构建脚本累积 ────→ 会话5 解决 ✓
+                                   ↓
+                              文档生成 (附加)
+```
+
+---
+
+## 五、当前状态与待办
+
+### 已完成
+
+- [x] 项目知识索引(AGENTS.md)
+- [x] 前后端测试基建(51 个测试用例)
+- [x] 构建脚本统一(15 → 2)
+- [x] 架构文档生成(28 个 Mermaid 图表)
+
+### 待处理
+
+- [ ] 提交架构文档(docs/04、docs/05、docs/06 未跟踪)
+- [ ] Better Harness 评分继续提升(目标:各维度 > 70)
+- [ ] 部署配置实际验证(CI/CD 管道)