From 19de7e24ecf69515d14939e05dc1c79aa27211a4 Mon Sep 17 00:00:00 2001 From: pigeon Date: Thu, 4 Jun 2026 09:31:24 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=BF=81=E7=A7=BB=20spring-ai=20?= =?UTF-8?q?=E9=80=9A=E7=94=A8=E6=96=87=E6=A1=A3=E5=88=B0=20rui-docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 从 docs-local 迁移以下文档: - backend/guides/: AI开发环境配置、Nacos配置、GitNexus指南、OpenCode工作流等 - backend/templates/: Superpowers设计模板、计划模板、审查清单 - backend/config-templates/: 应用配置模板、Nacos配置 - backend/design/: 数据库表结构规划 - backend/specs/: 项目文档治理、MQ统一推送设计 - backend/: 代码分析报告、Feign分析报告、文档治理报告 - frontend/design/: Admin-UI分模块打包设计 --- .../config-templates/application-template.yml | 65 ++ .../logback-spring-template.xml | 154 ++++ backend/config-templates/nacos/rui-auth.yaml | 7 + .../config-templates/nacos/rui-common.yaml | 47 ++ backend/config-templates/nacos/rui-data.yaml | 74 ++ .../config-templates/nacos/rui-gateway.yaml | 80 +++ .../nacos/rui-service-cache.yaml | 8 + .../nacos/rui-service-file.yaml | 8 + .../nacos/rui-service-log.yaml | 8 + .../nacos/rui-service-monitor.yaml | 8 + .../nacos/rui-service-msg.yaml | 8 + .../nacos/rui-service-order.yaml | 7 + .../nacos/rui-service-pay.yaml | 60 ++ .../nacos/rui-service-search.yaml | 8 + .../nacos/rui-service-system.yaml | 33 + .../nacos/rui-service-user.yaml | 7 + backend/design/数据库表结构规划.md | 664 ++++++++++++++++++ backend/guides/AI开发环境配置手册.md | 388 ++++++++++ backend/guides/Nacos配置管理规范.md | 120 ++++ ...PoolBulkhead-租户上下文传播问题排查指南.md | 413 +++++++++++ backend/guides/environment-setup.md | 181 +++++ backend/guides/gitnexus-guide.md | 52 ++ backend/guides/opencode-workflow.md | 322 +++++++++ backend/guides/rui-common-core使用手册.md | 459 ++++++++++++ backend/guides/self-hosted-git-server.md | 480 +++++++++++++ backend/guides/灰度发布.md | 242 +++++++ backend/guides/聚合启动器使用文档.md | 302 ++++++++ backend/rui-common-feign-分析报告.md | 21 + ...目文档治理与Superpowers流程规范化-design.md | 587 ++++++++++++++++ .../2026-06-04-mq-unified-push-design.md | 236 +++++++ backend/spring-rui 代码分析报告.md | 278 ++++++++ backend/templates/design-template.md | 54 ++ backend/templates/plan-template.md | 32 + backend/templates/review-checklist.md | 25 + backend/项目文档治理改进报告.md | 63 ++ ...2026-06-04-admin-ui-module-build-design.md | 371 ++++++++++ 36 files changed, 5872 insertions(+) create mode 100644 backend/config-templates/application-template.yml create mode 100644 backend/config-templates/logback-spring-template.xml create mode 100644 backend/config-templates/nacos/rui-auth.yaml create mode 100644 backend/config-templates/nacos/rui-common.yaml create mode 100644 backend/config-templates/nacos/rui-data.yaml create mode 100644 backend/config-templates/nacos/rui-gateway.yaml create mode 100644 backend/config-templates/nacos/rui-service-cache.yaml create mode 100644 backend/config-templates/nacos/rui-service-file.yaml create mode 100644 backend/config-templates/nacos/rui-service-log.yaml create mode 100644 backend/config-templates/nacos/rui-service-monitor.yaml create mode 100644 backend/config-templates/nacos/rui-service-msg.yaml create mode 100644 backend/config-templates/nacos/rui-service-order.yaml create mode 100644 backend/config-templates/nacos/rui-service-pay.yaml create mode 100644 backend/config-templates/nacos/rui-service-search.yaml create mode 100644 backend/config-templates/nacos/rui-service-system.yaml create mode 100644 backend/config-templates/nacos/rui-service-user.yaml create mode 100644 backend/design/数据库表结构规划.md create mode 100644 backend/guides/AI开发环境配置手册.md create mode 100644 backend/guides/Nacos配置管理规范.md create mode 100644 backend/guides/Resilience4j-ThreadPoolBulkhead-租户上下文传播问题排查指南.md create mode 100644 backend/guides/environment-setup.md create mode 100644 backend/guides/gitnexus-guide.md create mode 100644 backend/guides/opencode-workflow.md create mode 100644 backend/guides/rui-common-core使用手册.md create mode 100644 backend/guides/self-hosted-git-server.md create mode 100644 backend/guides/灰度发布.md create mode 100644 backend/guides/聚合启动器使用文档.md create mode 100644 backend/rui-common-feign-分析报告.md create mode 100644 backend/specs/2026-06-02-项目文档治理与Superpowers流程规范化-design.md create mode 100644 backend/specs/2026-06-04-mq-unified-push-design.md create mode 100644 backend/spring-rui 代码分析报告.md create mode 100644 backend/templates/design-template.md create mode 100644 backend/templates/plan-template.md create mode 100644 backend/templates/review-checklist.md create mode 100644 backend/项目文档治理改进报告.md create mode 100644 frontend/design/2026-06-04-admin-ui-module-build-design.md diff --git a/backend/config-templates/application-template.yml b/backend/config-templates/application-template.yml new file mode 100644 index 0000000..b7697dc --- /dev/null +++ b/backend/config-templates/application-template.yml @@ -0,0 +1,65 @@ +# ============================================================================ +# 睿核科技 — 通用平台框架 通用 application.yml 模板 +# ============================================================================ +# 使用方法: +# 复制到新模块的 src/main/resources/application.yml +# 修改 server.port 为模块对应端口 +# 本地开发配置见项目根目录 config/application-dev.yml(不提交 git) +# ============================================================================ + +server: + port: XXXX # 模块端口(按规划分配) + shutdown: graceful # 优雅关闭 + + +spring: + application: + name: @artifactId@ # Maven 过滤,自动替换为模块名 + profiles: + active: @profiles.active@ # Maven 过滤,默认 dev + lifecycle: + timeout-per-shutdown-phase: 30s # 优雅关闭等待时间 + autoconfigure: + exclude: + servlet: + multipart: + max-file-size: 5MB + max-request-size: 10MB + encoding: + charset: UTF-8 + enabled: true + force: true + cloud: + openfeign: + circuitbreaker: + enabled: true + nacos: + discovery: # 服务发现(独立环境变量,不依赖 config) + server-addr: ${NACOS_SERVER_ADDR:nacos:8848} + namespace: ${NACOS_NAMESPACE:} + group: ${NACOS_GROUP:DEFAULT_GROUP} + username: ${NACOS_USERNAME:nacos} + password: ${NACOS_PASSWORD:nacos} + config: # 配置中心 + server-addr: ${NACOS_SERVER_ADDR:nacos:8848} + namespace: ${NACOS_NAMESPACE:} + group: ${NACOS_GROUP:DEFAULT_GROUP} + username: ${NACOS_USERNAME:nacos} + password: ${NACOS_PASSWORD:nacos} + file-extension: yaml + import-check: + enabled: true + config: + import: + - optional:nacos:${spring.application.name}.${spring.cloud.nacos.config.file-extension:yaml} + - optional:nacos:rui-common.${spring.cloud.nacos.config.file-extension:yaml} + # 无 MyBatis 的模块(gateway)请删除下面这行 + - optional:nacos:rui-data.${spring.cloud.nacos.config.file-extension:yaml} + +management: + endpoints: + web: + exposure: + include: health + discovery: + enabled: false diff --git a/backend/config-templates/logback-spring-template.xml b/backend/config-templates/logback-spring-template.xml new file mode 100644 index 0000000..bb07b10 --- /dev/null +++ b/backend/config-templates/logback-spring-template.xml @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + ${CONSOLE_LOG_PATTERN} + UTF-8 + + + + + + + ${LOG_PATH}/debug.log + + DEBUG + ACCEPT + DENY + + + ${LOG_PATH}/history/debug/log-debug.%d{yyyy-MM-dd}.%i.log + 50MB + 7 + 200MB + + + ${FILE_LOG_PATTERN} + UTF-8 + + + + + + + ${LOG_PATH}/info.log + + INFO + ACCEPT + DENY + + + ${LOG_PATH}/history/info/log-info.%d{yyyy-MM-dd}.%i.log + 50MB + 7 + 200MB + + + ${FILE_LOG_PATTERN} + UTF-8 + + + + + + + ${LOG_PATH}/warn.log + + WARN + ACCEPT + DENY + + + ${LOG_PATH}/history/warn/log-warn.%d{yyyy-MM-dd}.%i.log + 50MB + 7 + 200MB + + + ${FILE_LOG_PATTERN} + UTF-8 + + + + + + + ${LOG_PATH}/error.log + + ERROR + ACCEPT + DENY + + + ${LOG_PATH}/history/error/log-error.%d{yyyy-MM-dd}.%i.log + 50MB + 7 + 200MB + + + ${FILE_LOG_PATTERN} + UTF-8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/backend/config-templates/nacos/rui-auth.yaml b/backend/config-templates/nacos/rui-auth.yaml new file mode 100644 index 0000000..92f8702 --- /dev/null +++ b/backend/config-templates/nacos/rui-auth.yaml @@ -0,0 +1,7 @@ +# rui-auth.yaml — 认证中心模块配置 +# Data ID: rui-auth.yaml +# Group: DEFAULT_GROUP + +# 服务端口:9301(认证中心,所有服务依赖) +server: + port: 9301 diff --git a/backend/config-templates/nacos/rui-common.yaml b/backend/config-templates/nacos/rui-common.yaml new file mode 100644 index 0000000..fe14972 --- /dev/null +++ b/backend/config-templates/nacos/rui-common.yaml @@ -0,0 +1,47 @@ +# rui-common.yaml — 所有模块共享 +# Data ID: rui-common.yaml +# Group: DEFAULT_GROUP +# 用途: 全局通用配置(Redis、Jackson、JWT、安全白名单) + +spring: + rabbitmq: + host: ${RABBITMQ_HOST:192.168.31.210} + port: ${RABBITMQ_PORT:5672} + username: ${RABBITMQ_USERNAME:vifo} + password: ${RABBITMQ_PASSWORD:!QW3e4r2023} + data: + redis: + host: ${REDIS_HOST:192.168.31.210} + port: ${REDIS_PORT:6379} + password: ${REDIS_PASSWORD:123456} + database: 0 + timeout: 3000ms + lettuce: + pool: + max-active: 8 + max-idle: 8 + min-idle: 0 + max-wait: -1ms + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: GMT+8 + default-property-inclusion: non_null +security: + oauth2: + ignore-urls: + - /entry/** + - /notify/** + - /actuator/** + +# MyBatis Plus 全局配置 +mybatis-plus: + configuration: + map-underscore-to-camel-case: true + cache-enabled: true + +# Feign 服务提供者配置(默认走聚合启动器,独立模式请在各服务配置中覆盖) +feign: + providers: + user: rui-service-starter # 用户服务:默认指向聚合启动器 + system: rui-service-starter # 系统服务:默认指向聚合启动器 + auth: rui-auth # 认证中心:保持独立 diff --git a/backend/config-templates/nacos/rui-data.yaml b/backend/config-templates/nacos/rui-data.yaml new file mode 100644 index 0000000..a9a3323 --- /dev/null +++ b/backend/config-templates/nacos/rui-data.yaml @@ -0,0 +1,74 @@ +# rui-data.yaml — 数据库模块共享 +# Data ID: rui-data.yaml +# Group: DEFAULT_GROUP +# 用途: 数据源 + MyBatis Plus 配置(仅 DB 模块导入) + +spring: + datasource: + url: jdbc:mysql://${DB_HOST:192.168.31.210}:3306/rui_platform?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai + username: ${DB_USERNAME:root} + password: ${DB_PASSWORD:123456} + driver-class-name: com.mysql.cj.jdbc.Driver + druid: + initial-size: 5 + min-idle: 5 + max-active: 20 + max-wait: 60000 + +mybatis-plus: + global-config: + db-config: + table-prefix: rui_ + id-type: assign_id + logic-delete-field: deleted + logic-delete-value: 1 + logic-not-delete-value: 0 + configuration: + map-underscore-to-camel-case: true + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + mapper-locations: classpath*:/mapper/**/*.xml + tenant: + mode: IGNORE + tenant-ignore: + - sys_tenant + - user_credential + - system_oauth2_client + # 系统租户也需限制租户隔离的表(即使是系统租户,也只能查自己租户的数据) + system-tenant-table: + - uc_user + - uc_user_detail + - uc_user_role + - uc_user_dept + - uc_user_post + - uc_user_permission + - uc_user_level + - uc_user_level_log + - sys_menu + - sys_role + - sys_role_menu + - sys_role_dept + - sys_dept + - sys_post + - sys_dict_type + - sys_dict_item + - sys_config + - sys_oper_log + - sys_login_log + + +seata: + enabled: true + tx-service-group: my_tx_group + service: + vgroup-mapping: + my_tx_group: default + data-source-proxy-mode: AT + registry: + type: nacos + nacos: + application: seata-server + server-addr: ${spring.cloud.nacos.config.server-addr} + group : SEATA_GROUP + namespace: cloud + username: ${spring.cloud.nacos.config.username} + password: ${spring.cloud.nacos.config.password} \ No newline at end of file diff --git a/backend/config-templates/nacos/rui-gateway.yaml b/backend/config-templates/nacos/rui-gateway.yaml new file mode 100644 index 0000000..ab75f98 --- /dev/null +++ b/backend/config-templates/nacos/rui-gateway.yaml @@ -0,0 +1,80 @@ +# rui-gateway.yaml — 网关路由配置 (Gateway 5.x 格式:server.webflux.routes) +# 说明:默认使用聚合模式(所有业务路由指向 rui-service-starter) +# 如需独立微服务模式,取消注释独立路由并注释掉聚合路由 +spring: + cloud: + gateway: + server: + webflux: + routes: + - id: rui-auth + uri: lb://rui-auth + predicates: + - Path=/auth/** + filters: + - StripPrefix=0 + - id: rui-auth + uri: lb://rui-auth + predicates: + - Path=/oauth2/** + filters: + - StripPrefix=0 + - id: rui-service-pay + uri: lb://rui-service-pay + predicates: + - Path=/payment/** + filters: + - StripPrefix=0 + # ========== 聚合模式(默认,中小型项目)========== + - id: rui-service-starter + uri: lb://rui-service-starter + predicates: + - Path=/user/**,/system/** + filters: + - StripPrefix=0 + - id: rui-cashier + uri: lb://rui-cashier-api + predicates: + - Path=/cashier/** + filters: + - StripPrefix=0 + # ========== 独立微服务模式(大型项目)========== + # - id: rui-service-user + # uri: lb://rui-service-user + # predicates: + # - Path=/user/** + # filters: + # - StripPrefix=0 + # - id: rui-service-system + # uri: lb://rui-service-system + # predicates: + # - Path=/system/** + # filters: + # - StripPrefix=0 + +# 灰度发布配置 +# 支持按服务配置不同的灰度策略,包括:权重、用户白名单、IP 白名单、强制 Header +grayscale: + # 强制灰度 Header 名称,客户端通过此 Header 强制指定版本 + force-header: X-Grayscale-Version + # 灰度规则(Key 为服务名,如 rui-service-user) + # 配置示例: + # rules: + # rui-service-user: + # enabled: true + # version: v2 + # weight: 10 + # user-ids: + # - user001 + # ip-ranges: + # - 192.168.1.0/24 + +management: + endpoints: + web: + exposure: + include: health # 仅暴露 health 端点,其余全部禁止访问 + +# 服务端口:9300(网关最优先) +server: + port: 9300 diff --git a/backend/config-templates/nacos/rui-service-cache.yaml b/backend/config-templates/nacos/rui-service-cache.yaml new file mode 100644 index 0000000..090bca6 --- /dev/null +++ b/backend/config-templates/nacos/rui-service-cache.yaml @@ -0,0 +1,8 @@ +# rui-service-cache.yaml — 缓存服务配置 +# Data ID: rui-service-cache.yaml +# Group: DEFAULT_GROUP +# 功能:Redis缓存封装、分布式锁 + +# 服务端口:9309(缓存服务) +server: + port: 9309 diff --git a/backend/config-templates/nacos/rui-service-file.yaml b/backend/config-templates/nacos/rui-service-file.yaml new file mode 100644 index 0000000..987fad3 --- /dev/null +++ b/backend/config-templates/nacos/rui-service-file.yaml @@ -0,0 +1,8 @@ +# rui-service-file.yaml — 文件存储服务配置 +# Data ID: rui-service-file.yaml +# Group: DEFAULT_GROUP +# 功能:文件上传、下载、OOS存储、本地存储 + +# 服务端口:9305(文件服务) +server: + port: 9305 diff --git a/backend/config-templates/nacos/rui-service-log.yaml b/backend/config-templates/nacos/rui-service-log.yaml new file mode 100644 index 0000000..98de516 --- /dev/null +++ b/backend/config-templates/nacos/rui-service-log.yaml @@ -0,0 +1,8 @@ +# rui-service-log.yaml — 日志服务配置 +# Data ID: rui-service-log.yaml +# Group: DEFAULT_GROUP +# 功能:日志收集、日志分析、ELK集成 + +# 服务端口:9310(日志服务) +server: + port: 9310 diff --git a/backend/config-templates/nacos/rui-service-monitor.yaml b/backend/config-templates/nacos/rui-service-monitor.yaml new file mode 100644 index 0000000..e70ff14 --- /dev/null +++ b/backend/config-templates/nacos/rui-service-monitor.yaml @@ -0,0 +1,8 @@ +# rui-service-monitor.yaml — 监控告警服务配置 +# Data ID: rui-service-monitor.yaml +# Group: DEFAULT_GROUP +# 功能:系统监控、性能指标、告警通知 + +# 服务端口:9311(监控服务) +server: + port: 9311 diff --git a/backend/config-templates/nacos/rui-service-msg.yaml b/backend/config-templates/nacos/rui-service-msg.yaml new file mode 100644 index 0000000..0990564 --- /dev/null +++ b/backend/config-templates/nacos/rui-service-msg.yaml @@ -0,0 +1,8 @@ +# rui-service-msg.yaml — 消息通知服务配置 +# Data ID: rui-service-msg.yaml +# Group: DEFAULT_GROUP +# 功能:SMS短信、邮件、站内信、App推送 + +# 服务端口:9304(消息服务) +server: + port: 9304 diff --git a/backend/config-templates/nacos/rui-service-order.yaml b/backend/config-templates/nacos/rui-service-order.yaml new file mode 100644 index 0000000..486374e --- /dev/null +++ b/backend/config-templates/nacos/rui-service-order.yaml @@ -0,0 +1,7 @@ +# rui-service-order.yaml — 订单服务配置 +# Data ID: rui-service-order.yaml +# Group: DEFAULT_GROUP + +# 服务端口:9306(订单服务) +server: + port: 9306 diff --git a/backend/config-templates/nacos/rui-service-pay.yaml b/backend/config-templates/nacos/rui-service-pay.yaml new file mode 100644 index 0000000..12598b1 --- /dev/null +++ b/backend/config-templates/nacos/rui-service-pay.yaml @@ -0,0 +1,60 @@ +# rui-service-pay.yaml — 支付服务配置 +# Data ID: rui-service-pay.yaml +# Group: DEFAULT_GROUP +# 功能:支付通道、支付回调、对账 + +# 服务端口:9307(支付服务) +server: + port: 9307 + +# 支付模块配置 +payment: + # 订单超时时间(分钟) + order-timeout: 30 + # 分账延迟时间(天) + split-delay-days: 7 + # 佣金结算周期 + commission-settle-cycle: T+1 + # 通知重试次数 + notify-max-times: 5 + # 通知间隔(秒) + notify-intervals: 15,30,60,300,900 + +# 渠道配置(示例) +payment: + channels: + alipay: + enabled: true + sandbox: true + app-id: ${ALIPAY_APP_ID:} + private-key: ${ALIPAY_PRIVATE_KEY:} + public-key: ${ALIPAY_PUBLIC_KEY:} + notify-url: http://localhost:9307/payment/notify/alipay + wechat_pay: + enabled: true + sandbox: true + app-id: ${WXPAY_APP_ID:} + mch-id: ${WXPAY_MCH_ID:} + api-v3-key: ${WXPAY_API_V3_KEY:} + notify-url: http://localhost:9307/payment/notify/wechat_pay + +# 安全白名单 +security: + oauth2: + ignore-urls: + - /payment/entry/** + - /payment/notify/** + +# Swagger 文档 +springdoc: + swagger-ui: + enabled: true + path: /swagger-ui.html + api-docs: + enabled: true + path: /v3/api-docs + +knife4j: + enable: true + setting: + language: zh_cn diff --git a/backend/config-templates/nacos/rui-service-search.yaml b/backend/config-templates/nacos/rui-service-search.yaml new file mode 100644 index 0000000..46ae7c3 --- /dev/null +++ b/backend/config-templates/nacos/rui-service-search.yaml @@ -0,0 +1,8 @@ +# rui-service-search.yaml — 搜索服务配置 +# Data ID: rui-service-search.yaml +# Group: DEFAULT_GROUP +# 功能:Elasticsearch封装、全文检索 + +# 服务端口:9308(搜索服务) +server: + port: 9308 diff --git a/backend/config-templates/nacos/rui-service-system.yaml b/backend/config-templates/nacos/rui-service-system.yaml new file mode 100644 index 0000000..ba7ad5b --- /dev/null +++ b/backend/config-templates/nacos/rui-service-system.yaml @@ -0,0 +1,33 @@ +# rui-service-system.yaml — 系统服务配置 +# Data ID: rui-service-system.yaml +# Group: DEFAULT_GROUP + +# 服务端口:9302(系统基础服务) +server: + port: 9302 + +# 模块管理配置 +rui: + modules: + # 全局可用模块列表(系统层面定义有哪些模块可选) + available: + - code: system + name: 系统管理 + icon: tabler:settings + - code: user + name: 用户管理 + icon: tabler:users + - code: order + name: 订单管理 + icon: tabler:shopping-cart + - code: cms + name: 内容管理 + icon: tabler:edit + - code: marketing + name: 营销中心 + icon: tabler:present + - code: demo + name: 演示中心 + icon: tabler:device-desktop + # 默认启用模块(新租户默认开启,逗号分隔) + default-enabled: system,user,demo diff --git a/backend/config-templates/nacos/rui-service-user.yaml b/backend/config-templates/nacos/rui-service-user.yaml new file mode 100644 index 0000000..3526f5e --- /dev/null +++ b/backend/config-templates/nacos/rui-service-user.yaml @@ -0,0 +1,7 @@ +# rui-service-user.yaml — 用户基础信息及等级服务配置 +# Data ID: rui-service-user.yaml +# Group: DEFAULT_GROUP + +# 服务端口:9303(用户中心服务) +server: + port: 9303 diff --git a/backend/design/数据库表结构规划.md b/backend/design/数据库表结构规划.md new file mode 100644 index 0000000..3ad3cfe --- /dev/null +++ b/backend/design/数据库表结构规划.md @@ -0,0 +1,664 @@ +# 通用平台框架 — 数据库表结构规划 + +> 基于当前项目分析和通用平台框架最佳实践,列出平台运行所需的全量表结构及归属服务。 +> **注意:本规划仅做设计,不做任何代码实施。** + +--- + +## 一、表结构总览 + +| 服务归属 | 表数量 | 表名前缀 | 说明 | +|---------|--------|---------|------| +| **rui-service-system** | 11 | `sys_` | 系统基础服务(租户/菜单/角色/字典/配置/部门/岗位) | +| **rui-service-user** | 7 | `uc_` | 用户中心服务(用户/详情/等级/角色/部门/岗位/权限) | +| **rui-auth** | 3 | `auth_` | 认证中心(OAuth2客户端/登录日志/操作日志) | +| **rui-gateway** | 2 | `gw_` | 网关服务(路由配置/限流规则) | +| **公共表** | 2 | — | 跨服务使用(文件/消息) | +| **合计** | **25** | | | + +> **命名调整建议**:当前 `rui_xxx` 前缀过长,建议简化为服务简称前缀,如 `sys_`、`uc_`、`auth_`、`gw_`,更简洁专业。 + +--- + +## 二、rui-service-system 系统基础服务(11张表) + +### 2.1 租户管理 + +```sql +-- sys_tenant — 租户(原 rui_system_tenant 改进) +CREATE TABLE sys_tenant ( + id BIGINT NOT NULL, + tenant_code VARCHAR(50) NOT NULL COMMENT '租户编码', + tenant_name VARCHAR(200) NOT NULL COMMENT '租户名称', + tenant_type TINYINT NOT NULL DEFAULT 1 COMMENT '类型 1:企业 2:个人 3:试用', + tenant_level TINYINT NOT NULL DEFAULT 1 COMMENT '等级 1:基础版 2:专业版 3:旗舰版', + logo_url VARCHAR(500) DEFAULT NULL COMMENT 'Logo', + contact_name VARCHAR(100) DEFAULT NULL, + contact_phone VARCHAR(20) DEFAULT NULL, + contact_email VARCHAR(100) DEFAULT NULL, + domains VARCHAR(500) DEFAULT NULL COMMENT '绑定域名(逗号分隔)', + max_user_count INT NOT NULL DEFAULT 100 COMMENT '最大用户数', + expire_time DATETIME DEFAULT NULL COMMENT '过期时间 NULL:永久', + super_admin_id BIGINT DEFAULT NULL COMMENT '超管用户ID', + status TINYINT NOT NULL DEFAULT 1, + deleted TINYINT NOT NULL DEFAULT 0, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_tenant_code (tenant_code), + INDEX idx_status (status) +) COMMENT='租户'; + +-- sys_tenant_package — 租户套餐(新增) +CREATE TABLE sys_tenant_package ( + id BIGINT NOT NULL, + package_code VARCHAR(100) NOT NULL COMMENT '套餐编码', + package_name VARCHAR(200) NOT NULL COMMENT '套餐名称', + max_user_count INT NOT NULL DEFAULT 100, + max_dept_count INT NOT NULL DEFAULT 50, + max_menu_count INT NOT NULL DEFAULT 100, + price DECIMAL(19,4) NOT NULL DEFAULT 0 COMMENT '价格', + duration_days INT NOT NULL DEFAULT 365 COMMENT '时长(天)', + remark VARCHAR(500) DEFAULT NULL, + status TINYINT NOT NULL DEFAULT 1, + deleted TINYINT NOT NULL DEFAULT 0, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_package_code (package_code) +) COMMENT='租户套餐'; +``` + +### 2.2 组织架构 + +```sql +-- sys_dept — 部门(新增) +CREATE TABLE sys_dept ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + parent_id BIGINT NOT NULL DEFAULT 0, + ancestors VARCHAR(500) DEFAULT '' COMMENT '祖级ID列表 如: 0,1,5,', + dept_code VARCHAR(100) NOT NULL COMMENT '部门编码', + dept_name VARCHAR(100) NOT NULL COMMENT '部门名称', + leader_id BIGINT DEFAULT NULL COMMENT '负责人ID', + phone VARCHAR(20) DEFAULT NULL, + email VARCHAR(100) DEFAULT NULL, + sort_no INT NOT NULL DEFAULT 0, + status TINYINT NOT NULL DEFAULT 1, + deleted TINYINT NOT NULL DEFAULT 0, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_dept_code (tenant_id, dept_code), + INDEX idx_parent (parent_id), + INDEX idx_tenant (tenant_id) +) COMMENT='部门'; + +-- sys_post — 岗位(新增) +CREATE TABLE sys_post ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + post_code VARCHAR(100) NOT NULL COMMENT '岗位编码', + post_name VARCHAR(100) NOT NULL COMMENT '岗位名称', + sort_no INT NOT NULL DEFAULT 0, + status TINYINT NOT NULL DEFAULT 1, + deleted TINYINT NOT NULL DEFAULT 0, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_post_code (tenant_id, post_code), + INDEX idx_tenant (tenant_id) +) COMMENT='岗位'; +``` + +### 2.3 菜单与权限 + +```sql +-- sys_menu — 菜单(原 rui_system_menu 改进) +CREATE TABLE sys_menu ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + parent_id BIGINT NOT NULL DEFAULT 0 COMMENT '父菜单ID 0:顶级', + ancestors VARCHAR(500) DEFAULT '' COMMENT '祖级ID列表', + menu_code VARCHAR(100) NOT NULL COMMENT '菜单编码(唯一标识)', + menu_name VARCHAR(100) NOT NULL COMMENT '菜单名称', + menu_type TINYINT NOT NULL DEFAULT 1 COMMENT '类型 1:目录 2:菜单 3:按钮', + icon VARCHAR(100) DEFAULT NULL COMMENT '图标', + path VARCHAR(200) DEFAULT NULL COMMENT '路由路径', + component VARCHAR(200) DEFAULT NULL COMMENT '组件路径', + permission VARCHAR(200) DEFAULT NULL COMMENT '权限标识 如: user:list', + is_external TINYINT NOT NULL DEFAULT 0 COMMENT '是否外链 0:否 1:是', + target VARCHAR(20) DEFAULT '_self' COMMENT '打开方式 _self/_blank', + keep_alive TINYINT NOT NULL DEFAULT 0 COMMENT '是否缓存 0:否 1:是', + visible TINYINT NOT NULL DEFAULT 1 COMMENT '是否显示 0:隐藏 1:显示', + status TINYINT NOT NULL DEFAULT 1, + sort_no INT NOT NULL DEFAULT 0, + remark VARCHAR(500) DEFAULT NULL, + deleted TINYINT NOT NULL DEFAULT 0, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_menu_code (tenant_id, menu_code), + INDEX idx_parent (parent_id), + INDEX idx_ancestors (ancestors(100)), + INDEX idx_tenant (tenant_id) +) COMMENT='菜单'; +``` + +### 2.4 角色管理 + +```sql +-- sys_role — 角色(原 rui_system_role 改进) +CREATE TABLE sys_role ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + parent_id BIGINT NOT NULL DEFAULT 0, + ancestors VARCHAR(500) DEFAULT '' COMMENT '祖级ID列表', + role_code VARCHAR(100) NOT NULL COMMENT '角色编码', + role_name VARCHAR(100) NOT NULL COMMENT '角色名称', + role_type TINYINT NOT NULL DEFAULT 1 COMMENT '类型 1:系统角色 2:租户角色 3:自定义', + data_scope TINYINT NOT NULL DEFAULT 1 COMMENT '数据范围 1:全部 2:本部门 3:本部门及子部门 4:仅本人 5:自定义', + description VARCHAR(500) DEFAULT NULL, + sort_no INT NOT NULL DEFAULT 0, + status TINYINT NOT NULL DEFAULT 1, + deleted TINYINT NOT NULL DEFAULT 0, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_role_code (tenant_id, role_code), + INDEX idx_parent (parent_id), + INDEX idx_tenant (tenant_id) +) COMMENT='角色'; + +-- sys_role_menu — 角色菜单关联(原 rui_system_role_menu 改进) +CREATE TABLE sys_role_menu ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + role_id BIGINT NOT NULL, + menu_id BIGINT NOT NULL, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_role_menu (tenant_id, role_id, menu_id), + INDEX idx_role (role_id), + INDEX idx_menu (menu_id), + INDEX idx_tenant (tenant_id) +) COMMENT='角色菜单关联'; +``` + +### 2.5 数据字典 + +```sql +-- sys_dict_type — 字典类型(新增,拆分原字典表) +CREATE TABLE sys_dict_type ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + dict_code VARCHAR(100) NOT NULL COMMENT '字典编码(唯一标识)', + dict_name VARCHAR(200) NOT NULL COMMENT '字典名称', + description VARCHAR(500) DEFAULT NULL, + status TINYINT NOT NULL DEFAULT 1, + deleted TINYINT NOT NULL DEFAULT 0, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_dict_code (tenant_id, dict_code), + INDEX idx_tenant (tenant_id) +) COMMENT='字典类型'; + +-- sys_dict_item — 字典项(新增,拆分原字典表) +CREATE TABLE sys_dict_item ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + dict_type_id BIGINT NOT NULL COMMENT '字典类型ID', + item_code VARCHAR(100) NOT NULL COMMENT '项编码', + item_label VARCHAR(200) NOT NULL COMMENT '项标签', + item_value VARCHAR(200) NOT NULL COMMENT '项值', + sort_no INT NOT NULL DEFAULT 0, + remark VARCHAR(500) DEFAULT NULL, + status TINYINT NOT NULL DEFAULT 1, + deleted TINYINT NOT NULL DEFAULT 0, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_dict_type_code (tenant_id, dict_type_id, item_code), + INDEX idx_dict_type (dict_type_id), + INDEX idx_tenant (tenant_id) +) COMMENT='字典项'; +``` + +### 2.6 系统配置 + +```sql +-- sys_config — 系统配置(原 rui_system_config 改进) +CREATE TABLE sys_config ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + config_group VARCHAR(100) NOT NULL DEFAULT 'default' COMMENT '配置分组(oss/sms/email)', + config_key VARCHAR(200) NOT NULL COMMENT '配置键', + config_value VARCHAR(2000) NOT NULL COMMENT '配置值', + config_type VARCHAR(20) NOT NULL DEFAULT 'STRING' COMMENT '值类型 STRING/JSON/NUMBER/BOOLEAN/ENCRYPTED', + is_system TINYINT NOT NULL DEFAULT 0 COMMENT '是否系统级 0:租户 1:系统', + is_encrypted TINYINT NOT NULL DEFAULT 0 COMMENT '是否加密 0:明文 1:密文', + description VARCHAR(500) DEFAULT NULL, + sort_no INT NOT NULL DEFAULT 0, + status TINYINT NOT NULL DEFAULT 1, + deleted TINYINT NOT NULL DEFAULT 0, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_config_key (tenant_id, config_key), + INDEX idx_group (config_group), + INDEX idx_tenant (tenant_id) +) COMMENT='系统配置'; +``` + +--- + +## 三、rui-service-user 用户中心服务(7张表) + +### 3.1 用户主体 + +```sql +-- uc_user — 用户主表(原 rui_user_credential + rui_user_info 合并改进) +CREATE TABLE uc_user ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + username VARCHAR(100) NOT NULL COMMENT '用户名', + password VARCHAR(255) NOT NULL COMMENT '密码(BCrypt加密)', + user_type TINYINT NOT NULL DEFAULT 1 COMMENT '用户类型 1:普通用户 2:管理员 3:系统用户', + status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 0:禁用 1:启用', + deleted TINYINT NOT NULL DEFAULT 0, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_username (tenant_id, username), + INDEX idx_tenant (tenant_id) +) COMMENT='用户'; + +-- uc_user_detail — 用户详情表(原 rui_user_info 拆分) +CREATE TABLE uc_user_detail ( + id BIGINT NOT NULL, + user_id BIGINT NOT NULL COMMENT '用户ID', + tenant_id BIGINT NOT NULL DEFAULT 0, + nickname VARCHAR(100) DEFAULT NULL COMMENT '昵称', + real_name VARCHAR(100) DEFAULT NULL COMMENT '真实姓名', + email VARCHAR(100) DEFAULT NULL COMMENT '邮箱', + phone VARCHAR(20) DEFAULT NULL COMMENT '手机号', + avatar VARCHAR(1000) DEFAULT NULL COMMENT '头像URL', + gender TINYINT DEFAULT 0 COMMENT '性别 0:未知 1:男 2:女', + birthday DATE DEFAULT NULL, + id_card VARCHAR(18) DEFAULT NULL COMMENT '身份证号', + address VARCHAR(500) DEFAULT NULL COMMENT '地址', + extra JSON DEFAULT NULL COMMENT '扩展字段(JSON格式)', + remark VARCHAR(500) DEFAULT NULL, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_user_id (user_id), + INDEX idx_tenant (tenant_id) +) COMMENT='用户详情'; +``` + +### 3.2 用户等级 + +```sql +-- uc_user_level — 用户等级定义(原 rui_user_level 改进) +CREATE TABLE uc_user_level ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + level_code VARCHAR(100) NOT NULL COMMENT '等级编码', + level_name VARCHAR(100) NOT NULL COMMENT '等级名称', + level_no INT NOT NULL DEFAULT 1 COMMENT '等级序号(数字越大等级越高)', + min_score INT NOT NULL DEFAULT 0 COMMENT '最低积分要求', + icon VARCHAR(500) DEFAULT NULL COMMENT '等级图标', + benefits JSON DEFAULT NULL COMMENT '权益配置(JSON)', + upgrade_type TINYINT NOT NULL DEFAULT 1 COMMENT '升级方式 1:自动 2:手动审核', + expire_days INT DEFAULT 0 COMMENT '有效期(天) 0:永久', + status TINYINT NOT NULL DEFAULT 1, + sort_no INT NOT NULL DEFAULT 0, + deleted TINYINT NOT NULL DEFAULT 0, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_level_code (tenant_id, level_code), + INDEX idx_tenant (tenant_id) +) COMMENT='用户等级'; + +-- uc_user_level_log — 用户等级变更记录(原 rui_user_level_log 改进) +CREATE TABLE uc_user_level_log ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + user_id BIGINT NOT NULL COMMENT '用户ID', + change_type TINYINT NOT NULL DEFAULT 1 COMMENT '变更类型 1:升级 2:降级 3:手动调整 4:过期', + from_level_id BIGINT DEFAULT NULL COMMENT '原等级ID NULL:初始', + to_level_id BIGINT NOT NULL COMMENT '新等级ID', + score_before INT DEFAULT NULL COMMENT '变更前积分', + score_after INT DEFAULT NULL COMMENT '变更后积分', + reason VARCHAR(500) DEFAULT NULL COMMENT '变更原因', + operator_id BIGINT DEFAULT NULL COMMENT '操作人ID', + operator_type TINYINT NOT NULL DEFAULT 1 COMMENT '操作人类型 1:系统 2:管理员 3:用户', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + INDEX idx_user (user_id), + INDEX idx_tenant (tenant_id) +) COMMENT='用户等级变更记录'; +``` + +### 3.3 用户关联 + +```sql +-- uc_user_role — 用户角色关联(原 rui_user_role 改进) +CREATE TABLE uc_user_role ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + user_id BIGINT NOT NULL, + role_id BIGINT NOT NULL, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_user_role (tenant_id, user_id, role_id), + INDEX idx_user (user_id), + INDEX idx_role (role_id), + INDEX idx_tenant (tenant_id) +) COMMENT='用户角色关联'; + +-- uc_user_dept — 用户部门关联(新增) +CREATE TABLE uc_user_dept ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + user_id BIGINT NOT NULL, + dept_id BIGINT NOT NULL, + is_main TINYINT NOT NULL DEFAULT 1 COMMENT '是否主部门 0:否 1:是', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_user_dept (tenant_id, user_id, dept_id), + INDEX idx_user (user_id), + INDEX idx_dept (dept_id), + INDEX idx_tenant (tenant_id) +) COMMENT='用户部门关联'; + +-- uc_user_post — 用户岗位关联(新增) +CREATE TABLE uc_user_post ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + user_id BIGINT NOT NULL, + post_id BIGINT NOT NULL, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_user_post (tenant_id, user_id, post_id), + INDEX idx_user (user_id), + INDEX idx_post (post_id), + INDEX idx_tenant (tenant_id) +) COMMENT='用户岗位关联'; + +-- uc_user_permission — 用户权限关联(新增,支持直接授权) +CREATE TABLE uc_user_permission ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + user_id BIGINT NOT NULL, + permission VARCHAR(200) NOT NULL COMMENT '权限标识 如: user:list', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_user_permission (tenant_id, user_id, permission), + INDEX idx_user (user_id), + INDEX idx_tenant (tenant_id) +) COMMENT='用户权限关联(直接授权)'; +``` + +--- + +## 四、rui-auth 认证中心(3张表) + +### 4.1 OAuth2 客户端 + +```sql +-- auth_oauth2_client — OAuth2客户端(原 rui_system_oauth2_client 改进) +CREATE TABLE auth_oauth2_client ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + client_id VARCHAR(100) NOT NULL COMMENT '客户端ID', + client_secret VARCHAR(255) DEFAULT NULL COMMENT '客户端密钥', + client_name VARCHAR(200) NOT NULL COMMENT '客户端名称', + client_type TINYINT NOT NULL DEFAULT 1 COMMENT '客户端类型 1:Web 2:App 3:小程序', + logo_url VARCHAR(500) DEFAULT NULL COMMENT 'Logo', + description VARCHAR(500) DEFAULT NULL, + authentication_methods VARCHAR(500) NOT NULL COMMENT '认证方式', + grant_types VARCHAR(500) NOT NULL COMMENT '授权类型', + redirect_uris TEXT DEFAULT NULL COMMENT '回调地址(逗号分隔)', + scopes VARCHAR(500) NOT NULL COMMENT '授权范围', + access_token_ttl INT NOT NULL DEFAULT 7200 COMMENT '访问令牌有效期(秒)', + refresh_token_ttl INT NOT NULL DEFAULT 604800 COMMENT '刷新令牌有效期(秒)', + status TINYINT NOT NULL DEFAULT 1, + deleted TINYINT NOT NULL DEFAULT 0, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_client_id (tenant_id, client_id), + INDEX idx_tenant (tenant_id) +) COMMENT='OAuth2客户端'; +``` + +### 4.2 日志审计 + +```sql +-- auth_login_log — 登录日志(新增) +CREATE TABLE auth_login_log ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + user_id BIGINT DEFAULT NULL, + username VARCHAR(100) DEFAULT NULL, + login_type TINYINT NOT NULL DEFAULT 1 COMMENT '登录类型 1:密码 2:短信 3:微信 4:支付宝', + client_id VARCHAR(100) DEFAULT NULL COMMENT '客户端ID', + ip VARCHAR(128) DEFAULT NULL, + location VARCHAR(255) DEFAULT NULL, + browser VARCHAR(200) DEFAULT NULL, + os VARCHAR(200) DEFAULT NULL, + status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 0:失败 1:成功', + msg VARCHAR(500) DEFAULT NULL COMMENT '消息', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + INDEX idx_user (user_id), + INDEX idx_tenant (tenant_id), + INDEX idx_created (created_at) +) COMMENT='登录日志'; + +-- auth_oper_log — 操作日志(新增) +CREATE TABLE auth_oper_log ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + oper_type TINYINT NOT NULL DEFAULT 1 COMMENT '操作类型 1:新增 2:修改 3:删除 4:查询 5:导出 6:登录 7:登出', + title VARCHAR(200) NOT NULL COMMENT '操作模块', + method VARCHAR(500) DEFAULT NULL COMMENT '请求方法', + request_url VARCHAR(500) DEFAULT NULL COMMENT '请求URL', + request_method VARCHAR(10) DEFAULT NULL COMMENT '请求方式 GET/POST/PUT/DELETE', + request_params TEXT DEFAULT NULL COMMENT '请求参数', + response_data TEXT DEFAULT NULL COMMENT '响应数据', + user_id BIGINT DEFAULT NULL COMMENT '操作用户ID', + user_name VARCHAR(100) DEFAULT NULL COMMENT '操作用户名', + oper_ip VARCHAR(128) DEFAULT NULL COMMENT '操作IP', + oper_location VARCHAR(255) DEFAULT NULL COMMENT '操作地点', + status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 0:失败 1:成功', + error_msg TEXT DEFAULT NULL COMMENT '错误消息', + cost_time BIGINT DEFAULT 0 COMMENT '耗时(ms)', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + INDEX idx_user (user_id), + INDEX idx_tenant (tenant_id), + INDEX idx_created (created_at) +) COMMENT='操作日志'; +``` + +--- + +## 五、rui-gateway 网关服务(2张表) + +```sql +-- gw_route — 路由配置(新增) +CREATE TABLE gw_route ( + id BIGINT NOT NULL, + route_id VARCHAR(100) NOT NULL COMMENT '路由ID', + route_name VARCHAR(200) NOT NULL COMMENT '路由名称', + uri VARCHAR(500) NOT NULL COMMENT '目标URI', + predicates VARCHAR(1000) NOT NULL COMMENT '断言条件(JSON)', + filters VARCHAR(1000) DEFAULT NULL COMMENT '过滤器(JSON)', + sort_no INT NOT NULL DEFAULT 0, + status TINYINT NOT NULL DEFAULT 1, + deleted TINYINT NOT NULL DEFAULT 0, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + UNIQUE KEY uk_route_id (route_id) +) COMMENT='网关路由配置'; + +-- gw_rate_limit — 限流规则(新增) +CREATE TABLE gw_rate_limit ( + id BIGINT NOT NULL, + route_id VARCHAR(100) NOT NULL COMMENT '路由ID', + limit_type TINYINT NOT NULL DEFAULT 1 COMMENT '限流类型 1:IP 2:用户 3:接口', + limit_key VARCHAR(200) NOT NULL COMMENT '限流键', + limit_count INT NOT NULL DEFAULT 100 COMMENT '限流次数', + limit_window INT NOT NULL DEFAULT 60 COMMENT '时间窗口(秒)', + status TINYINT NOT NULL DEFAULT 1, + deleted TINYINT NOT NULL DEFAULT 0, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + INDEX idx_route (route_id) +) COMMENT='网关限流规则'; +``` + +--- + +## 六、公共表(跨服务使用,2张表) + +```sql +-- pub_file — 文件记录(新增) +CREATE TABLE pub_file ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + file_name VARCHAR(255) NOT NULL COMMENT '原始文件名', + file_url VARCHAR(1000) NOT NULL COMMENT '文件访问URL', + file_path VARCHAR(1000) NOT NULL COMMENT '文件存储路径', + file_size BIGINT NOT NULL DEFAULT 0 COMMENT '文件大小(字节)', + file_type VARCHAR(100) DEFAULT NULL COMMENT '文件类型', + storage_type TINYINT NOT NULL DEFAULT 1 COMMENT '存储类型 1:本地 2:OSS 3:MinIO', + module VARCHAR(100) DEFAULT NULL COMMENT '所属模块', + biz_id BIGINT DEFAULT NULL COMMENT '业务ID', + status TINYINT NOT NULL DEFAULT 1, + deleted TINYINT NOT NULL DEFAULT 0, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + INDEX idx_tenant (tenant_id), + INDEX idx_module_biz (module, biz_id) +) COMMENT='文件记录'; + +-- pub_message — 消息记录(新增) +CREATE TABLE pub_message ( + id BIGINT NOT NULL, + tenant_id BIGINT NOT NULL DEFAULT 0, + msg_type TINYINT NOT NULL DEFAULT 1 COMMENT '消息类型 1:短信 2:邮件 3:站内信 4:App推送', + template_code VARCHAR(100) DEFAULT NULL COMMENT '模板编码', + sender VARCHAR(200) DEFAULT NULL COMMENT '发送方', + receiver VARCHAR(500) NOT NULL COMMENT '接收方', + subject VARCHAR(500) DEFAULT NULL COMMENT '主题', + content TEXT NOT NULL COMMENT '内容', + params JSON DEFAULT NULL COMMENT '模板参数(JSON)', + send_status TINYINT NOT NULL DEFAULT 0 COMMENT '发送状态 0:待发送 1:发送中 2:成功 3:失败', + retry_count INT NOT NULL DEFAULT 0 COMMENT '重试次数', + send_time DATETIME DEFAULT NULL COMMENT '发送时间', + result_msg VARCHAR(500) DEFAULT NULL COMMENT '发送结果', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + PRIMARY KEY (id), + INDEX idx_tenant (tenant_id), + INDEX idx_status (send_status), + INDEX idx_created (created_at) +) COMMENT='消息记录'; +``` + +--- + +## 七、表结构变更对照(当前 → 规划) + +| 当前表名 | 规划表名 | 归属服务 | 变更类型 | +|---------|---------|---------|---------| +| rui_system_oauth2_client | auth_oauth2_client | rui-auth | 🔴 迁移 + 重构 | +| rui_system_tenant | sys_tenant | rui-service-system | 🟡 重构 | +| rui_user_credential | uc_user | rui-service-user | 🔴 合并拆分 | +| rui_user_info | uc_user_detail | rui-service-user | 🔴 合并拆分 | +| rui_user_level | uc_user_level | rui-service-user | 🟡 重构 | +| rui_user_level_log | uc_user_level_log | rui-service-user | 🟡 重构 | +| rui_user_role | uc_user_role | rui-service-user | 🟡 重构 | +| rui_system_menu | sys_menu | rui-service-system | 🟡 重构 | +| rui_system_role | sys_role | rui-service-system | 🟡 重构 | +| rui_system_role_menu | sys_role_menu | rui-service-system | 🟡 重构 | +| rui_system_dict | sys_dict_type + sys_dict_item | rui-service-system | 🔴 拆分 | +| rui_system_config | sys_config | rui-service-system | 🟡 重构 | +| — | sys_tenant_package | rui-service-system | 🟢 新增 | +| — | sys_dept | rui-service-system | 🟢 新增 | +| — | sys_post | rui-service-system | 🟢 新增 | +| — | uc_user_dept | rui-service-user | 🟢 新增 | +| — | uc_user_post | rui-service-user | 🟢 新增 | +| — | uc_user_permission | rui-service-user | 🟢 新增 | +| — | auth_login_log | rui-auth | 🟢 新增 | +| — | auth_oper_log | rui-auth | 🟢 新增 | +| — | gw_route | rui-gateway | 🟢 新增 | +| — | gw_rate_limit | rui-gateway | 🟢 新增 | +| — | pub_file | 公共 | 🟢 新增 | +| — | pub_message | 公共 | 🟢 新增 | + +--- + +## 八、表前缀规则(新增) + +| 前缀 | 归属服务 | 说明 | +|------|---------|------| +| `sys_` | rui-service-system | 系统基础表(租户/部门/岗位/菜单/角色/字典/配置) | +| `uc_` | rui-service-user | 用户中心表(用户/详情/等级/角色/部门/岗位关联) | +| `auth_` | rui-auth | 认证授权表(OAuth2客户端/登录日志/操作日志) | +| `gw_` | rui-gateway | 网关表(路由/限流) | +| `pub_` | 公共 | 跨服务公共表(文件/消息) | +| `biz_` | 业务服务 | 业务应用模块表(如 biz_order, biz_pay) | + +--- + +## 九、Entity 设计规则(新增) + +### 9.1 必须继承 BaseEntity + +```java +@Data +@EqualsAndHashCode(callSuper = true) +public class User extends BaseEntity { + // 业务字段 +} +``` + +### 9.2 @TableName 命名规则 + +```java +// ✅ 正确:不包含前缀,与全局配置 table-prefix 配合 +@TableName(value = "user", keepGlobalPrefix = true) +// 实际表名: rui_user(当前)或 uc_user(建议调整后) + +// ❌ 错误:硬编码前缀,或前缀与配置不一致 +@TableName(value = "auth_user", keepGlobalPrefix = true) +// 实际表名: rui_auth_user(与 SQL 不一致) +``` + +### 9.3 主键策略统一 + +```java +// ✅ 统一使用 ASSIGN_ID(雪花算法) +@TableId(type = IdType.ASSIGN_ID) +private Long id; + +// ❌ 不要混用 AUTO +@TableId(type = IdType.AUTO) // 错误! +``` + +--- + +> **文档版本**: v1.0 +> **创建日期**: 2026-05-28 +> **适用范围**: spring-ai 项目数据库设计 +> **状态**: 仅规划,未实施 diff --git a/backend/guides/AI开发环境配置手册.md b/backend/guides/AI开发环境配置手册.md new file mode 100644 index 0000000..a068662 --- /dev/null +++ b/backend/guides/AI开发环境配置手册.md @@ -0,0 +1,388 @@ +# AI 开发环境配置手册 + +> **适用对象**: 业务模块开发者(支付、收银台等) +> **版本**: v1.0 +> **更新日期**: 2026-06-03 + +--- + +## 目录 + +1. [概述](#一概述) +2. [环境准备](#二环境准备) +3. [仓库克隆与配置](#三仓库克隆与配置) +4. [GitNexus 索引配置](#四gitnexus-索引配置) +5. [AI 开发工作流](#五ai-开发工作流) +6. [常见问题](#六常见问题) + +--- + +## 一、概述 + +### 1.1 背景 + +项目已拆分为独立仓库: + +| 仓库 | 地址 | 用途 | 负责人 | +|------|------|------|--------| +| `rui-framework` | `git@gitee.com:pigeon/rui-framework.git` | 框架(backend) | 框架维护者 | +| `rui-payment` | `git@gitee.com:pigeon/rui-payment.git` | 支付模块 | 员工A | +| `rui-cashier` | `git@gitee.com:pigeon/rui-cashier.git` | 收银台模块 | 员工B | + +业务开发者**只需要**维护自己的业务仓库,框架依赖通过 Maven 仓库自动下载。 + +### 1.2 为什么需要本地 clone 框架仓库? + +AI(OpenCode)基于 GitNexus 知识图谱工作: + +- **业务代码索引**:理解业务逻辑、生成业务代码 +- **框架代码索引**:理解框架 API(如 `AuthUtil`、`BizException`) + +框架代码以 **jar 包** 形式通过 Maven 引入,AI 无法直接解析 jar 中的 class 文件。因此需要在本地 clone 框架仓库作为**只读参考**,供 AI 索引和查询。 + +--- + +## 二、环境准备 + +### 2.1 基础工具 + +| 工具 | 最低版本 | 验证命令 | 说明 | +|------|---------|---------|------| +| JDK | 21 | `java -version` | 必须 | +| Maven | 3.9 | `mvn -version` | 必须 | +| Git | 2.40 | `git --version` | 必须 | +| Node.js | 18 | `node --version` | GitNexus 需要 | + +### 2.2 配置 Maven 仓库 + +确保 `~/.m2/settings.xml` 已配置公司 Nexus 仓库认证(向运维获取): + +```xml + + + + releases + your-username + your-password + + + snapshots + your-username + your-password + + + +``` + +> **注意**:框架 `rui-parent` 和 `rui-common-*` 已发布到 Nexus,首次编译时会自动下载。 + +--- + +## 三、仓库克隆与配置 + +### 3.1 目录结构 + +``` +~/work/ +├── rui-framework/ # 框架仓库(只读参考) +│ ├── backend/ +│ └── .gitnexus/ # 框架代码索引 +└── rui-payment/ # 业务仓库(主要工作区) + ├── pom.xml + ├── rui-payment-api/ + └── .gitnexus/ # 业务代码索引 +``` + +### 3.2 克隆仓库 + +**步骤1:克隆框架仓库(所有员工都需要)** + +```bash +git clone git@gitee.com:pigeon/rui-framework.git ~/work/rui-framework +``` + +**步骤2:克隆业务仓库** + +```bash +# 员工A(支付) +git clone git@gitee.com:pigeon/rui-payment.git ~/work/rui-payment + +# 员工B(收银台) +git clone git@gitee.com:pigeon/rui-cashier.git ~/work/rui-cashier +``` + +### 3.3 验证编译 + +```bash +cd ~/work/rui-payment +mvn clean compile -DskipTests +``` + +预期输出:`BUILD SUCCESS` + +如果报错找不到 `rui-parent`,联系框架维护者确认已发布到 Nexus。 + +--- + +## 四、GitNexus 索引配置 + +### 4.1 什么是 GitNexus? + +GitNexus 是 AI 的代码智能引擎,通过索引代码库构建知识图谱,帮助 AI: +- 理解代码结构(类、方法、调用关系) +- 分析修改影响(改 A 会波及 B、C) +- 安全导航(不重命名、不遗漏引用) + +### 4.2 索引框架仓库 + +```bash +cd ~/work/rui-framework +npx gitnexus analyze +``` + +预期输出: +``` +Repository indexed successfully +7,504 nodes | 15,350 edges | 268 clusters | 300 flows +``` + +### 4.3 索引业务仓库 + +```bash +cd ~/work/rui-payment +npx gitnexus analyze +``` + +预期输出: +``` +Repository indexed successfully +1,601 nodes | 3,921 edges | 63 clusters | 131 flows +``` + +### 4.4 验证索引 + +```bash +npx gitnexus list +``` + +预期输出: +``` + Indexed Repositories (2) + + spring-ai + Path: ~/work/rui-framework + Stats: 7504 symbols, 15350 edges + + rui-payment + Path: ~/work/rui-payment + Stats: 1601 symbols, 3921 edges +``` + +### 4.5 索引维护 + +| 场景 | 操作 | +|------|------| +| 业务代码修改后 | `cd ~/work/rui-payment && npx gitnexus analyze` | +| 框架升级后 | `cd ~/work/rui-framework && git pull && npx gitnexus analyze` | +| 索引损坏 | `npx gitnexus clean && npx gitnexus analyze` | +| 检查状态 | `npx gitnexus status` | + +--- + +## 五、AI 开发工作流 + +### 5.1 启动 AI + +在**业务仓库**目录下启动 IDE/OpenCode: + +```bash +cd ~/work/rui-payment +# 启动 IDE 或 OpenCode +``` + +AI 默认使用当前目录的索引(`rui-payment`)。 + +### 5.2 开发业务代码(默认模式) + +AI 自动基于 `rui-payment` 索引工作: + +``` +用户:帮我写一个订单查询接口 +AI:基于 rui-payment 索引分析... + 生成 OrderController、OrderService、OrderMapper +``` + +### 5.3 查询框架 API(跨仓库模式) + +当需要理解框架源码时,在对话中指定 `repo` 参数: + +**查询类定义:** +``` +gitnexus_context({ + name: "AuthUtil", + repo: "spring-ai" +}) +``` + +**搜索功能实现:** +``` +gitnexus_query({ + query: "分布式锁 Redisson", + repo: "spring-ai" +}) +``` + +**分析修改影响:** +``` +gitnexus_impact({ + target: "BaseController", + repo: "spring-ai", + direction: "upstream" +}) +``` + +**查看执行流程:** +``` +gitnexus_query({ + query: "用户登录认证流程", + repo: "spring-ai" +}) +``` + +### 5.4 常用查询对照表 + +| 我想查... | 命令 | 仓库 | +|-----------|------|------| +| `AuthUtil.getUserId()` 怎么用 | `gitnexus_context({name:"AuthUtil", repo:"spring-ai"})` | framework | +| 业务异常怎么抛 | `gitnexus_query({query:"BizException", repo:"spring-ai"})` | framework | +| 分布式锁怎么加 | `gitnexus_query({query:"Redisson分布式锁", repo:"spring-ai"})` | framework | +| 支付订单状态流转 | `gitnexus_query({query:"订单状态", repo:"rui-payment"})` | payment | +| 修改订单会影响哪里 | `gitnexus_impact({target:"OrderService", direction:"upstream"})` | payment | +| 收银台缓存策略 | `gitnexus_query({query:"缓存 CacheKeys", repo:"rui-cashier"})` | cashier | + +### 5.5 工作流示例 + +**场景:开发一个支付退款接口** + +``` +1. 员工A在 ~/work/rui-payment 中启动 AI + +2. 员工:帮我写退款接口 + AI基于 rui-payment 索引分析业务代码... + +3. 员工:退款时需要校验用户权限吗? + AI:建议调用 AuthUtil.getUserId()... + +4. 员工:AuthUtil 有哪些方法? + 【AI执行】gitnexus_context({name:"AuthUtil", repo:"spring-ai"}) + AI:AuthUtil 提供 getUserId()、getTenantId()、getUser()... + +5. 员工:退款金额用 BigDecimal 吗? + 【AI执行】gitnexus_query({query:"金额计算 BigDecimal", repo:"spring-ai"}) + AI:框架规范要求金额使用 DECIMAL(19,4),Java 对应 BigDecimal... + +6. AI 生成完整代码 +``` + +--- + +## 六、常见问题 + +### Q1:AI 提示 "Index is stale" + +**原因**:代码已修改但索引未更新。 +**解决**: +```bash +cd ~/work/你的仓库 +npx gitnexus analyze +``` + +### Q2:查询框架代码时提示 "Repo not found" + +**原因**:框架仓库未索引或索引名称不对。 +**解决**: +```bash +# 查看所有索引 +npx gitnexus list + +# 确认 spring-ai 存在 +# 如果不存在,重新索引框架仓库 +cd ~/work/rui-framework +npx gitnexus analyze +``` + +### Q3:编译时找不到 rui-parent + +**原因**:框架未发布到 Nexus,或 Maven 仓库配置错误。 +**解决**: +1. 确认 `~/.m2/settings.xml` 已配置 Nexus 认证 +2. 联系框架维护者确认已执行 `mvn clean deploy` +3. 临时方案:本地 clone framework 后执行 `mvn clean install -DskipTests` + +### Q4:框架升级后 AI 给出的 API 已过时 + +**原因**:框架索引未更新。 +**解决**: +```bash +cd ~/work/rui-framework +git pull origin main +npx gitnexus analyze +``` + +### Q5:发现框架代码有 Bug + +**禁止**:直接修改 `~/work/rui-framework` 代码。 +**正确做法**: +1. 在业务仓库记录:`docs/框架问题记录.md` +2. 通知框架维护者 +3. 等待框架修复并发布新版本 + +### Q6:AI 回答中引用了不存在的框架类 + +**原因**:业务仓库依赖的框架版本与本地索引的框架版本不一致。 +**解决**: +1. 检查 `pom.xml` 中 parent version(如 `1.0.0`) +2. 确认 `~/work/rui-framework` 的代码版本一致 +3. 如果不一致,更新 framework clone 并重新索引 + +--- + +## 附录 + +### A. 各仓库索引名称 + +| 仓库路径 | 索引名称 | 说明 | +|----------|----------|------| +| `~/work/rui-framework` | `spring-ai` | 基于 pom.xml artifactId | +| `~/work/rui-payment` | `rui-payment` | 基于目录名 | +| `~/work/rui-cashier` | `rui-cashier` | 基于目录名 | + +### B. 快速命令速查 + +```bash +# 克隆所有仓库(新员工一次性执行) +git clone git@gitee.com:pigeon/rui-framework.git ~/work/rui-framework +git clone git@gitee.com:pigeon/rui-payment.git ~/work/rui-payment + +# 初始化索引(一次性执行) +cd ~/work/rui-framework && npx gitnexus analyze +cd ~/work/rui-payment && npx gitnexus analyze + +# 日常开发 +mvn clean install -DskipTests + +# 更新索引 +npx gitnexus analyze +``` + +### C. 相关文档 + +| 文档 | 路径 | +|------|------| +| GitNexus 使用指南 | `docs/gitnexus-guide.md` | +| 环境搭建指南 | `docs/environment-setup.md` | +| 项目规范 | `AGENTS.md` | + +--- + +> **提示**:本手册随项目演进持续更新。如有问题,联系框架维护者或技术负责人。 diff --git a/backend/guides/Nacos配置管理规范.md b/backend/guides/Nacos配置管理规范.md new file mode 100644 index 0000000..b7e4060 --- /dev/null +++ b/backend/guides/Nacos配置管理规范.md @@ -0,0 +1,120 @@ +# Nacos 配置管理规范 + +## 1. 配置分类 + +| 配置类型 | 文件位置 | 是否推送 Nacos | 说明 | +|---------|---------|--------------|------| +| **本地开发配置** | `config/application-dev.yml` | ❌ 不推送 | 本地环境专属,已加入 `.gitignore` | +| **Nacos 配置文件** | `docs/nacos/*.yaml` | ✅ **必须推送** | 所有服务的 Nacos 配置源文件 | +| **应用模板** | `docs/application-template.yml` | ❌ 不推送 | 新建模块的模板,不直接推送 | + +## 2. 核心规则 + +### 规则 1:修改必须推送 + +**除 `config/application-dev.yml` 外,任何对 `docs/nacos/*.yaml` 的修改必须推送至 Nacos 服务器。** + +> ⚠️ **禁止行为**:只修改本地文件不推送。这会导致: +> - 本地测试正常,线上环境异常 +> - 多人协作时配置不同步 +> - 生产环境使用旧配置,引发故障 + +### 规则 2:统一推送脚本 + +使用根目录 `push-nacos-config.sh` 统一推送: + +```bash +# 推送所有配置(推荐,确保所有配置同步) +bash push-nacos-config.sh + +# 只推送单个配置(快速修复时) +bash push-nacos-config.sh rui-common.yaml +``` + +### 规则 3:推送前检查清单 + +推送前请确认: +- [ ] 配置文件语法正确(YAML 格式) +- [ ] 敏感信息使用 `${}` 环境变量注入,不硬编码 +- [ ] 端口配置与 `项目实施规范.md` 一致 +- [ ] 修改内容已 git commit + +### 规则 4:推送后验证 + +推送后必须验证配置是否生效: + +```bash +# 1. 查看 Nacos 控制台确认配置已更新 +# 2. 重启对应服务使配置生效 +# 3. 检查服务日志确认配置加载成功 +``` + +## 3. 配置文件说明 + +### 3.1 公共配置(rui-common.yaml) + +| 配置项 | 说明 | 示例 | +|--------|------|------| +| `spring.data.redis` | Redis 连接配置 | host、port、password | +| `spring.jackson` | JSON 序列化配置 | date-format、time-zone | +| `security.oauth2.ignore-urls` | 免认证 URL 白名单 | `/entry/**`、`/actuator/**` | +| `feign.providers` | Feign 服务名映射 | user、system、auth | + +### 3.2 数据配置(rui-data.yaml) + +| 配置项 | 说明 | +|--------|------| +| `spring.datasource` | MySQL + Druid 连接池配置 | +| `mybatis-plus` | MyBatis Plus 全局配置 | + +### 3.3 网关配置(rui-gateway.yaml) + +| 配置项 | 说明 | +|--------|------| +| `spring.cloud.gateway.routes` | 路由规则 | +| `grayscale` | 灰度发布规则 | + +### 3.4 服务专属配置(rui-service-*.yaml) + +| 配置项 | 说明 | +|--------|------| +| `server.port` | 服务端口 | + +## 4. 命名空间与分组 + +| 环境 | 命名空间 | Group | +|------|---------|-------| +| 开发环境 | `rui-dev` | `DEFAULT_GROUP` | +| 测试环境 | `rui-test` | `DEFAULT_GROUP` | +| 生产环境 | `rui-prod` | `DEFAULT_GROUP` | + +> 推送脚本默认使用 `rui-dev`,生产环境推送需手动指定命名空间。 + +## 5. 常见问题 + +### Q1: 为什么修改了本地配置但服务没变化? + +> 因为 Spring Cloud 应用启动时会从 Nacos 拉取配置,**本地修改不影响运行中的服务**。必须推送至 Nacos 后重启服务才能生效。 + +### Q2: 可以同时修改多个配置吗? + +> 可以,但建议每次只修改一个配置文件,避免推送时出错难以排查。 + +### Q3: 推送失败怎么办? + +> 检查以下几点: +> 1. Nacos 服务器是否可访问(`http://192.168.31.210:8848`) +> 2. 用户名密码是否正确(默认 nacos/nacos) +> 3. 命名空间是否存在(rui-dev) +> 4. YAML 格式是否正确(缩进、特殊字符等) + +### Q4: 如何回滚配置? + +> Nacos 控制台支持配置历史版本回滚,或手动将旧配置内容重新推送。 + +## 6. 最佳实践 + +1. **先修改本地文件** → **测试验证** → **git commit** → **推送 Nacos** → **重启服务** +2. 多人协作时,推送前先看一眼 Nacos 控制台的当前配置,避免覆盖他人修改 +3. 生产环境配置修改建议先修改测试环境验证,再同步到生产 +4. 定期备份 Nacos 配置(导出为文件存档) diff --git a/backend/guides/Resilience4j-ThreadPoolBulkhead-租户上下文传播问题排查指南.md b/backend/guides/Resilience4j-ThreadPoolBulkhead-租户上下文传播问题排查指南.md new file mode 100644 index 0000000..592e12a --- /dev/null +++ b/backend/guides/Resilience4j-ThreadPoolBulkhead-租户上下文传播问题排查指南.md @@ -0,0 +1,413 @@ +# Resilience4j ThreadPoolBulkhead 租户上下文跨线程传播问题排查指南 + +> **适用场景**:Spring Cloud + OpenFeign + Resilience4j(ThreadPoolBulkhead)+ TransmittableThreadLocal(TTL) + +--- + +## 1. 问题现象 + +### 1.1 典型日志特征 + +``` +# HTTP 线程正确设置了租户上下文 +[nio-9301-exec-3] GlobalContextFilter : 租户上下文已设置: tenantId=5 + +# Feign 调用线程(线程池线程)却读取到错误的租户 ID +[pool-5-thread-1] OAuthRequestInterceptor : Feign 透传租户 ID: tenantId=4 + +# 后续请求无论 X-Tenant-Id 是多少,线程池线程始终返回第一次的 tenantId=4 +[nio-9301-exec-4] GlobalContextFilter : 租户上下文已设置: tenantId=51 +[pool-5-thread-1] OAuthRequestInterceptor : Feign 透传租户 ID: tenantId=4 ← 仍然是 4! +``` + +### 1.2 核心特征 + +| 现象 | 说明 | +|------|------| +| HTTP 线程上下文正确 | `TenantContextHolder.getTenantId()` 在 Controller/Filter 中返回正确值 | +| 线程池线程上下文错误 | Feign 拦截器或 Service 中读取到旧值或 `null` | +| 旧值具有"粘性" | 线程池线程复用后,始终残留第一次被创建时的上下文值 | +| 与请求头不一致 | 请求头 `X-Tenant-Id` 变化,但业务线程读取的值不变 | + +--- + +## 2. 问题根因 + +### 2.1 架构背景 + +本项目使用以下技术栈: + +- **租户上下文**:`TenantContextHolder` 基于 `TransmittableThreadLocal`(TTL)实现 +- **服务间调用**:OpenFeign + Spring Cloud LoadBalancer +- **熔断隔离**:Spring Cloud Circuit Breaker + Resilience4j `ThreadPoolBulkhead` +- **线程池隔离目的**:限制并发数,防止故障扩散 + +### 2.2 线程切换链路(关键!) + +当 Feign 调用触发 Circuit Breaker + ThreadPoolBulkhead 时,一次请求会经历 **三层线程**: + +``` +┌─────────────────┐ ┌─────────────────────────┐ ┌─────────────────────────┐ +│ HTTP 线程 │ │ ThreadPoolBulkhead 线程 │ │ CircuitBreakerFactory │ +│ [nio-9301-exec] │ ──▶ │ [bulkhead-xxx-thread] │ ──▶ │ ExecutorService 线程 │ +│ │ │ │ │ [pool-N-thread-M] │ +└─────────────────┘ └─────────────────────────┘ └─────────────────────────┘ + │ │ │ + │ ① TTL 自动透传 │ ② ContextPropagator 恢复 │ ③ ??? 上下文丢失 + │ (原生 ThreadLocal │ (Resilience4j 官方机制) │ + │ 不跨线程池) │ │ + │ │ │ + tenantId=5 tenantId=5 ✓ tenantId=4 ✗ +``` + +### 2.3 为什么 ContextPropagator 不够? + +Resilience4j 提供了 `ContextPropagator` 接口,官方设计目的是在 **ThreadPoolBulkhead 线程池** 内透传上下文: + +- `retrieve()`:在调用方线程捕获上下文值 +- `copy()`:在线程池线程恢复上下文值 +- `clear()`:在线程池线程清理上下文值 + +**但 Spring Cloud Circuit Breaker 内部还有一层线程池!** + +查看 `Resilience4JCircuitBreaker.run()` 源码: + +```java +if (executorService != null) { + // ① 先把任务提交到工厂自己的 ExecutorService(newCachedThreadPool) + Supplier> futureSupplier = () -> executorService.submit(toRun::get); + + // ② 再用 ThreadPoolBulkhead 包装 Future 等待逻辑 + Callable bulkheadCall = bulkheadProvider.decorateCallable(..., timeLimitedCall); + ... +} +``` + +**执行流程变成了:** + +1. HTTP 线程提交任务 → `ThreadPoolBulkhead` 线程池 +2. `ThreadPoolBulkhead` 线程执行 `ContextPropagator.copy()` → 恢复 `tenantId=5` +3. `ThreadPoolBulkhead` 线程调用 `executorService.submit(toRun::get)` → 提交到 **第二个线程池** +4. `executorService` 线程(`pool-5-thread-1`)执行 Feign 调用 +5. `executorService` 线程 **没有** 经过 `ContextPropagator` 恢复,其 `ThreadLocal` 为 `null` +6. 但由于 `TransmittableThreadLocal` 继承 `InheritableThreadLocal`,线程创建时可能继承了父线程的值,且 **永不清理**,导致旧值残留 + +### 2.4 为什么旧值有"粘性"? + +`Resilience4JCircuitBreakerFactory` 默认使用 `Executors.newCachedThreadPool()`: + +- 线程创建时继承父线程(`ThreadPoolBulkhead` 线程)的 `InheritableThreadLocal` +- 线程被缓存复用,永不销毁(空闲 60 秒) +- **没有人清理** `executorService` 线程的 `ThreadLocal` +- 因此该线程永远携带第一次被创建时的 `tenantId` + +--- + +## 3. 排查思路(按优先级) + +### Step 1:确认问题范围 + +检查日志中 Feign 调用所在的线程名: + +``` +# 如果是 ThreadPoolBulkhead 线程,命名类似: +[bulkhead-xxx-1] + +# 如果是 Spring 默认线程池,命名类似: +[pool-5-thread-1] +``` + +如果看到 `[pool-N-thread-M]`,说明问题在 **第二层线程切换**。 + +### Step 2:确认 ContextPropagator 是否生效 + +在 `TenantContextPropagator` 的 `retrieve()` / `copy()` / `clear()` 方法中加日志: + +```java +@Override +public Supplier> retrieve() { + return () -> { + Long tenantId = TenantContextHolder.getTenantId(); + log.info("[ContextPropagator] retrieve: tenantId={} in thread={}", + tenantId, Thread.currentThread().getName()); + ... + }; +} +``` + +- 如果 `retrieve()` 日志不打印 → `ContextPropagator` 未被注册到 ThreadPoolBulkheadConfig +- 如果 `copy()` 打印的线程名是 `[pool-N-thread-M]` → `ContextPropagator` 被用在了错误的线程池上(本不应出现) + +### Step 3:确认是否存在多层线程池 + +在 `OAuthRequestInterceptor` 中加日志: + +```java +Long tenantId = TenantContextHolder.getTenantId(); +log.info("[Feign] 当前线程={}, tenantId={}", Thread.currentThread().getName(), tenantId); +``` + +对比 HTTP 线程的 `tenantId` 和 Feign 线程的 `tenantId`: + +| HTTP 线程 | Feign 线程 | 结论 | +|-----------|-----------|------| +| 5 | 5 | 正常 | +| 5 | null | 上下文完全丢失 | +| 5 | 4 | 旧值残留(本文档描述的问题) | +| 5 | 51(上一次的值)| 线程复用且未清理 | + +### Step 4:检查 ThreadPoolBulkheadConfig 配置 + +断点或日志打印 `ThreadPoolBulkheadConfig.getContextPropagator()`: + +```java +ThreadPoolBulkheadConfig config = threadPoolBulkheadRegistry.getDefaultConfig(); +log.info("配置中的 ContextPropagator: {}", config.getContextPropagator()); +``` + +- 如果为空列表 → 配置未生效 +- 如果有 `TenantContextPropagator` → 配置已生效,但只能解决第一层线程切换 + +--- + +## 4. 完整修复方案 + +### 4.1 方案概览 + +需要 **三个层面的修复** 协同工作: + +| 层面 | 修复目标 | 组件 | +|------|---------|------| +| 第一层 | HTTP 线程 → ThreadPoolBulkhead 线程 | `TenantContextPropagator` + `TenantContextThreadPoolBulkheadConfigCustomizer` | +| 第二层 | ThreadPoolBulkhead 线程 → ExecutorService 线程 | `TtlExecutors` + `TtlResilience4JCircuitBreakerFactoryCustomizer` | +| 注册层 | Feign 客户端被 Spring 正确扫描 | `META-INF/spring.factories` 注册 Feign 接口 | + +### 4.2 第一层:ThreadPoolBulkhead 内上下文传播 + +**组件**:`TenantContextPropagator`(已存在)+ `TenantContextThreadPoolBulkheadConfigCustomizer`(新增 BeanPostProcessor) + +**原理**: +- Resilience4j `ThreadPoolBulkhead` 内部使用 `ContextPropagator.decorateSupplier()` 包装任务 +- 在任务提交时 `retrieve()` 捕获上下文,在线程池线程执行前 `copy()` 恢复,执行后 `clear()` 清理 + +**实现要点**: +- `TenantContextThreadPoolBulkheadConfigCustomizer` 实现 `BeanPostProcessor` +- 在 `ThreadPoolBulkheadRegistry` 初始化后,通过反射修改其默认配置,注入 `TenantContextPropagator` +- 不能使用 `AbstractRegistry.addConfiguration("default", config)`,因为该方法禁止修改 `"default"` 键 +- 必须直接修改内部的 `configurations` Map + +```java +public class TenantContextThreadPoolBulkheadConfigCustomizer implements BeanPostProcessor { + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) { + if (bean instanceof ThreadPoolBulkheadRegistry registry) { + injectContextPropagator(registry); + } + return bean; + } + + @SuppressWarnings("unchecked") + private void injectContextPropagator(ThreadPoolBulkheadRegistry registry) { + try { + Field configurationsField = AbstractRegistry.class.getDeclaredField("configurations"); + configurationsField.setAccessible(true); + Map configurations = + (Map) configurationsField.get(registry); + + ThreadPoolBulkheadConfig defaultConfig = configurations.get("default"); + if (defaultConfig == null || hasTenantPropagator(defaultConfig)) { + return; + } + + ThreadPoolBulkheadConfig newDefaultConfig = ThreadPoolBulkheadConfig.from(defaultConfig) + .contextPropagator(TenantContextPropagator.class) + .build(); + configurations.put("default", newDefaultConfig); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new IllegalStateException("无法修改 ThreadPoolBulkheadRegistry 的默认配置", e); + } + } +} +``` + +**注册为 Spring Bean**(注意用 `static` 方法避免 BeanPostProcessor 警告): + +```java +@Bean +@ConditionalOnMissingBean +public static TenantContextThreadPoolBulkheadConfigCustomizer tenantContextThreadPoolBulkheadConfigCustomizer() { + return new TenantContextThreadPoolBulkheadConfigCustomizer(); +} +``` + +### 4.3 第二层:CircuitBreakerFactory ExecutorService 上下文传播 + +**组件**:`TtlResilience4JCircuitBreakerFactoryCustomizer`(新增 Customizer) + +**原理**: +- 使用 Alibaba `TtlExecutors` 包装 `ExecutorService` +- `TtlExecutors` 在 `submit()` 时自动捕获当前线程的 `TransmittableThreadLocal` 值 +- 在目标线程执行前自动恢复,执行后自动清理 +- 支持线程池复用场景,无旧值残留 + +**实现**: + +```java +public class TtlResilience4JCircuitBreakerFactoryCustomizer + implements Customizer { + + @Override + public void customize(Resilience4JCircuitBreakerFactory factory) { + factory.configureExecutorService( + TtlExecutors.getTtlExecutorService(Executors.newCachedThreadPool()) + ); + factory.configureGroupExecutorService( + group -> TtlExecutors.getTtlExecutorService(Executors.newCachedThreadPool()) + ); + } +} +``` + +**注册为 Spring Bean**: + +```java +@Bean +@ConditionalOnMissingBean +public static TtlResilience4JCircuitBreakerFactoryCustomizer ttlResilience4JCircuitBreakerFactoryCustomizer() { + return new TtlResilience4JCircuitBreakerFactoryCustomizer(); +} +``` + +### 4.4 第三层:Feign 客户端注册 + +**组件**:`META-INF/spring.factories` + +**原理**: +- 本项目使用自定义的 `CustomFeignClientsRegistrar` 注册 Feign 客户端 +- `CustomFeignClientsRegistrar` 从 `SpringFactoriesLoader.loadFactoryNames(CloudFeignAutoConfiguration.class, classLoader)` 加载 Feign 接口类名 +- 如果 Feign 接口未在 `spring.factories` 中注册,Spring 容器中不会出现该 Bean,导致 `NoSuchBeanDefinitionException` + +**实现**: + +在定义 Feign 接口的模块(如 `rui-common-security`)新增 `META-INF/spring.factories`: + +```properties +com.rui.common.feign.CloudFeignAutoConfiguration=\ + com.rui.common.security.feign.TokenManageFeign +``` + +### 4.5 模块依赖关系 + +确保 `rui-common-security` 添加 `rui-common-feign` 依赖: + +```xml + + com.rui + rui-common-feign + +``` + +否则 `spring.factories` 中引用的 `CloudFeignAutoConfiguration` 类在编译期不可见。 + +--- + +## 5. 验证方法 + +### 5.1 本地验证 + +1. 启动 `rui-auth` 和 `rui-service-system` +2. 发送第一次请求:`X-Tenant-Id: 5` +3. 观察 Feign 调用日志,确认 `tenantId=5` +4. 发送第二次请求:`X-Tenant-Id: 51` +5. 观察 Feign 调用日志,确认 `tenantId=51`(不是 5) +6. 发送第三次请求:`X-Tenant-Id: 3` +7. 观察 Feign 调用日志,确认 `tenantId=3`(不是 5 也不是 51) + +### 5.2 关键日志断言 + +```java +// 断言:HTTP 线程和 Feign 线程的 tenantId 必须一致 +assertEquals("HTTP 线程和 Feign 线程的租户 ID 必须一致", + httpTenantId, feignTenantId); + +// 断言:每次请求的 tenantId 必须不同(如果请求头不同) +assertNotEquals("线程池线程不应残留旧租户 ID", + previousTenantId, currentTenantId); +``` + +### 5.3 断点验证 + +在以下位置打断点,单步跟踪: + +1. `TenantContextPropagator.retrieve()` — 确认每次请求捕获的值不同 +2. `TenantContextPropagator.copy()` — 确认在线程池线程恢复的值正确 +3. `TtlExecutors` 内部 — 确认 `executorService` 线程恢复的值正确 +4. `OAuthRequestInterceptor` — 确认最终 Feign 调用时的值正确 + +--- + +## 6. 常见问题 FAQ + +### Q1:为什么 YAML 中配置 `resilience4j.thread-pool-bulkhead.configs.default.contextPropagators` 不生效? + +**A**:该配置依赖 Spring Boot `ConfigurationProperties` 绑定 `Class[]` 类型。虽然 `CommonThreadPoolBulkheadConfigurationProperties` 支持该属性,但: + +1. Spring Cloud Circuit Breaker 动态创建的 Bulkhead 实例名不确定 +2. `CompositeCustomizer` 按实例名精确匹配,不存在通配符机制 +3. 因此编程式注入(`BeanPostProcessor`)更可靠 + +### Q2:只用 `TtlExecutors` 不用 `ContextPropagator` 可以吗? + +**A**:不可以。`TtlExecutors` 只能透传标准 `ThreadPoolExecutor` 的任务提交。Resilience4j 的 `ThreadPoolBulkhead` 内部使用自己的 `ThreadPoolExecutor`,不经过 `TtlExecutors`。因此第一层切换(HTTP → ThreadPoolBulkhead)必须由 `ContextPropagator` 处理。 + +### Q3:为什么 `TenantContextHolder` 使用 `TransmittableThreadLocal` 而不是普通 `ThreadLocal`? + +**A**:因为项目中存在 `@Async` 异步任务、Feign 线程池切换等场景。`TransmittableThreadLocal` 配合 `TtlExecutors` 可以在线程池间自动透传上下文,而普通 `ThreadLocal` 只能在线程父子间继承(且对线程池无效)。 + +### Q4:如果以后引入其他线程池(如 `@Async`),是否也会遇到同样问题? + +**A**:是的。任何使用线程池的地方,如果任务提交方线程有 `ThreadLocal` 上下文,而执行方线程需要读取该上下文,都必须使用以下方案之一: + +- 用 `TtlExecutors` 包装线程池(推荐) +- 手动在任务提交前捕获上下文,在任务执行前恢复(类似 `ContextPropagator` 原理) +- 使用 Project Reactor 的 `Context` + `Hooks.onEachOperator`(响应式场景) + +**最佳实践**:所有业务线程池统一通过 `TtlExecutors` 包装。 + +### Q5:如果关闭 ThreadPoolBulkhead,改用 SemaphoreBulkhead,能否避免此问题? + +**A**:可以。SemaphoreBulkhead 在同一线程内执行,不存在线程切换。但会牺牲线程隔离的故障保护能力。 + +配置方式: +```yaml +spring: + cloud: + circuitbreaker: + resilience4j: + enableSemaphoreDefaultBulkhead: true +``` + +--- + +## 7. 后续维护建议 + +1. **新增 Feign 客户端时**:务必在所在模块的 `META-INF/spring.factories` 中注册 +2. **新增线程池时**:优先使用 `TtlExecutors.getTtlExecutorService()` 包装 +3. **新增 ThreadLocal 上下文时**:考虑是否需要配套 `ContextPropagator` +4. **日志规范**:在上下文切换关键点(Filter、Interceptor、线程池任务)打印 `tenantId` + `threadName`,便于快速定位问题 +5. **自动化测试**:编写并发测试,模拟多租户同时请求,断言各线程的 `tenantId` 与请求头一致 + +--- + +## 8. 相关代码文件 + +| 文件 | 作用 | +|------|------| +| `rui-common-core/holder/TenantContextHolder.java` | 租户上下文持有者(TransmittableThreadLocal) | +| `rui-common-security/feign/TokenManageFeign.java` | Feign 客户端示例 | +| `rui-common-security/feign/OAuthRequestInterceptor.java` | Feign 请求拦截器(透传租户 ID) | +| `rui-common-feign/propagator/TenantContextPropagator.java` | Resilience4j ContextPropagator 实现 | +| `rui-common-feign/config/TenantContextThreadPoolBulkheadConfigCustomizer.java` | 注入 ContextPropagator 到 ThreadPoolBulkheadRegistry | +| `rui-common-feign/config/TtlResilience4JCircuitBreakerFactoryCustomizer.java` | 用 TtlExecutors 包装 CircuitBreakerFactory 线程池 | +| `rui-common-feign/CloudFeignAutoConfiguration.java` | 注册上述 Bean | +| `rui-common-security/META-INF/spring.factories` | 注册 Feign 客户端 | diff --git a/backend/guides/environment-setup.md b/backend/guides/environment-setup.md new file mode 100644 index 0000000..1349347 --- /dev/null +++ b/backend/guides/environment-setup.md @@ -0,0 +1,181 @@ +# 环境搭建指南 + +> **适用范围**: 新加入的开发者 +> **预计耗时**: 30-60 分钟 + +--- + +## 一、必要工具安装 + +### 1.1 JDK 21 + +```bash +# macOS (使用 Homebrew) +brew install openjdk@21 + +# 验证 +java -version +# Expected: openjdk version "21" +``` + +### 1.2 Maven 3.9+ + +```bash +# macOS +brew install maven + +# 验证 +mvn -version +# Expected: Apache Maven 3.9.x +``` + +### 1.3 MySQL 8.0 + +```bash +# macOS +brew install mysql@8.0 +brew services start mysql@8.0 + +# 验证 +mysql --version +# Expected: mysql Ver 8.0.x +``` + +### 1.4 Node.js 18+ 和 pnpm + +```bash +# macOS +brew install node@18 +npm install -g pnpm + +# 验证 +node --version +pnpm --version +``` + +### 1.5 Git + +```bash +# macOS +brew install git + +# 验证 +git --version +``` + +--- + +## 二、项目初始化 + +### 2.1 克隆项目 + +```bash +git clone +cd spring-ai +``` + +### 2.2 配置本地开发环境 + +```bash +# 创建本地配置文件 +cp backend/config/application-dev.yml.example backend/config/application-dev.yml + +# 编辑配置(使用你的数据库连接信息) +# vim backend/config/application-dev.yml +``` + +配置示例: +```yaml +spring: + datasource: + url: jdbc:mysql://localhost:3306/rui_platform?useUnicode=true&characterEncoding=utf8 + username: root + password: your_password +``` + +### 2.3 初始化数据库 + +```bash +# 创建数据库 +mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS rui_platform CHARACTER SET utf8mb4;" + +# 执行初始化脚本 +mysql -u root -p rui_platform < docs/init-database.sql +``` + +### 2.4 编译项目 + +```bash +cd backend +mvn clean install -DskipTests +``` + +Expected: `BUILD SUCCESS` + +--- + +## 三、IDE 配置 + +### 3.1 IntelliJ IDEA + +1. 打开项目(选择 backend/pom.xml) +2. 启用 Annotation Processing: + - Settings → Build → Annotation Processors + - 勾选 "Enable annotation processing" +3. 配置代码风格: + - Settings → Editor → Code Style → Java + - Import Scheme → Project + +### 3.2 VS Code(前端) + +1. 安装推荐插件: + - ESLint + - Prettier + - Vue Language Features +2. 配置自动格式化: + ```json + { + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode" + } + ``` + +--- + +## 四、验证清单 + +完成以上步骤后,请确认: + +- [ ] `java -version` 显示 JDK 21 +- [ ] `mvn -version` 显示 Maven 3.9+ +- [ ] `mysql --version` 显示 MySQL 8.0+ +- [ ] `backend/mvn clean install -DskipTests` 执行成功 +- [ ] 数据库 `rui_platform` 已创建 +- [ ] IntelliJ IDEA 已配置 Annotation Processing + +--- + +## 五、常见问题 + +### Q1: Maven 编译失败 + +**可能原因**: JDK 版本不对 +**解决**: 确认 `JAVA_HOME` 指向 JDK 21 + +```bash +export JAVA_HOME=$(/usr/libexec/java_home -v 21) +``` + +### Q2: 数据库连接失败 + +**可能原因**: MySQL 未启动或配置错误 +**解决**: +```bash +brew services start mysql +# 检查 application-dev.yml 中的连接信息 +``` + +### Q3: Lombok 注解不生效 + +**可能原因**: Annotation Processing 未启用 +**解决**: 按 3.1 节启用 diff --git a/backend/guides/gitnexus-guide.md b/backend/guides/gitnexus-guide.md new file mode 100644 index 0000000..6810386 --- /dev/null +++ b/backend/guides/gitnexus-guide.md @@ -0,0 +1,52 @@ +# GitNexus — Code Intelligence 使用指南 + +> **项目索引**: spring-ai (2690 symbols, 5387 relationships, 218 execution flows) + +## 基本概念 + +GitNexus 是一个代码智能工具,通过索引代码库构建知识图谱,帮助开发者理解代码、评估影响、安全导航。 + +## 核心原则 + +### Always Do + +- **MUST run impact analysis before editing any symbol.** Before modifying a function, class, or method, run `gitnexus_impact({target: "symbolName", direction: "upstream"})` and report the blast radius (direct callers, affected processes, risk level) to the user. +- **MUST run `gitnexus_detect_changes()` before committing** to verify your changes only affect expected symbols and execution flows. +- **MUST warn the user** if impact analysis returns HIGH or CRITICAL risk before proceeding with edits. +- When exploring unfamiliar code, use `gitnexus_query({query: "concept"})` to find execution flows instead of grepping. It returns process-grouped results ranked by relevance. +- When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use `gitnexus_context({name: "symbolName"})`. + +### Never Do + +- NEVER edit a function, class, or method without first running `gitnexus_impact` on it. +- NEVER ignore HIGH or CRITICAL risk warnings from impact analysis. +- NEVER rename symbols with find-and-replace — use `gitnexus_rename` which understands the call graph. +- NEVER commit changes without running `gitnexus_detect_changes()` to check affected scope. + +## 资源速查 + +| Resource | Use for | +|----------|---------| +| `gitnexus://repo/spring-ai/context` | Codebase overview, check index freshness | +| `gitnexus://repo/spring-ai/clusters` | All functional areas | +| `gitnexus://repo/spring-ai/processes` | All execution flows | +| `gitnexus://repo/spring-ai/process/{name}` | Step-by-step execution trace | + +## 技能参考 + +| 场景 | 技能文件 | +|------|---------| +| 架构理解 / "How does X work?" | `.claude/skills/gitnexus/gitnexus-exploring/SKILL.md` | +| 影响分析 / "What breaks if I change X?" | `.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md` | +| Bug 追踪 / "Why is X failing?" | `.claude/skills/gitnexus/gitnexus-debugging/SKILL.md` | +| 重构 / "Rename this function" | `.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md` | +| 工具参考 | `.claude/skills/gitnexus/gitnexus-guide/SKILL.md` | +| CLI 命令 | `.claude/skills/gitnexus/gitnexus-cli/SKILL.md` | + +## 索引维护 + +如果 GitNexus 工具提示索引过期,执行: + +```bash +npx gitnexus analyze +``` diff --git a/backend/guides/opencode-workflow.md b/backend/guides/opencode-workflow.md new file mode 100644 index 0000000..116d4e0 --- /dev/null +++ b/backend/guides/opencode-workflow.md @@ -0,0 +1,322 @@ +# OpenCode 多仓库操作指南 + +> **版本**: v1.0 +> **创建日期**: 2026-06-04 +> **适用**: rui 项目前后端分离开发团队 + +--- + +## 一、项目结构概览 + +rui 项目采用**多仓库**架构: + +``` +~/rhkj/ +├── spring-ai/ # 后端仓库(Java/Spring) +│ ├── backend/ # 基础框架 +│ ├── app/ # 应用模块 +│ └── docs/ # 文档 +│ +└── rui-frontend/ # 前端仓库(Vue/Node.js) + ├── admin-ui/ # 管理后台 + ├── cashier-mobile/ # 收银移动端 + └── customer-mobile/ # 顾客端 +``` + +**原则**:一个 OpenCode 会话只处理一个仓库。 + +--- + +## 二、启动 OpenCode 的正确姿势 + +### 2.1 后端开发(spring-ai) + +```bash +# 1. 进入后端目录 +cd /Users/zhangsheng/rhkj/spring-ai + +# 2. 启动 OpenCode(命令行方式) +opencode + +# 3. 会话启动后,明确告知角色 +``` + +**启动时输入**(粘贴到 OpenCode 对话框): + +``` +你现在进入【后端开发模式】。 + +工作目录:/Users/zhangsheng/rhkj/spring-ai +负责范围:backend/ 和 app/ 目录下的 Java 代码 +技术栈:Spring Boot 4.x、Spring Cloud、MyBatis Plus、JDK 21 + +规则: +1. 只能修改 backend/ 和 app/ 下的代码 +2. 发现前端需求时,提醒用户创建 Gitee Issue +3. 编码规范参考 docs/AGENTS.md + +当前任务:【在这里描述你的具体任务】 +``` + +--- + +### 2.2 前端开发(rui-frontend) + +```bash +# 1. 进入前端目录 +cd /Users/zhangsheng/rhkj/rui-frontend + +# 2. 启动 OpenCode +opencode + +# 3. 会话启动后,明确告知角色 +``` + +**启动时输入**(粘贴到 OpenCode 对话框): + +``` +你现在进入【前端开发模式】。 + +工作目录:/Users/zhangsheng/rhkj/rui-frontend +负责范围:admin-ui/、cashier-mobile/、customer-mobile/ +技术栈:Vue 3、TypeScript、Element Plus、Vite、pnpm + +规则: +1. 只能修改前端项目下的代码 +2. 需要后端接口时,在 spring-ai 仓库创建 Gitee Issue +3. 编码规范参考 AGENTS.md +4. 使用 pnpm workspace 管理多项目 + +当前任务:【在这里描述你的具体任务,如:开发用户管理页面】 +``` + +--- + +### 2.3 框架开发(仅修改 backend/) + +``` +你现在进入【框架开发模式】。 + +工作目录:/Users/zhangsheng/rhkj/spring-ai +负责范围:仅 backend/ 目录 +角色:基础框架维护者 + +规则: +1. 只能修改 backend/ 下的代码 +2. 不修改任何 app/ 目录下的业务代码 +3. 保持框架的通用性和向后兼容性 +4. 修改公共接口时,评估对 app/ 的影响 + +当前任务:【描述框架任务】 +``` + +--- + +## 三、切换工作流的正确方式 + +### ❌ 错误示范 + +在一个 OpenCode 会话中: +``` +用户:帮我修改后端接口 +AI:好的,已修改 backend/xxx.java +用户:再帮我改一下前端页面 +AI:好的,已修改 admin-ui/xxx.vue ← 错误!上下文已污染 +``` + +### ✅ 正确示范 + +**场景 1:同一仓库内切换任务** + +如果任务相关(如修改后端接口 + 对应单元测试),可以在同一会话中完成。 + +如果任务不相关(如用户管理 + 订单管理),建议: +``` +用户:/new +AI:已创建新会话 +用户:【输入新的任务描述】 +``` + +**场景 2:跨仓库协作** + +``` +# 后端仓库会话 +用户:开发用户查询接口 +AI:已完成,接口路径:GET /user/admin/list + +# 需要前端对接时 +用户:需要前端开发列表页面 +AI:请创建新会话处理前端任务。 + 在 rui-frontend 目录启动 OpenCode,输入前端开发模式提示词。 + 接口文档:http://localhost:8080/doc.html#/user/list + +# 用户切换到前端仓库,新建会话 +用户:/new +【进入 rui-frontend 目录,启动新 OpenCode 会话】 +用户:根据接口文档开发用户列表页面 +AI:好的,开始开发前端页面... +``` + +--- + +## 四、跨仓库通信机制 + +### 4.1 前端需要后端接口 + +**前端会话**中: +``` +我需要后端提供用户批量导入接口,参数是 Excel 文件 +``` + +OpenCode 应该回答: +``` +请在 spring-ai 仓库创建 Issue,使用模板:api_request.md + +Issue 内容: +标题:[API-REQ] 用户模块需要批量导入接口 +内容:... + +创建后,在 backend/ 开发会话中处理该 Issue +``` + +### 4.2 后端接口完成通知前端 + +**后端会话**中: +``` +接口已实现,Swagger 地址:/doc.html#/user/import +请通知前端团队进行对接 +``` + +OpenCode 应该: +``` +已在 Issue 中回复前端团队。 +前端可以在 rui-frontend 仓库的新会话中进行对接开发。 +``` + +--- + +## 五、目录访问限制检查 + +启动会话后,可以让 OpenCode 自我检查: + +``` +请确认你的工作范围: +1. 可以修改哪些目录? +2. 不能修改哪些目录? +3. 如果需要跨仓库协作,应该怎么做? +``` + +期望回答: +``` +1. 可修改:backend/、app/(后端模式)或 admin-ui/(前端模式) +2. 不可修改:frontend/(后端模式)或 backend/(前端模式) +3. 跨仓库协作:通过 Gitee Issue 进行 +``` + +--- + +## 六、常见问题 + +### Q1: 我不小心在错误目录启动了 OpenCode,怎么办? + +**答**: +1. 保存当前对话(如有重要信息) +2. 关闭当前 OpenCode 窗口 +3. 切换到正确目录重新启动 +4. 使用 `/new` 创建新会话 + +### Q2: 一个功能需要同时修改前后端,怎么操作? + +**答**: +1. **方法 A(推荐)**:先在一个仓库完成,提交后切换到另一个仓库 + - 在 spring-ai 开发接口 → 提交 PR + - 在 rui-frontend 开发页面 → 提交 PR + +2. **方法 B(并行)**:两个 OpenCode 窗口同时工作 + - 窗口 1:spring-ai 目录,开发后端 + - 窗口 2:rui-frontend 目录,开发前端 + +3. **不要**:在一个会话中同时修改两个仓库 + +### Q3: OpenCode 能记住跨仓库的上下文吗? + +**答**:不能。每个 OpenCode 会话是独立的: +- 不同目录 = 不同上下文 +- 即使同一个目录,`/new` 后也是全新上下文 +- 需要人工传递关键信息(如接口文档链接) + +### Q4: 怎么快速查看当前在哪个仓库? + +**答**:在 OpenCode 中输入: +``` +请告诉我当前工作目录和可修改范围 +``` + +### Q5: 可以用同一个 OpenCode 窗口切换目录吗? + +**答**:不建议。OpenCode 启动时会锁定工作目录。如果需要切换: +1. 关闭当前窗口 +2. `cd` 到新目录 +3. 重新启动 OpenCode + +--- + +## 七、快捷键和命令速查 + +| 操作 | 命令 | +|------|------| +| 创建新会话 | `/new` | +| 查看当前目录 | `pwd` | +| 查看文件树 | `tree -L 2` | +| 查看 Git 状态 | `git status` | +| 切换分支 | `git checkout branch-name` | + +--- + +## 八、最佳实践 + +1. **明确角色**:启动时明确告知 OpenCode 当前角色和范围 +2. **单一职责**:一个会话只做一件事(一个功能/一个 Bug) +3. **及时提交**:完成一个功能后立即 `git commit`,不要积压 +4. **Issue 驱动**:跨仓库需求通过 Issue 追踪,不要口头传递 +5. **文档优先**:复杂功能先写设计文档,再编码 +6. **定期 /new**:对话超过 20-30 轮后,新建会话保持上下文清晰 + +--- + +## 九、模板库 + +### 启动模板 + +保存以下模板,启动时直接粘贴: + +**后端启动模板**: +```markdown +你现在进入【后端开发模式】。 +工作目录:/Users/zhangsheng/rhkj/spring-ai +技术栈:Spring Boot 4.x、JDK 21、MyBatis Plus +规则:只能修改 backend/ 和 app/ 目录 +当前任务:【填写】 +``` + +**前端启动模板**: +```markdown +你现在进入【前端开发模式】。 +工作目录:/Users/zhangsheng/rhkj/rui-frontend +技术栈:Vue 3、TypeScript、Element Plus、Vite +规则:只能修改前端项目目录 +当前任务:【填写】 +``` + +--- + +## 十、相关文档 + +- [跨团队协作规范](./cross-team-workflow.md) +- [后端项目规范](../AGENTS.md) +- [前端项目规范](../../rui-frontend/AGENTS.md) +- [Gitea 自建 Git 服务器](./self-hosted-git-server.md) + +--- + +> **提示**:本文档是活文档,根据团队实践持续更新。如有建议请提交 PR。 diff --git a/backend/guides/rui-common-core使用手册.md b/backend/guides/rui-common-core使用手册.md new file mode 100644 index 0000000..841f5f8 --- /dev/null +++ b/backend/guides/rui-common-core使用手册.md @@ -0,0 +1,459 @@ +# rui-common-core 使用手册 + +> **文件名**:`rui-common-core使用手册.md` +> **存放位置**:`docs/rui-common-core使用手册.md` +> +> **文档定位**:本文档是 `rui-common-core` 模块的**唯一权威参考**,记录所有工具类、注解、事件、DTO 的功能与用法。 +> +> **使用规则**: +> 1. **开发前先查本文档**:使用任何通用工具/注解/常量前,优先查阅本文档确认是否存在可用实现 +> 2. **新增即更新**:向 `rui-common-core` 模块新增/修改任何类、方法时,**必须同步更新本文档** +> 3. **禁止重复造轮子**:本文档中已有的工具,禁止在业务模块中重新实现 + +--- + +## 1. 模块概述 + +`rui-common-core` 是睿核通用平台框架的**核心基础模块**,为所有上层模块提供通用的工具类、常量、异常、上下文持有器、注解、事件、DTO 等基础能力。 + +> **定位**:无业务依赖,无 Spring 依赖(除 SpringUtil、LoginEvent 外),可被任意模块引用。 + +--- + +## 2. 功能清单 + +### 2.1 上下文持有器(holder) + +| 类名 | 功能 | 说明 | +|------|------|------| +| `TenantContextHolder` | 租户上下文 | 线程隔离的租户 ID 存储,支持父子线程传递 | +| `LocaleContextHolder` | 本地化上下文 | 线程隔离的语言环境存储 | + +### 2.2 工具类(util) + +| 类名 | 功能 | 依赖 | +|------|------|------| +| `ServletUtil` | Servlet 请求工具 | 获取 IP、参数、Header、请求体等 | +| `SpringUtil` | Spring 上下文工具 | 获取 Bean、配置、Environment、判断环境 | +| `JsonUtil` | JSON 工具 | 基于 Fastjson2,对象与 JSON 互转 | +| `DateUtil` | 日期时间工具 | 基于 JDK 8 java.time,格式化、解析、计算 | +| `IdWorker` | 雪花算法 ID 生成器 | 分布式唯一 ID,支持趋势递增 | +| `BeanUtil` | Bean 拷贝工具 | 基于 Spring BeanUtils,支持列表拷贝 | +| `EncryptUtil` | 加密工具 | MD5、SHA-256、AES、Base64 | +| `ValidateUtil` | 校验工具 | 手机号、邮箱、身份证、URL、密码等校验 | +| `StringUtil` | 字符串扩展工具 | 驼峰/下划线转换、脱敏、截取等 | +| `ThreadUtil` | 线程工具 | 线程池创建、优雅关闭、命名线程工厂 | +| `FileUtil` | 文件工具 | 读写、复制、移动、目录操作、大小格式化 | +| `UserNoGenerator` | 用户编号生成器 | 生成 U0001 格式编号,自动跳过保留靓号 | + +### 2.3 异常(exception) + +| 类名 | 功能 | +|------|------| +| `BizException` | 业务异常,统一业务错误抛出 | + +### 2.4 常量(constants) + +| 类名 | 功能 | +|------|------| +| `SecurityConstant` | 安全相关常量(Token 前缀、Header 名称等) | + +### 2.5 模型(model) + +| 类名 | 功能 | +|------|------| +| `PageResult` | 统一分页结果封装 | + +### 2.6 结果封装(result) + +| 类名 | 功能 | +|------|------| +| `Result` | 统一 API 返回结果(code、msg、data) | +| `ResultCode` | 统一错误码枚举 | + +### 2.7 注解(annotation) + +| 类名 | 功能 | 目标位置 | +|------|------|---------| +| `DataScope` | 数据权限注解,自动拼接数据范围 SQL | Service 方法 | + +### 2.8 事件(event) + +| 类名 | 功能 | 说明 | +|------|------|------| +| `LoginEvent` | 登录事件 | 登录成功/失败时发布,供监听器记录日志 | + +### 2.9 DTO(dto) + +| 类名 | 功能 | 说明 | +|------|------|------| +| `OperLogDTO` | 操作日志 DTO | 跨服务传输操作日志数据 | + +### 2.10 拦截器上下文(interceptor) + +| 类名 | 功能 | 说明 | +|------|------|------| +| `DataScopeContext` | 数据权限上下文 | ThreadLocal 存储数据范围信息,需手动清理 | + +--- + +## 3. 工具类详细说明 + +### 3.1 IdWorker(雪花算法) + +```java +// 生成唯一 ID +long id = IdWorker.nextIdLong(); +String idStr = IdWorker.nextIdStr(); + +// 从 ID 中提取信息 +long timestamp = IdWorker.extractTimestamp(id); +long workerId = IdWorker.extractWorkerId(id); +``` + +### 3.2 DateUtil(日期时间) + +```java +// 获取当前时间 +String now = DateUtil.now(); // 2024-01-01 12:00:00 +String today = DateUtil.today(); // 2024-01-01 + +// 格式化与解析 +String str = DateUtil.format(LocalDateTime.now()); +LocalDateTime dt = DateUtil.parse("2024-01-01 12:00:00"); + +// 计算 +LocalDateTime tomorrow = DateUtil.plusDays(dt, 1); +long days = DateUtil.betweenDays(start, end); +``` + +### 3.3 JsonUtil(JSON 处理) + +```java +// 对象转 JSON +String json = JsonUtil.toJsonString(user); + +// JSON 转对象 +User user = JsonUtil.parseObject(json, User.class); +List list = JsonUtil.parseList(json, User.class); +Map map = JsonUtil.parseMap(json); +``` + +### 3.4 EncryptUtil(加密) + +```java +// MD5 +String md5 = EncryptUtil.md5("password"); + +// SHA-256 +String sha256 = EncryptUtil.sha256("password"); + +// AES 对称加密 +String encrypt = EncryptUtil.aesEncrypt("content", "1234567890123456"); +String decrypt = EncryptUtil.aesDecrypt(encrypt, "1234567890123456"); + +// Base64 +String base64 = EncryptUtil.base64Encode("content"); +``` + +### 3.5 ValidateUtil(校验) + +```java +// 常用校验 +boolean isMobile = ValidateUtil.isMobile("13800138000"); +boolean isEmail = ValidateUtil.isEmail("test@example.com"); +boolean isIdCard = ValidateUtil.isIdCard("110101199001011234"); +boolean isUrl = ValidateUtil.isUrl("https://example.com"); +boolean isIpv4 = ValidateUtil.isIpv4("192.168.1.1"); + +// 密码强度 +boolean validPwd = ValidateUtil.isValidPassword("Abc123456"); +``` + +### 3.6 SpringUtil(Spring 上下文) + +```java +// 获取 Bean +UserService service = SpringUtil.getBean(UserService.class); + +// 获取配置 +String value = SpringUtil.getProperty("server.port"); + +// 判断环境 +boolean isDev = SpringUtil.isDev(); +boolean isProd = SpringUtil.isProd(); +``` + +### 3.7 BeanUtil(Bean 拷贝) + +```java +// 对象拷贝 +UserDTO dto = BeanUtil.copyProperties(user, UserDTO.class); + +// 列表拷贝 +List dtoList = BeanUtil.copyList(userList, UserDTO.class); + +// 忽略 null 值拷贝(用于更新) +BeanUtil.copyNonNullProperties(source, target); +``` + +### 3.8 StringUtil(字符串扩展) + +```java +// 命名转换 +String camel = StringUtil.underlineToCamel("user_name"); // userName +String underline = StringUtil.camelToUnderline("userName"); // user_name + +// 脱敏 +String mobile = StringUtil.desensitizeMobile("13800138000"); // 138****8000 +String email = StringUtil.desensitizeEmail("test@example.com"); // t***@example.com + +// 其他 +String truncated = StringUtil.truncate("很长的字符串", 5); // 很长的字... +``` + +### 3.9 ThreadUtil(线程池) + +```java +// 创建线程池 +ExecutorService pool = ThreadUtil.newFixedPool(4, "my-pool"); +ScheduledExecutorService scheduled = ThreadUtil.newScheduledPool(2, "schedule"); + +// 推荐:自定义线程池 +ThreadPoolExecutor executor = ThreadUtil.newThreadPool( + 4, 8, 60, 100, "business" +); + +// 优雅关闭 +ThreadUtil.shutdown(pool, 30); +``` + +### 3.10 FileUtil(文件操作) + +```java +// 读写 +String content = FileUtil.readString("/path/file.txt"); +FileUtil.writeString("/path/file.txt", "content"); +FileUtil.appendString("/path/file.txt", "append"); + +// 目录 +FileUtil.createDir("/path/dir"); +FileUtil.delete("/path/file.txt"); + +// 信息 +boolean exists = FileUtil.exists("/path/file.txt"); +long size = FileUtil.size("/path/file.txt"); +String sizeStr = FileUtil.formatSize(1024 * 1024); // 1.00 MB +``` + +### 3.11 UserNoGenerator(用户编号生成器) + +```java +// 生成格式化的用户编号(U0001、U0002...) +String userNo = UserNoGenerator.format(1); // U0001 + +// 判断是否为保留靓号(豹子号、连号、含666/888/999) +boolean reserved = UserNoGenerator.isReserved("U1111"); // true + +// 生成下一个可用编号(自动跳过保留号) +String next = UserNoGenerator.generate(1); // U0001(如果 U0001 是靓号则自动跳过) +``` + +--- + +## 4. 注解使用说明 + +### 4.1 @DataScope(数据权限) + +标记在 Service 方法上,由 MyBatis Plus 拦截器自动拼接数据范围 SQL。 + +```java +@DataScope(deptField = "dept_id", userField = "create_by") +public List list() { + return baseMapper.selectList(); +} +``` + +**参数说明**: +- `deptField`:部门字段名,默认 `"dept_id"` +- `userField`:用户字段名,默认 `"create_by"` + +**数据范围类型**(由 `DataScopeContext` 设置): +- `1`:全部数据 +- `2`:本部门数据 +- `3`:本部门及子部门数据 +- `4`:仅本人数据 +- `5`:自定义数据 + +--- + +## 5. 事件使用说明 + +### 5.1 LoginEvent(登录事件) + +登录成功或失败时发布,供其他模块监听记录日志。 + +```java +// 发布事件 +applicationEventPublisher.publishEvent( + new LoginEvent(this, userId, username, 1, clientId, ip, + location, browser, os, 1, "登录成功") +); + +// 监听事件 +@Component +public class LoginEventListener { + @EventListener + public void onLogin(LoginEvent event) { + // 记录登录日志 + } +} +``` + +--- + +## 6. DTO 使用说明 + +### 6.1 OperLogDTO(操作日志 DTO) + +用于跨服务传输操作日志数据。 + +```java +OperLogDTO log = new OperLogDTO(); +log.setTitle("用户管理"); +log.setOperType(2); // 修改 +log.setOperTypeName("修改用户"); +log.setRequestUrl("/user/admin/user"); +log.setRequestMethod("PUT"); +log.setUserId(userId); +log.setStatus(1); // 成功 +``` + +--- + +## 7. 上下文使用说明 + +### 7.1 TenantContextHolder(租户上下文) + +```java +// 设置租户ID +TenantContextHolder.setTenantId(100L); + +// 获取租户ID +Long tenantId = TenantContextHolder.getTenantId(); + +// 清理(必须在线程结束时调用) +TenantContextHolder.clear(); +``` + +### 7.2 DataScopeContext(数据权限上下文) + +```java +// 设置数据范围 +DataScopeContext.setDataScope(2); // 本部门 +DataScopeContext.setUserId(userId); +DataScopeContext.setDeptId(deptId); + +// 获取数据范围 +Integer scope = DataScopeContext.getDataScope(); + +// 清理(必须在线程结束时调用,防止内存泄漏) +DataScopeContext.clear(); +``` + +--- + +## 8. 使用方式 + +### 8.1 Maven 依赖 + +```xml + + com.rui + rui-common-core + ${revision} + +``` + +### 8.2 在业务模块中使用 + +```java +import com.rui.common.core.util.*; + +@Service +public class UserService { + + public void createUser(User user) { + // 生成唯一 ID + user.setId(IdWorker.nextIdLong()); + + // 生成用户编号 + user.setUserNo(UserNoGenerator.generate(seq)); + + // 日期处理 + user.setCreatedAt(DateUtil.nowDateTime()); + + // 密码加密 + user.setPassword(EncryptUtil.md5(user.getPassword())); + + // 保存... + } +} +``` + +--- + +## 9. 规范说明 + +### 9.1 工具类设计原则 + +1. **无状态**:所有工具类均为无状态静态方法,线程安全 +2. **不可实例化**:通过 private 构造器防止实例化 +3. **异常处理**:内部捕获并转换为 RuntimeException,避免污染业务代码 +4. **空安全**:所有方法对 null 参数有处理,避免 NPE + +### 9.2 新增规范 + +如需向本模块新增类,请遵循: + +1. **包名规范**: + - 工具类:`com.rui.common.core.util` + - 注解:`com.rui.common.core.annotation` + - 事件:`com.rui.common.core.event` + - DTO:`com.rui.common.core.dto` + - 上下文:`com.rui.common.core.holder` / `interceptor` + - 常量:`com.rui.common.core.constants` + - 异常:`com.rui.common.core.exception` + +2. **命名规范**: + - 工具类:以 `Util` 结尾,如 `XxxUtil` + - 注解:以功能命名,如 `@DataScope` + - 事件:以 `Event` 结尾,如 `XxxEvent` + - DTO:以 `DTO` 结尾,如 `XxxDTO` + +3. **方法规范**:均为 public static(工具类) +4. **文档规范**:类注释和方法注释使用中文 +5. **测试规范**:建议补充单元测试 +6. **文档同步**:**新增/修改后必须同步更新本文档** + +--- + +## 10. 文档维护说明 + +### 10.1 何时更新本文档 + +| 场景 | 操作 | +|------|------| +| 新增工具类/注解/事件/DTO | 在功能清单中添加条目,在详细说明中添加使用示例 | +| 修改现有类的方法签名 | 同步更新对应详细说明中的代码示例 | +| 删除类或方法 | 从文档中移除对应条目,并在版本历史中注明 | +| 发现文档与代码不一致 | 以代码为准,修正文档 | + +### 10.2 版本历史 + +| 日期 | 版本 | 变更内容 | +|------|------|---------| +| 2024-01 | 1.0 | 初始版本,包含基础工具类 | +| 2024-06 | 1.1 | 新增 IdWorker、BeanUtil、ThreadUtil | +| 2026-05 | 1.2 | 补充完整工具类集合,新增文档 | +| 2026-06 | 1.3 | 新增 UserNoGenerator、DataScope 注解、LoginEvent、OperLogDTO、DataScopeContext;补充文档使用说明 | diff --git a/backend/guides/self-hosted-git-server.md b/backend/guides/self-hosted-git-server.md new file mode 100644 index 0000000..b781c68 --- /dev/null +++ b/backend/guides/self-hosted-git-server.md @@ -0,0 +1,480 @@ +# 自建 Git 服务器方案:Gitea + +> **版本**: v1.0 +> **创建日期**: 2026-06-04 +> **适用场景**: 替代 Gitee,实现完整的 Git + CI/CD 私有化部署 + +--- + +## 一、为什么选择 Gitea? + +### 1.1 对比分析 + +| 特性 | Gitee | GitLab CE | Gitea | Gogs | +|------|-------|-----------|-------|------| +| **开源免费** | 部分功能收费 | ✅ 社区版免费 | ✅ 完全开源 | ✅ 完全开源 | +| **资源占用** | 云端,无需部署 | 4GB+ 内存 | **128MB 内存** | 64MB 内存 | +| **CI/CD** | 收费 | ✅ 内置 | ✅ Gitea Actions | ❌ 需搭配 Drone | +| **中文支持** | ✅ 原生 | ✅ 支持 | ✅ 支持 | ✅ 支持 | +| **Issue 模板** | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | +| **代码审查** | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 | +| **部署难度** | 无需部署 | 复杂 | **简单** | 简单 | +| **GitHub Actions 兼容** | ❌ | ❌ | ✅ 兼容 | ❌ | + +### 1.2 Gitea 优势 + +- ✅ **轻量级**:单二进制文件,内置 SQLite,无需额外数据库 +- ✅ **低资源**:128MB 内存即可运行,适合低配服务器 +- ✅ **CI/CD 内置**:Gitea Actions 完全兼容 GitHub Actions 语法 +- ✅ **易迁移**:支持从 Gitee/GitHub 导入仓库 +- ✅ **Webhook 丰富**:支持钉钉、企业微信、Slack 等通知 +- ✅ **权限管理**:组织、团队、仓库级权限控制 + +--- + +## 二、部署方案 + +### 方案 A:Docker 部署(推荐) + +适合:有 Docker 环境的服务器 + +```yaml +# docker-compose.yml +version: "3" + +services: + gitea: + image: gitea/gitea:latest + container_name: gitea + environment: + - USER_UID=1000 + - USER_GID=1000 + - GITEA__database__DB_TYPE=sqlite3 + - GITEA__server__DOMAIN=git.vifo.cc + - GITEA__server__ROOT_URL=https://git.vifo.cc + - GITEA__server__SSH_DOMAIN=git.vifo.cc + - GITEA__actions__ENABLED=true + restart: always + networks: + - gitea + volumes: + - ./gitea:/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - "3000:3000" + - "222:22" + + # 可选:Gitea Actions Runner(执行 CI/CD 任务) + runner: + image: gitea/act_runner:latest + container_name: gitea-runner + environment: + - GITEA_INSTANCE_URL=https://git.vifo.cc + - GITEA_RUNNER_REGISTRATION_TOKEN=your-token + - GITEA_RUNNER_NAME=default-runner + restart: always + networks: + - gitea + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - ./runner:/data + depends_on: + - gitea + +networks: + gitea: + external: false +``` + +**启动命令**: +```bash +# 创建目录 +mkdir -p ~/gitea && cd ~/gitea + +# 创建 docker-compose.yml(粘贴上方内容) +nano docker-compose.yml + +# 启动 +docker-compose up -d + +# 查看日志 +docker-compose logs -f gitea +``` + +**初始化配置**: +1. 访问 `http://服务器IP:3000` +2. 填写管理员账号(首次访问会自动跳转到安装页面) +3. 基础 URL 设置为你的域名(如 `https://git.vifo.cc`) +4. 数据库选择 SQLite(轻量级)或 MySQL(生产环境) + +--- + +### 方案 B:二进制部署 + +适合:没有 Docker 环境的裸机 + +```bash +# 1. 下载二进制(Linux AMD64) +wget -O gitea https://dl.gitea.com/gitea/latest/gitea-latest-linux-amd64 +chmod +x gitea + +# 2. 创建用户(不要使用 root 运行) +sudo useradd -r -m -s /bin/bash git + +# 3. 创建工作目录 +sudo mkdir -p /var/lib/gitea/{custom,data,log} +sudo chown -R git:git /var/lib/gitea/ +sudo chmod -R 750 /var/lib/gitea/ + +# 4. 移动到系统目录 +sudo mv gitea /usr/local/bin/ + +# 5. 创建 Systemd 服务 +sudo tee /etc/systemd/system/gitea.service > /dev/null < **提示**:如果不方便自己部署服务器,也可以考虑 **Gitea Cloud**(官方托管版)或继续使用 Gitee 免费版(仅代码托管,CI/CD 用其他方案如 Jenkins)。 diff --git a/backend/guides/灰度发布.md b/backend/guides/灰度发布.md new file mode 100644 index 0000000..256d21f --- /dev/null +++ b/backend/guides/灰度发布.md @@ -0,0 +1,242 @@ +# 灰度发布(金丝雀发布) + +> 网关层灰度发布解决方案,支持多种灰度策略,实现平滑的服务升级。 + +## 概述 + +灰度发布(Canary Release)是一种渐进式发布策略,通过将小部分流量先路由到新版本,验证无误后再逐步扩大流量,最终完成全量发布。本方案在网关层实现,对业务服务无侵入。 + +## 核心特性 + +| 特性 | 说明 | +|------|------| +| **多策略支持** | 权重、用户白名单、IP 白名单、强制 Header | +| **多服务独立配置** | 每个服务可配置独立的灰度规则 | +| **无侵入** | 业务服务无需改动,仅通过元数据标记版本 | +| **优先级控制** | 多种策略按优先级执行,确保灰度准确性 | + +## 灰度策略(按优先级排序) + +### 1. 强制 Header(最高优先级) + +客户端通过指定 Header 强制访问特定版本,用于测试验证。 + +```http +GET /user/api/info HTTP/1.1 +Host: api.example.com +X-Grayscale-Version: v2 +``` + +### 2. 用户白名单 + +特定用户 ID 强制走灰度版本,通常用于内部测试账号。 + +**识别方式**:通过 `X-User-Id` Header 识别用户身份。 + +### 3. IP 白名单 + +特定 IP 或 IP 段的请求走灰度版本,支持 CIDR 格式。 + +**示例**: +- `192.168.1.0/24` - 内网网段 +- `10.0.0.5` - 单个 IP + +### 4. 权重比例(最低优先级) + +按比例分配流量,适用于全量灰度场景。 + +**示例**:`weight: 10` 表示 10% 的请求走灰度版本。 + +## 后端服务配置 + +### 1. 标记灰度实例 + +在服务的 `application.yml` 中通过 Nacos 元数据标记版本: + +```yaml +spring: + cloud: + nacos: + discovery: + metadata: + gray.version: v2 # 标记为灰度版本 v2 +``` + +### 2. 部署多个版本 + +同时部署稳定版本和灰度版本: + +``` +服务实例列表 +├── rui-service-user:v1 (稳定版本,无 gray.version 或 gray.version=v1) +├── rui-service-user:v1 (稳定版本) +└── rui-service-user:v2 (灰度版本,gray.version=v2) +``` + +## 网关配置 + +在 Nacos 的 `rui-gateway.yaml` 中配置灰度规则: + +```yaml +grayscale: + # 强制灰度 Header 名称 + force-header: X-Grayscale-Version + # 灰度规则 + rules: + # rui-service-user 服务的灰度规则 + rui-service-user: + enabled: true # 启用灰度 + version: v2 # 灰度版本标识(与实例元数据对应) + weight: 10 # 10% 流量走灰度 + user-ids: # 特定用户走灰度 + - user001 + - user002 + ip-ranges: # 特定 IP 走灰度 + - 192.168.1.0/24 +``` + +### 配置项说明 + +| 配置项 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| `enabled` | boolean | 是 | 是否启用灰度 | +| `version` | string | 否 | 灰度版本标识,默认 `gray` | +| `weight` | int | 否 | 灰度流量权重(0-100),默认 0 | +| `user-ids` | list | 否 | 用户白名单列表 | +| `ip-ranges` | list | 否 | IP 白名单列表,支持 CIDR | + +## 使用场景示例 + +### 场景一:内部测试 + +仅需内部测试人员访问新版本: + +```yaml +grayscale: + rules: + rui-service-user: + enabled: true + version: v2 + user-ids: + - tester001 + - tester002 +``` + +### 场景二:按比例灰度 + +对全量用户按比例灰度: + +```yaml +grayscale: + rules: + rui-service-user: + enabled: true + version: v2 + weight: 5 # 先 5%,逐步提高到 10%、20%、50%、100% +``` + +### 场景三:内部 IP 灰度 + +公司内部员工先行体验: + +```yaml +grayscale: + rules: + rui-service-user: + enabled: true + version: v2 + ip-ranges: + - 192.168.0.0/16 # 公司内网 + - 10.0.0.0/8 # VPN 网段 +``` + +### 场景四:组合策略 + +多种策略同时生效(按优先级匹配): + +```yaml +grayscale: + rules: + rui-service-user: + enabled: true + version: v2 + weight: 10 + user-ids: + - vip001 # VIP 用户优先体验 + ip-ranges: + - 192.168.1.0/24 # 办公室网络 +``` + +**匹配逻辑**: +1. 强制 Header > 2. 用户白名单 > 3. IP 白名单 > 4. 权重 + +## 验证灰度是否生效 + +### 1. 查看网关日志 + +开启 DEBUG 级别日志,查看实例选择: + +``` +选择灰度实例: rui-service-user:v2 [v2] +选择稳定实例: rui-service-user:v1 +``` + +### 2. 通过 Header 验证 + +在响应头中添加版本标识: + +```java +// 后端服务在响应中添加版本信息 +response.setHeader("X-Server-Version", version); +``` + +### 3. 使用强制 Header 测试 + +```bash +curl -H "X-Grayscale-Version: v2" https://api.example.com/user/api/info +``` + +## 最佳实践 + +### 1. 灰度前准备 + +- [ ] 新版本已通过测试环境验证 +- [ ] 监控和告警已配置 +- [ ] 回滚方案已准备 + +### 2. 灰度流程 + +1. **Phase 1**:内部测试(用户白名单) +2. **Phase 2**:办公网灰度(IP 白名单) +3. **Phase 3**:小流量灰度(weight=1%) +4. **Phase 4**:逐步扩大(5% → 10% → 20% → 50% → 100%) +5. **Phase 5**:全量发布,下线旧版本 + +### 3. 监控指标 + +- 错误率对比(灰度 vs 稳定) +- 响应时间对比 +- 业务指标波动 + +### 4. 快速回滚 + +发现问题时立即关闭灰度: + +```yaml +grayscale: + rules: + rui-service-user: + enabled: false # 关闭灰度,全部流量回稳定版本 +``` + +## 注意事项 + +1. **服务发现延迟**:Nacos 服务列表更新可能有延迟(默认 5-10 秒) +2. **数据兼容性**:确保新版本与旧版本数据库兼容 +3. **接口兼容性**:灰度期间避免破坏性接口变更 +4. **会话一致性**:有状态服务需考虑会话粘滞或共享 + +## 相关文档 + +- [Spring Cloud Gateway 文档](https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/) +- [Spring Cloud LoadBalancer 文档](https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#spring-cloud-loadbalancer) diff --git a/backend/guides/聚合启动器使用文档.md b/backend/guides/聚合启动器使用文档.md new file mode 100644 index 0000000..c6a3289 --- /dev/null +++ b/backend/guides/聚合启动器使用文档.md @@ -0,0 +1,302 @@ +# 聚合启动器(rui-service-starter)使用文档 + +## 1. 什么是聚合启动器 + +`rui-service-starter` 是将多个业务微服务合并为一个 Spring Boot 应用启动的**轻量化部署方案**。 + +| 模块 | 说明 | +|------|------| +| `rui-service-system` | 系统管理服务(菜单、角色、部门、字典、租户等) | +| `rui-service-user` | 用户基础服务(用户、等级、权限等) | + +> **认证中心(rui-auth)和网关(rui-gateway)保持独立**,不参与聚合。 + +--- + +## 2. 适用场景 + +| 场景 | 推荐模式 | +|------|---------| +| 中小型项目、团队规模 < 10 人 | ✅ **聚合模式**(节省资源、简化部署) | +| 大型项目、多团队并行开发 | 独立微服务模式(服务隔离、独立发布) | +| 从单体向微服务过渡 | ✅ **聚合模式**(先聚合后拆分) | +| 本地开发调试 | ✅ **聚合模式**(一键启动所有业务) | + +**聚合模式优势:** +- 减少 JVM 内存占用(节省 500MB+) +- 减少 Nacos 注册中心压力 +- 一次打包、一次部署、一次启动 +- 本地开发只需启动 3 个服务(gateway + auth + starter) + +--- + +## 3. 架构说明 + +### 3.1 独立微服务模式(默认) + +``` +┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ +│ Gateway │────▶│ rui-auth │────▶│ rui-service-xxx │ +│ :9300 │ │ :9301 │ │ :9302~930N │ +└─────────────┘ └─────────────┘ └─────────────────┘ + │ + ┌──────────┴──────────┐ + ▼ ▼ + rui-service-system rui-service-user + :9302 :9303 +``` + +### 3.2 聚合模式 + +``` +┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ +│ Gateway │────▶│ rui-auth │────▶│ rui-service-starter │ +│ :9300 │ │ :9301 │ │ :9399 │ +└─────────────┘ └─────────────┘ └─────────────────────────┘ + │ + ┌──────────┴──────────┐ + ▼ ▼ + [system 模块] [user 模块] + 共享 JVM + 端口 +``` + +--- + +## 4. 快速启动 + +### 4.1 编译 + +```bash +cd backend + +# 编译聚合启动器(自动编译依赖模块) +mvn clean install -pl rui-service/rui-service-starter -am -DskipTests +``` + +### 4.2 本地开发启动 + +```bash +# 方式一:IDE 直接运行 StarterApplication.java +# 方式二:命令行启动 +java -jar rui-service/rui-service-starter/target/rui-service-starter-1.0.0-SNAPSHOT.jar +``` + +### 4.3 生产环境启动 + +```bash +# 指定环境变量(也可在 Nacos 中配置) +java -jar rui-service-starter-1.0.0-SNAPSHOT.jar \ + --NACOS_SERVER_ADDR=127.0.0.1:8848 \ + --spring.profiles.active=prod +``` + +--- + +## 5. 端口与服务名 + +| 服务 | 端口 | Nacos 服务名 | 说明 | +|------|------|-------------|------| +| rui-gateway | 9300 | rui-gateway | 网关(保持独立) | +| rui-auth | 9301 | rui-auth | 认证中心(保持独立) | +| rui-service-system | 9302 | rui-service-system | 系统服务(独立模式) | +| rui-service-user | 9303 | rui-service-user | 用户服务(独立模式) | +| **rui-service-starter** | **9399** | **rui-service-starter** | **聚合启动器(替代 system + user)** | + +--- + +## 6. 网关路由配置 + +Nacos `rui-gateway.yaml` 中已默认使用聚合模式,将 `/system/**` 和 `/user/**` 统一路由到 `rui-service-starter`: + +```yaml +spring: + cloud: + gateway: + server: + webflux: + routes: + - id: rui-auth + uri: lb://rui-auth + predicates: + - Path=/auth/** + filters: + - StripPrefix=0 + # ========== 聚合模式(默认,中小型项目)========== + - id: rui-service-starter + uri: lb://rui-service-starter + predicates: + - Path=/user/**,/system/** + filters: + - StripPrefix=0 + # ========== 独立微服务模式(大型项目)========== + # - id: rui-service-user + # uri: lb://rui-service-user + # predicates: + # - Path=/user/** + # filters: + # - StripPrefix=0 + # - id: rui-service-system + # uri: lb://rui-service-system + # predicates: + # - Path=/system/** + # filters: + # - StripPrefix=0 +``` + +> **提示**:如需切换到独立模式,取消注释独立路由并注释掉聚合路由即可。 + +--- + +## 7. Feign 调用说明 + +### 7.1 聚合模式下的 Feign 行为 + +| Feign 接口 | 目标服务 | 默认指向 | 说明 | +|-----------|---------|---------|------| +| `UserAuthFeign` | `rui-service-user` | `rui-service-starter` | 通过 Nacos 路由到聚合启动器 | +| `SystemClientFeign` | `rui-service-system` | `rui-service-starter` | 通过 Nacos 路由到聚合启动器 | +| `TokenManageFeign` | `rui-auth` | `rui-auth` | 认证中心保持独立 | + +### 7.2 配置原理 + +FeignClient 的 `value` 属性使用 `${feign.providers.xxx}` 变量,默认指向聚合启动器: + +```java +@FeignClient(contextId = "userAuthFeign", + value = "${feign.providers.user:rui-service-starter}", // 默认指向聚合启动器 + path = "/user/inner") +``` + +**Nacos `rui-common.yaml` 中的公共配置:** + +```yaml +feign: + providers: + user: rui-service-starter # 用户服务:默认指向聚合启动器 + system: rui-service-starter # 系统服务:默认指向聚合启动器 + auth: rui-auth # 认证中心:保持独立 +``` + +**切换独立模式**:在对应服务的 Nacos 配置中覆盖: + +```yaml +feign: + providers: + user: rui-service-user # 改回独立用户服务 + system: rui-service-system # 改回独立系统服务 +``` + +--- + +## 8. Nacos 配置建议 + +### 8.1 配置中心 + +聚合启动器启动时会加载以下 Nacos 配置: + +| 配置文件 | 说明 | +|---------|------| +| `rui-service-starter.yaml` | 聚合服务专属配置(可选) | +| `rui-common.yaml` | 公共配置(日志、线程池等) | +| `rui-data.yaml` | 数据源配置(MySQL、Redis 等) | + +### 8.2 配置继承 + +聚合模式下,`rui-service-starter.yaml` 可以覆盖 `rui-service-system.yaml` 和 `rui-service-user.yaml` 中的冲突配置。 + +建议将**业务无关的基础配置**放到 `rui-common.yaml`,**数据库连接等环境配置**放到 `rui-data.yaml`。 + +--- + +## 9. 两种模式切换指南 + +### 9.1 从独立模式切换到聚合模式 + +1. **停止** `rui-service-user` 和 `rui-service-system` +2. **启动** `rui-service-starter` +3. **修改网关路由**(见 6.1) +4. **完成** + +### 9.2 从聚合模式切换到独立模式 + +1. **停止** `rui-service-starter` +2. **启动** `rui-service-system`(端口 9302)和 `rui-service-user`(端口 9303) +3. **修改网关路由**(见 6.2) +4. **完成** + +### 9.3 代码层面注意事项 + +- 聚合模式下,**所有业务代码无需修改** +- 两个服务的 `@RestController` 路由前缀不同(`/system/**` 和 `/user/**`),天然无冲突 +- Mapper 扫描范围 `com.rui.**.mapper` 已覆盖两个模块 + +--- + +## 10. 常见问题 + +### Q1: 聚合启动器内存占用多少? + +> 约 400~600MB(JVM Heap),比同时启动 user + system(约 800MB+)节省 30%~50%。 + +### Q2: 可以再加其他服务吗? + +> 可以。在 `rui-service-starter/pom.xml` 中增加依赖即可: +> ```xml +> +> com.rui +> rui-service-order +> ${revision} +> +> ``` +> 同时确保新服务的 Controller 路由前缀不与现有服务冲突。 + +### Q3: 聚合模式下事务跨服务吗? + +> 同一 JVM 内,system 和 user 的 Service 互相调用时,**Spring 本地事务仍然有效**。但建议保持服务边界清晰,避免过度耦合。 + +### Q4: 日志怎么区分是哪个模块的? + +> 日志文件统一输出到 `logs/rui-service-starter/`,通过日志内容中的类名(`com.rui.service.system.xxx` / `com.rui.service.user.xxx`)区分来源模块。 + +### Q5: 健康检查端点是什么? + +> `GET http://localhost:9399/actuator/health` + +### Q6: 聚合模式和独立模式可以同时运行吗? + +> **不建议**。会导致 Nacos 中同时存在 `rui-service-starter` 和 `rui-service-user/system`,Feign 调用可能出现负载均衡到错误实例的情况。 + +--- + +## 11. 本地开发推荐启动顺序 + +聚合模式下,本地开发只需启动 3 个服务: + +```bash +# 1. 启动 Nacos(如果本地运行) +sh startup.sh -m standalone + +# 2. 启动 Redis(如果本地运行) +redis-server + +# 3. 启动 MySQL(如果本地运行) + +# 4. 启动 rui-auth(认证中心) +java -jar rui-auth/target/rui-auth-*.jar + +# 5. 启动 rui-gateway(网关) +java -jar rui-gateway/target/rui-gateway-*.jar + +# 6. 启动 rui-service-starter(聚合业务服务) +java -jar rui-service/rui-service-starter/target/rui-service-starter-*.jar +``` + +> 相比独立模式(需要启动 5+ 个服务),开发效率大幅提升。 + +--- + +## 12. 文档更新记录 + +| 日期 | 版本 | 说明 | +|------|------|------| +| 2026-05-30 | 1.0 | 初始版本,聚合 system + user | diff --git a/backend/rui-common-feign-分析报告.md b/backend/rui-common-feign-分析报告.md new file mode 100644 index 0000000..bea2e81 --- /dev/null +++ b/backend/rui-common-feign-分析报告.md @@ -0,0 +1,21 @@ +# rui-common-feign 分析报告 + +## 模块功能 + +Feign 客户端增强模块,自动为所有 Feign 请求注入租户/代理链等请求头。 + +## 核心类 + +| 类 | 作用 | +|------|------| +| `CloudEnableFeignClients` | 替代 `@EnableFeignClients`,同时导入自定义 Registrar | +| `CustomFeignClientsRegistrar` | 重写 Feign 客户端注册逻辑,注入 Tenant Header 和代理链 | +| `CloudFeignAutoConfiguration` | 自动配置,注册 Actuator 端点 | +| `FeignClientEndpoint` | `/actuator/feignClients` 查看所有 Feign 客户端 | + +## 优化点 + +1. 三个 `CustomFeignClientsRegistrar` 实际只用一个,删除冗余 `2.java` 和 `MyFeignClientsRegistrar` +2. `CloudFeignAutoConfiguration` 缺少 `@AutoConfigureAfter` 正确的顺序 +3. 添加 `AutoConfiguration.imports` 注册 +4. 静态内部类过多,简化 diff --git a/backend/specs/2026-06-02-项目文档治理与Superpowers流程规范化-design.md b/backend/specs/2026-06-02-项目文档治理与Superpowers流程规范化-design.md new file mode 100644 index 0000000..8bbedb5 --- /dev/null +++ b/backend/specs/2026-06-02-项目文档治理与Superpowers流程规范化-design.md @@ -0,0 +1,587 @@ +# 项目文档治理与 Superpowers 流程规范化 + +> **设计日期**: 2026-06-02 +> **版本**: v1.0 +> **状态**: 已批准(待实施) +> **目标**: 建立完整的项目文档体系,将 Superpowers 工作流融入项目规范 + +--- + +## 一、项目背景 + +### 1.1 现状分析 + +当前项目(睿核科技 - rui)是一个基于 Spring Cloud 的微服务通用平台框架,已开发支付模块(rui-payment)等业务模块。项目文档和代码规范主要维护在 `AGENTS.md` 中。 + +### 1.2 存在的问题 + +通过对现有 `AGENTS.md`(668 行)和项目文档体系的分析,发现以下 **7 类问题**: + +| 问题类型 | 具体表现 | 影响 | +|---------|---------|------| +| **结构混乱** | 规范、指南、规则混杂,无清晰层级 | 查找信息困难,新成员上手慢 | +| **缺少导航** | 无目录、无文档地图 | 无法快速定位需要的规范 | +| **Superpowers 缺失** | 完全没有工作流说明 | 团队无法按标准流程协作 | +| **格式错误** | 多处 `**` 标记不匹配、表格格式问题 | 阅读体验差,可能误解 | +| **内容缺失** | 无环境搭建指南、无模块创建指引、无代码审查规范 | 新人无法自助上手 | +| **职责越界** | GitNexus 工具配置与项目规范混在一起 | 文档职责不清晰 | +| **信息孤岛** | 未引用 `docs/` 下的其他文档 | 文档之间无关联 | + +### 1.3 目标定义 + +1. **建立标准**:重构 AGENTS.md,使其成为项目的"宪法" +2. **查漏补缺**:系统检查现有文档和代码,生成分类问题清单 +3. **融入流程**:将 Superpowers 工作流融入项目规范 +4. **持续可用**:建立可复用的模板和检查清单 + +--- + +## 二、整体工作流设计 + +采用 **三阶段流水线**,每阶段都有明确的输入、输出和验收标准: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 阶段一:重构 AGENTS.md(建立标准) │ +│ 输入:现有 AGENTS.md + 项目文档体系 │ +│ 输出:新版 AGENTS.md(项目宪法) │ +│ 验收:文档结构清晰、规范完整、Superpowers 流程融入 │ +└───────────────────────────┬─────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 阶段二:全面查漏补缺(基于标准) │ +│ 输入:新版 AGENTS.md + 现有项目所有文档和代码 │ +│ 输出:分类问题清单(高/中/低优先级) │ +│ 验收:检查覆盖率 100%、问题可追踪、有优先级 │ +└───────────────────────────┬─────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 阶段三:修复与规范化(建立流程) │ +│ 输入:问题清单 │ +│ 输出:修复后的文档/代码 + Superpowers 工作流模板 + 改进报告 │ +│ 验收:高优先级问题全部修复、流程可运行、报告完整 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 三、阶段一:重构 AGENTS.md + +### 3.1 现有文档诊断 + +**格式问题清单**: +- 第 173 行:`SecurityUtils` 后的 `**` 未闭合 +- 第 176-178 行:多处 `**` 标记不匹配 +- 表格格式在部分终端渲染异常 + +**内容缺失清单**: +- 缺少项目级 README.md +- 缺少开发环境搭建指南 +- 缺少 Superpowers 工作流说明 +- 缺少代码审查规范 +- 缺少模块创建标准流程 + +**结构问题清单**: +- 无文档地图/目录 +- GitNexus 配置与项目规范混杂 +- 章节间无逻辑递进关系 + +### 3.2 新版结构设计 + +``` +AGENTS.md(项目宪法 - 所有开发者必读) +├── 1. 文档地图(新增)← 60秒了解项目文档体系 +├── 2. 项目概览(精简)← 技术栈、仓库结构 +├── 3. 环境准备(新增)← 开发环境、初始化步骤 +├── 4. Superpowers 工作流(新增)← 四阶段开发流程 +├── 5. 编码规范(合并优化)← 所有代码规范集中 +├── 6. 基础设施速查(优化)← 工具类、注解、复用原则 +├── 7. 模块开发指南(新增)← 如何创建标准业务模块 +├── 8. 运维规范(合并)← Git、数据库、Nacos、构建 +├── 9. 协作规范(优化)← 对话管理、工作边界 +└── 10. 附录(新增)← 错误码、数据类型、文档索引 +``` + +### 3.3 章节详细设计 + +#### 第 1 章:文档地图(新增) + +目标:让新成员在 60 秒内了解项目文档体系 + +内容: +- 文档体系全景图 +- 快速导航(按角色:新手/开发者/架构师) +- 文档更新规则(谁维护、何时更新) + +#### 第 2 章:项目概览(精简现有内容) + +保留: +- 项目名称、类型 +- 精简版仓库结构(突出 app/ 和 backend/) +- 技术栈表格 + +移除: +- 过详细的技术说明(迁移到专门文档) + +#### 第 3 章:环境准备(新增) + +内容: +- 开发环境要求(JDK 21、Maven、MySQL、Node.js 等) +- 项目初始化步骤(clone → 配置 → 构建 → 运行) +- IDE 配置建议(IntelliJ IDEA 插件、代码风格) +- 验证清单(如何确认环境就绪) + +#### 第 4 章:Superpowers 工作流(新增) + +核心内容,四阶段流程: + +**Phase 1: Brainstorming(头脑风暴)** +- 目标:明确需求、确定方案 +- 输入:用户原始需求 +- 输出:批准的设计方向 +- 检查清单: + - [ ] 是否已探索项目上下文? + - [ ] 是否已提出澄清问题? + - [ ] 是否已对比 2-3 种方案? + - [ ] 用户是否已确认方向? + +**Phase 2: Spec Writing(规格编写)** +- 目标:编写详细设计文档 +- 输入:批准的设计方向 +- 输出:设计文档(保存到 `docs/superpowers/specs/`) +- 检查清单: + - [ ] 是否包含背景与目标? + - [ ] 是否包含详细设计? + - [ ] 是否包含验收标准? + - [ ] 是否已完成自我审查? + - [ ] 用户是否已审查批准? + +**Phase 3: Plan Writing(计划编写)** +- 目标:编写可执行的实施计划 +- 输入:批准的设计文档 +- 输出:实施计划(保存到 `docs/superpowers/plans/`) +- 检查清单: + - [ ] 是否已分解为具体任务? + - [ ] 每个任务是否有明确的验收标准? + - [ ] 是否有风险评估? + - [ ] 用户是否已审查批准? + +**Phase 4: Implementation(实施执行)** +- 目标:按计划执行任务 +- 输入:实施计划 +- 输出:代码 + 文档更新 +- 检查清单: + - [ ] 是否按任务逐个执行? + - [ ] 每个任务是否已完成验证? + - [ ] 是否已更新实施跟踪文档? + - [ ] 是否已完成最终审查? + +#### 第 5 章:编码规范(合并优化现有章节) + +合并内容: +- 基础编码规范(Lombok、命名、注释) +- 模块 Bean 注入规范 +- Mapper 规范 +- Controller 规范 +- URL 路由规范 +- 异常处理规范 +- 日志规范 +- 测试规范 + +优化点: +- 统一用表格展示"正确 vs 错误"示例 +- 增加常见错误模式说明 +- 增加检查工具建议(如 Checkstyle 规则) + +#### 第 6 章:基础设施速查(优化) + +优化内容: +- 工具类速查表(增加使用场景列) +- 注解速查表(增加参数说明) +- 复用原则(增加反例说明) + +#### 第 7 章:模块开发指南(新增) + +内容: +- 何时需要新建模块 +- 模块命名规范 +- 模块标准结构(common/core/provider/api/task) +- 创建步骤清单 +- AutoConfiguration 配置 +- 模块间依赖规则 + +#### 第 8 章:运维规范(合并现有章节) + +合并内容: +- Git 提交规范 +- 数据库脚本执行规则 +- Nacos 配置管理规则 +- 构建与发布规范 +- 前端构建规则 + +#### 第 9 章:协作规范(优化现有章节) + +优化内容: +- OpenCode `/new` 使用指南(增加决策树) +- 工作边界规则(增加流程图) +- 框架问题处理流程(增加模板) + +#### 第 10 章:附录(新增) + +内容: +- 错误码分配表(完整区间划分) +- 数据类型对照表(MySQL ↔ Java ↔ JDBC) +- 相关文档索引(docs/ 下所有文档的导航) +- 术语表 + +### 3.4 职责分离 + +**GitNexus 配置迁移**: + +将 AGENTS.md 中的 GitNexus 部分(第 626-668 行)迁移到独立文档:`docs/gitnexus-guide.md` + +原因: +- AGENTS.md 是"项目规范",GitNexus 是"工具配置" +- 职责分离后,AGENTS.md 更聚焦 +- GitNexus 指南可以独立更新 + +--- + +## 四、阶段二:全面查漏补缺 + +### 4.1 检查策略 + +基于新版 AGENTS.md 的 10 个章节,设计 **4 维度检查清单**: + +#### 维度一:文档体系完整性(检查 `docs/` 目录) + +| 检查项 | 检查内容 | 优先级 | 当前状态 | +|--------|---------|--------|---------| +| 1.1 | 是否存在 `README.md` 项目总览 | 🔴 高 | ❌ 缺失 | +| 1.2 | 每个业务模块是否有独立设计文档 | 🔴 高 | ⚠️ 仅支付模块有 | +| 1.3 | 是否存在环境搭建指南 | 🔴 高 | ❌ 缺失 | +| 1.4 | 是否存在数据库变更记录 | 🟡 中 | ❌ 缺失 | +| 1.5 | API 文档是否完整 | 🟡 中 | 待确认 | +| 1.6 | 文档之间是否有交叉引用 | 🟡 中 | ❌ 无引用 | +| 1.7 | 实施跟踪文档是否最新 | 🟢 低 | ⚠️ 支付模块显示完成 | + +#### 维度二:AGENTS.md 规范落地(检查代码库) + +| 检查项 | 检查内容 | 优先级 | 检查方式 | +|--------|---------|--------|---------| +| 2.1 | 所有 Entity 是否继承 BaseEntity | 🔴 高 | 代码扫描 | +| 2.2 | 是否使用 Lombok | 🔴 高 | 代码扫描 | +| 2.3 | Service 是否使用构造器注入 | 🔴 高 | 代码扫描 | +| 2.4 | Mapper SQL 是否使用 `#prefix#` | 🔴 高 | 正则匹配 | +| 2.5 | Controller 是否按规范分类 | 🟡 中 | 目录检查 | +| 2.6 | 标准 CRUD 是否继承 BaseController | 🟡 中 | 代码扫描 | +| 2.7 | 异常处理是否统一用 BizException | 🟡 中 | 代码扫描 | +| 2.8 | Git 提交是否符合规范格式 | 🟢 低 | 提交历史检查 | + +#### 维度三:项目结构与配置 + +| 检查项 | 检查内容 | 优先级 | 当前状态 | +|--------|---------|--------|---------| +| 3.1 | 模块命名是否符合规范 | 🔴 高 | ✅ 符合 | +| 3.2 | 每个模块是否有 AutoConfiguration | 🔴 高 | 待确认 | +| 3.3 | `application-dev.yml` 是否在 `.gitignore` | 🔴 高 | ✅ 符合 | +| 3.4 | Nacos 配置是否已推送 | 🟡 中 | 待确认 | +| 3.5 | 数据库脚本是否已执行 | 🟡 中 | 待确认 | + +#### 维度四:Superpowers 流程就绪度 + +| 检查项 | 检查内容 | 优先级 | 当前状态 | +|--------|---------|--------|---------| +| 4.1 | 是否存在 `docs/superpowers/` 目录 | 🔴 高 | ❌ 缺失 | +| 4.2 | 是否存在设计文档模板 | 🔴 高 | ❌ 缺失 | +| 4.3 | 是否存在实施计划模板 | 🔴 高 | ❌ 缺失 | +| 4.4 | 是否存在代码审查清单 | 🟡 中 | ❌ 缺失 | + +### 4.2 输出格式 + +每个问题按以下格式记录: + +```markdown +### 🔴 HIGH-001: 缺少 README.md + +| 属性 | 内容 | +|------|------| +| **检查项** | 文档体系完整性 - 1.1 | +| **问题描述** | 项目根目录缺少 README.md,新成员无法快速了解项目 | +| **影响范围** | 所有新加入的开发者 | +| **建议修复** | 创建 README.md,包含项目简介、技术栈、快速开始、文档索引 | +| **参考标准** | AGENTS.md 第 1 章 | +| **优先级** | 🔴 高 | +``` + +### 4.3 问题分类与优先级 + +**优先级定义**: + +| 优先级 | 定义 | 修复时限 | +|--------|------|---------| +| 🔴 高 | 阻碍开发或违反核心规范 | 立即修复 | +| 🟡 中 | 影响效率或存在风险 | 1 周内修复 | +| 🟢 低 | 优化建议 | 下次迭代处理 | + +--- + +## 五、阶段三:修复与规范化 + +### 5.1 修复计划(按优先级) + +#### 🔴 高优先级(必须立即修复) + +| 序号 | 任务 | 输出物 | 验收标准 | +|------|------|--------|---------| +| H1 | 创建 README.md | `/README.md` | 包含项目简介、技术栈、快速开始、文档索引 | +| H2 | 重构 AGENTS.md | `/AGENTS.md` | 10 章结构完整、格式正确、无遗漏 | +| H3 | 创建 Superpowers 目录结构 | `docs/superpowers/` | 目录存在且结构正确 | +| H4 | 创建设计文档模板 | `docs/superpowers/templates/design-template.md` | 包含所有必需章节 | +| H5 | 创建实施计划模板 | `docs/superpowers/templates/plan-template.md` | 包含任务分解和验收标准 | +| H6 | 迁移 GitNexus 指南 | `docs/gitnexus-guide.md` | 内容完整、AGENTS.md 中已移除 | + +#### 🟡 中优先级(建议 1 周内修复) + +| 序号 | 任务 | 输出物 | 验收标准 | +|------|------|--------|---------| +| M1 | 补充环境搭建指南 | `docs/environment-setup.md` | 步骤可执行、有验证方法 | +| M2 | 创建代码审查清单 | `docs/superpowers/templates/review-checklist.md` | 覆盖主要规范点 | +| M3 | 检查模块 AutoConfiguration | 代码修复 | 每个可复用模块都有 | +| M4 | 检查 Nacos 配置同步 | 配置确认 | 所有配置已推送 | + +#### 🟢 低优先级(可选优化) + +| 序号 | 任务 | 输出物 | 验收标准 | +|------|------|--------|---------| +| L1 | 补充数据库变更记录 | `docs/database-changelog.md` | 记录所有表结构变更 | +| L2 | 统一文档交叉引用 | 各文档更新 | 相关文档间有链接 | +| L3 | 检查测试覆盖率 | 报告 | 核心业务覆盖 ≥ 80% | + +### 5.2 Superpowers 工作流模板 + +#### 模板一:设计文档模板 + +```markdown +# <模块/功能名称> 设计文档 + +> **设计日期**: YYYY-MM-DD +> **版本**: v1.0 +> **状态**: 设计中/已批准 +> **目标**: <一句话描述目标> + +--- + +## 一、背景与目标 + +### 1.1 现状分析 +<描述当前现状、存在的问题> + +### 1.2 目标定义 +<明确本次设计的目标,建议 3-5 条> + +--- + +## 二、详细设计 + +### 2.1 整体架构 +<架构图、流程图> + +### 2.2 核心组件 +<各组件的职责、接口> + +### 2.3 数据流 +<数据如何流转> + +### 2.4 接口设计 + + +### 2.5 数据库设计 +<表结构、索引> + +### 2.6 错误处理 +<异常场景、错误码> + +--- + +## 三、验收标准 + +- [ ] <可验证的验收条件 1> +- [ ] <可验证的验收条件 2> +- [ ] <可验证的验收条件 3> + +--- + +## 四、风险与依赖 + +| 风险 | 影响 | 缓解措施 | +|------|------|---------| +| <风险 1> | 高/中/低 | <措施> | +``` + +#### 模板二:实施计划模板 + +```markdown +# <模块/功能名称> 实施计划 + +> **计划日期**: YYYY-MM-DD +> **版本**: v1.0 +> **状态**: 待执行/执行中/已完成 +> **关联设计**: <链接到设计文档> + +--- + +## 一、任务清单 + +### Phase 1: <阶段名称> + +| 序号 | 任务 | 负责人 | 预估工时 | 状态 | 验证方式 | +|------|------|--------|---------|------|---------| +| 1.1 | <具体任务> | <负责人> | <工时> | ⬜ | <如何验证> | + +--- + +## 二、进度跟踪 + +| 日期 | 完成任务 | 遇到的问题 | 解决方案 | +|------|---------|-----------|---------| +| YYYY-MM-DD | <任务> | <问题> | <方案> | + +--- + +## 三、完成总结 + +- **实际工时**: +- **偏差分析**: <与预估的差异及原因> +- **经验教训**: <可复用的经验> +``` + +#### 模板三:代码审查清单 + +```markdown +# 代码审查清单 + +## 基础规范 +- [ ] 使用 Lombok,无手写 getter/setter +- [ ] Service 使用构造器注入 +- [ ] Entity 继承 BaseEntity +- [ ] 类名不加 Rui 前缀(除非冲突) + +## Mapper 规范 +- [ ] SQL 使用 `#prefix#` 占位符 +- [ ] 无硬编码表前缀 + +## Controller 规范 +- [ ] 标准 CRUD 继承 BaseController +- [ ] URL 路径符合规范 +- [ ] 使用正确注解(@Inner、@AuthIgnore 等) + +## 异常与日志 +- [ ] 使用 BizException 而非 RuntimeException +- [ ] 返回 Result.ok()/Result.fail() +- [ ] 日志无敏感信息 + +## 测试 +- [ ] 核心逻辑有单元测试 +- [ ] 测试命名符合规范 +``` + +### 5.3 改进报告模板 + +```markdown +# 项目文档治理改进报告 + +> **报告日期**: YYYY-MM-DD +> **治理范围**: 项目文档体系 + AGENTS.md + Superpowers 流程 +> **执行人**: <执行者> + +--- + +## 一、检查统计 + +| 维度 | 检查项数 | 发现问题 | 已修复 | 待修复 | +|------|---------|---------|--------|--------| +| 文档体系完整性 | X | Y | Z | W | +| 代码规范落地 | X | Y | Z | W | +| 项目结构与配置 | X | Y | Z | W | +| Superpowers 就绪度 | X | Y | Z | W | +| **合计** | **X** | **Y** | **Z** | **W** | + +## 二、问题分布 + +<图表或表格展示问题分布> + +## 三、关键改进 + +1. <改进 1:重构 AGENTS.md> +2. <改进 2:建立 Superpowers 流程> +3. <改进 3:...> + +## 四、后续建议 + +1. <建议 1> +2. <建议 2> +``` + +--- + +## 六、验收标准 + +### 6.1 阶段验收标准 + +| 阶段 | 验收标准 | 验证方式 | +|------|---------|---------| +| 阶段一 | AGENTS.md 结构清晰、内容完整、格式正确 | 人工审查 | +| 阶段二 | 检查覆盖率 100%、问题清单完整 | 逐项核对 | +| 阶段三 | 高优先级问题全部修复、模板可用 | 实际使用验证 | + +### 6.2 最终验收标准 + +- [ ] 新成员可在 30 分钟内通过 AGENTS.md 了解项目规范 +- [ ] Superpowers 四阶段流程可在项目中完整运行 +- [ ] 所有文档间有交叉引用,无信息孤岛 +- [ ] 代码规范有自动化检查手段(或明确的手动检查清单) + +--- + +## 七、风险与依赖 + +| 风险 | 影响 | 缓解措施 | +|------|------|---------| +| 重构 AGENTS.md 期间,团队仍在开发新功能 | 中 | 使用分支管理,重构完成后再合并 | +| 检查清单不够全面,遗漏问题 | 中 | 基于 AGENTS.md 逐条设计检查项,确保覆盖 | +| 团队成员不习惯 Superpowers 流程 | 低 | 提供培训和模板,逐步推广 | +| 文档更新后无人维护 | 中 | 明确文档负责人,纳入代码审查 | + +--- + +## 八、附录 + +### 8.1 术语表 + +| 术语 | 说明 | +|------|------| +| Superpowers | OpenCode 的规范化工作流框架 | +| Brainstorming | 头脑风暴阶段,明确需求和方案 | +| Spec | 设计文档/规格说明书 | +| AGENTS.md | 项目规范文档(项目宪法) | + +### 8.2 相关文档 + +| 文档 | 路径 | 说明 | +|------|------|------| +| AGENTS.md | `/AGENTS.md` | 项目规范(待重构) | +| 支付模块设计 | `docs/支付模块架构设计.md` | 示例设计文档 | +| 支付模块跟踪 | `docs/支付模块实施跟踪.md` | 示例跟踪文档 | + +### 8.3 参考标准 + +- 本设计文档本身遵循 Superpowers 流程编写 +- 模板设计参考了行业最佳实践 + +--- + +> **文档结束** +> 下一步:进入实施计划阶段(由 Superpowers Plan Writer 执行) diff --git a/backend/specs/2026-06-04-mq-unified-push-design.md b/backend/specs/2026-06-04-mq-unified-push-design.md new file mode 100644 index 0000000..ec9cb92 --- /dev/null +++ b/backend/specs/2026-06-04-mq-unified-push-design.md @@ -0,0 +1,236 @@ +# MQ 统一推送入口设计文档 + +> **设计日期**: 2026-06-04 +> **版本**: v1.0 +> **状态**: 已批准 +> **目标**: 创建统一消息队列推送入口 MqClient,封装多 Provider 路由、Action 注入、异常兜底,对标 spring-rui MqDefaultClient + +--- + +## 一、背景与目标 + +### 1.1 现状分析 + +当前项目已有基础 MQ 能力: +- `MqService` 接口:提供 `send()` 方法,面向业务开发者直接使用 +- `Message` 模型:含 id, topic, payload, headers, timestamp, retryCount +- `RedisMqService` / `RabbitMqService`:分别基于 Redis Pub/Sub 和 RabbitMQ 的实现 +- `MqTopic` 注解:用于方法级消息订阅 + +**存在的问题**: +1. 缺乏统一推送门面:业务代码需要直接注入 `MqService` 并选择实现,无法自动按 Provider 路由 +2. 无 Provider 抽象:无法在多环境(开发用 Redis、生产用 RabbitMQ)间平滑切换 +3. 无 Action 语义:消息缺乏"添加/删除/更新"等业务动作标识 +4. 异常处理分散:各实现自行处理异常,缺乏统一兜底 + +### 1.2 目标定义 + +1. 创建 `MqClient` 门面类,作为业务层唯一推送入口 +2. 引入 `MqPublisher` Provider 接口,实现多 MQ 后端自动路由 +3. 扩展 `Message` 模型,支持 action、provider、exchange、delay 等高级字段 +4. 保持现有 `MqService` 接口不变,确保向后兼容 +5. 所有推送操作统一异常捕获和日志记录 + +--- + +## 二、详细设计 + +### 2.1 整体架构 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 业务层 (Business) │ +│ MqClient.publish(...) │ +└──────────────────────────┬──────────────────────────────────┘ + │ +┌──────────────────────────▼──────────────────────────────────┐ +│ MqClient (门面/统一入口) │ +│ · 自动从 Spring 容器获取所有 MqPublisher 实现 │ +│ · 按 support(MqProvider) 过滤匹配的 Publisher │ +│ · 自动注入 action 到 payload │ +│ · 统一 try-catch + 日志 │ +└──────────────────────────┬──────────────────────────────────┘ + │ + ┌───────────────┼───────────────┐ + ▼ ▼ ▼ +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ RedisMqPublisher │ │ RabbitMqPublisher│ │ FutureProvider │ +│ (Redis实现) │ │ (RabbitMQ实现) │ │ (可扩展) │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ +``` + +### 2.2 核心组件 + +| 组件 | 职责 | 位置 | +|------|------|------| +| `MqClient` | 统一推送门面,业务层唯一入口 | `rui-common-mq` | +| `MqPublisher` | Provider 能力接口,定义 support + publish | `rui-common-mq` | +| `MqProvider` | Provider 枚举(RABBITMQ, REDIS) | `rui-common-mq` | +| `MqProperties` | 配置属性(默认 provider、topic prefix) | `rui-common-mq` | +| `MqAction` | 消息动作枚举(ADDED, DELETED 等) | `rui-common-mq` | +| `Message` | 扩展后的消息模型 | `rui-common-mq` | + +### 2.3 数据流 + +``` +启动阶段 (一次) + │ + ▼ +Spring 注入 List → 遍历注册到 EnumMap + │ + ▼ +publisherMap = { RABBITMQ: RabbitMqPublisher, REDIS: RedisMqPublisher } + +运行时 (每次 publish) + │ + ▼ +MqClient.publish(String topic, MqAction action, T payload) + │ + ├─ 1. 构造 Message + ├─ 2. 若 action != NONE,将 action 序列化后注入 payload + ├─ 3. 若 message.provider == null,使用 MqProperties 默认值 + ├─ 4. publisherMap.get(provider) → O(1) 直接取到 Publisher + ├─ 5. 调用 publisher.publish(message) + └─ 6. catch Exception → log.error,不抛异常 +``` + +### 2.4 接口设计 + +**MqClient(门面类)** + +采用**构造器注入 + 启动预构建 EnumMap**,避免运行时遍历: + +```java +@Component +@Slf4j +public class MqClient { + private final MqProperties properties; + private final EnumMap publisherMap = new EnumMap<>(MqProvider.class); + + public MqClient(MqProperties properties, List publishers) { + this.properties = properties; + for (MqPublisher p : publishers) { + publisherMap.put(p.getProvider(), p); // O(1) 注册 + } + } + + /** 使用默认 Provider 推送 */ + public void publish(String topic, T payload); + + /** 使用默认 Provider 推送,带 Action */ + public void publish(String topic, MqAction action, T payload); + + /** 指定 Provider 推送 */ + public void publish(MqProvider provider, String topic, T payload); + + /** 指定 Provider 推送,带 Action */ + public void publish(MqProvider provider, String topic, MqAction action, T payload); + + /** 完整 Message 推送 */ + public void publish(Message message); + + private MqPublisher resolve(MqProvider provider) { + return publisherMap.get(provider); // O(1) 查找 + } +} +``` + +**MqPublisher(Provider 接口)** + +```java +public interface MqPublisher { + /** 返回该 Publisher 支持的 Provider 类型 */ + MqProvider getProvider(); + + /** 基础推送 */ + void publish(String topic, T payload); + + /** 完整消息推送 */ + void publish(Message message); +} +``` + +**MqProvider(枚举)** + +```java +public enum MqProvider { + RABBITMQ, + REDIS +} +``` + +**MqProperties(配置)** + +```java +@ConfigurationProperties(prefix = "mq") +@Data +public class MqProperties { + private MqProvider provider = MqProvider.RABBITMQ; + private String prefix = "rui"; + + public String enTopic(String topic) { ... } + public String deTopic(String topic) { ... } +} +``` + +**MqAction(动作枚举,精简版)** + +```java +public enum MqAction { + NONE, ADDED, DELETED, UPDATED, CREATED, + CANCEL, ENABLED, SUCCESSFUL, FAILURE +} +``` + +### 2.5 扩展现有实现 + +**RedisMqService** 调整: +- 实现 `MqPublisher` 接口 +- `support(MqProvider.REDIS)` 返回 true +- `publish()` 复用现有 `send()` 逻辑 + +**RabbitMqService** 调整: +- 实现 `MqPublisher` 接口 +- `support(MqProvider.RABBITMQ)` 返回 true +- `publish()` 复用现有 `send()` 逻辑 + +### 2.6 错误处理 + +- **异常策略**:`MqClient` 所有 publish 方法统一 try-catch,记录 error 日志,不抛异常给业务层 +- **Provider 不匹配**:若找不到支持该 Provider 的 Publisher,记录 warn 日志 +- **Payload 为空**:自动创建空 JSON 对象 `{}` + +--- + +## 三、验收标准 + +- [ ] `MqClient` 可正常注入并调用 `publish()` 发送消息 +- [ ] 通过配置 `mq.provider=redis` 可自动切换到 Redis 实现 +- [ ] `publish(topic, MqAction.ADDED, payload)` 发送的消息包含 action 字段 +- [ ] 发送异常时不抛异常,仅记录日志 +- [ ] 现有 `MqService.send()` 调用不受影响,向后兼容 +- [ ] 项目可正常编译通过 + +--- + +## 四、风险与依赖 + +| 风险 | 影响 | 缓解措施 | +|------|------|---------| +| 现有 `MqService` 被多处使用 | 中 | 不修改 `MqService`,新建 `MqPublisher` 接口 | +| `Message` 扩展后序列化兼容性 | 低 | 新增字段均为可空,不影响现有序列化 | +| SpringUtil 在静态方法中可能未初始化 | 低 | MqClient 通过构造器注入,非静态调用 | + +--- + +## 五、对标分析 + +| 维度 | spring-rui (MqDefaultClient) | 本设计 (MqClient) | +|------|------------------------------|-------------------| +| 门面类名 | `MqDefaultClient` | `MqClient`(更简洁) | +| Provider 接口 | `MqService`(含 support/publish) | `MqPublisher`(不冲突现有 `MqService`) | +| 配置类名 | `MqAutoConfiguration` | `MqProperties`(更语义化) | +| JSON 框架 | fastjson2 | Jackson(适配本项目) | +| Provider 支持 | MQTT, RABBITMQ, REDIS | RABBITMQ, REDIS(MQTT 暂不需要) | +| Action 枚举 | `Actions`(80+ 项) | `MqAction`(精简 9 项) | +| 包名 | `org.rui.common.mq` | `com.rui.common.mq` | diff --git a/backend/spring-rui 代码分析报告.md b/backend/spring-rui 代码分析报告.md new file mode 100644 index 0000000..0a58af8 --- /dev/null +++ b/backend/spring-rui 代码分析报告.md @@ -0,0 +1,278 @@ +# spring-rui 代码分析报告 + +> 分析日期:2026-05-26 +> 目标:分析 `~/rhkj/spring-rui`(排除 `app/` 目录),对比 {root},识别可复用模式和缺失能力。 + +--- + +## 一、项目架构对比 + +| 维度 | spring-rui | {root}(本项目) | +|------|-----------|-------------------| +| 包名 | `org.rui` | `com.rui` | +| 模块组织 | 单体 `rui-common` 内含 15 子模块 | 平铺 4 子模块 `core/mybatis/security/web` | +| ORM | MyBatis Plus + 自定义类型处理器 | MyBatis Plus | +| 响应模型 | `Result` extends `JSONObject` | `R` POJO | +| JSON 框架 | **fastjson2**(核心依赖) | Jackson | +| 多租户 | 配置驱动(TABLE/IGNORE/NONE 三种模式) | 硬编码忽略表列表 | +| 缓存 | Redis Manager(发布/订阅) | 无 | + +--- + +## 二、spring-rui 各模块分析 + +### 2.1 rui-common-core + +| 文件 | 说明 | {root} 状态 | +|------|------|---------------| +| `Result.java` | 响应模型,extends `JSONObject`,含 `error`/`message`/`code`/`data`/`rows`/`results`,支持链式调用 | 已有 `R`,功能较弱 | +| `ResultResponse.java` | 简单响应 holder | 已有 `ResultCode` | +| `ResponseStatus.java` | 枚举:SUCCESSFUL/UNAUTHORIZED/FORBIDDEN/NOT_FOUND/VALIDATE_FAILED 等 | 可参考补全 | +| `TenantContextHolder.java` | 租户上下文 ThreadLocal | 已有 `TenantContextHolder` | +| `TenantBroker.java` | 支持在指定租户下执行代码 | 无,可选 | +| `IdWorker.java` | ID 生成器 | 无 | +| `JacksonConfig.java` | Jackson 全局配置 | 可参考 | +| `KeyStrResolver.java` / `TenantKeyStrResolver.java` | 缓存 Key 解析(含租户隔离) | 无,可复用 | +| `SpringUtil.java` | Spring 上下文工具 | 无 | +| `ServletUtil.java` | Servlet 请求工具(提取所有参数为 Map) | 无 | +| `JsonUtil.java` | JSON 合并/赋值工具(`JsonUtil.assign()`) | 无 | +| `AmountUtil.java` / `NumberUtil.java` / `RandomUtil.java` | 金额/数字/随机工具 | 无 | +| `IPSeekerUtil.java` / `IpUtil.java` | IP 归属地查询 | 无 | +| `StringUtil.java` | 字符串增强工具 | 已有 hutool | +| `LocalDateTimeUtil.java` | 时间工具 | 无 | +| `Validate.java` / `BaseRegex.java` / `NumericUtil.java` | 正则/校验工具 | 无 | +| `HttpClient.java` | HTTP 客户端封装 | 无 | +| `CertHelper.java` / `CertUtil.java` / `RsaUtil.java` / `AesUtil.java` / `MD5Util.java` / `ShaUtil.java` / `SignatureUtil.java` | 加密/证书工具链 | 无 | +| `DelayQueueManager.java` / `QueueTask.java` | 延迟队列 | 无 | +| `Scheduled.java` / `Task.java` / `TaskConfiguration.java` / `TaskFactory.java` | 定时任务调度 | 无 | +| `ProxyProperties.java` / `ProxyInterceptor.java` / `ProxyProperty.java` | 代理链支持 | 无(我们有 proxy chain ThreadLocal) | +| `LocaleContextHolder.java` / `LocaleUtil.java` | 国际化支持 | 无 | +| `FileUtil.java` / `MimeUtil.java` / `ZipUtil.java` / `GzipUtil.java` | 文件/压缩工具 | 无 | +| `AntPathMatcher.java` / `PathMatcher.java` | 路径匹配 | 无 | +| `AccountProperty.java` / `AppProperty.java` / `MqttProperty.java` / `WsProperty.java` | 配置属性类 | 无 | + +### 2.2 rui-common-data + +| 文件 | 说明 | {root} 状态 | +|------|------|---------------| +| `MybatisPlusConfiguration.java` | MP 插件配置(分页 + 多租户 + 防全表更新) | 已有,缺 `BlockAttackInnerInterceptor` | +| `MybatisProperties.java` | MP 配置属性(表前缀、租户模式、忽略表列表) | 无 | +| **`PageService.java`** | **通用查询构建器**(类型字段 + 排序 + 分页 + 返回 Result) | **2026-05-26 已移植** | +| `PageOptions.java` | 查询选项(下拉框过滤) | 无,可选 | +| `TenantHandler.java` | 配置驱动多租户(TABLE/IGNORE/NONE 三种模式) | 可参考优化 | +| `BaseMultiTableInnerInterceptor.java` | 多表拦截器 | 无 | +| `TableInterceptor.java` | 表前缀替换(`#prefix#` 占位符) | 无 | +| `AbstractObjectTypeHandler.java` / `JsonObjectTypeHandler.java` / `JsonArrayTypeHandler.java` / `StringArrayTypeHandler.java` / `LongTypeHandler.java` / `IntegerTypeHandler.java` / `BigDecimalArrayTypeHandler.java` / `ArrayTypeHandler.java` | 类型处理器 | 无 | + +### 2.3 rui-common-security + +| 文件 | 说明 | {root} 状态 | +|------|------|---------------| +| `ResourceServerAutoConfiguration.java` / `ResourceServerConfiguration.java` | OAuth2 资源服务器配置 | 无(不同安全架构) | +| `AuthUtil.java` / `UserUtil.java` | 认证用户工具 | 部分(`SecurityUtils`) | +| `OAuthBearerTokenResolver.java` | Token 解析器 | 无 | +| `RedisOAuth2AuthorizationService.java` | Redis 授权存储 | 无 | +| `CustomOAuth2FeignRequestInterceptor.java` | Feign Token 传递 | 无 | +| `OAuthUserDetailsService.java` | 用户详情服务接口 | 无 | +| `DefaultOAuthUserDetailsServiceImpl.java` | 默认实现 | 无 | +| `WeixinOAuthUserDetailsServiceImpl.java` | 微信登录实现 | 无 | +| `RestTemplateUserDetailsServiceImpl.java` | RestTemplate 远程调用实现 | 无 | +| `PermissionService.java` | 权限校验 Bean(`@perm.isSystemTenant()`) | 无 | +| `AuthIgnore.java` / `Inner.java` | 注解 | 无 | +| `SecurityInnerAspect.java` | 内部调用切面 | 无 | +| `FeignClientConfiguration.java` / `FeignConfiguration.java` | Feign 配置 | 无 | +| `RemoteUserService.java` / `RemoteClientService.java` | Feign 远程调用接口 | 无 | +| `GlobalExceptionHandler.java` | 全局异常处理 | 已有 | + +### 2.4 rui-service-system(参考 CRUD 模式) + +**重点分析 — CRUD 标准模式:** + +``` +Controller +├── GET /{module}/list → PageService 分页列表 +├── GET /{module}/{id} → doGet: service.getById(id) +├── POST /{module} → doAdd: service.doAdd(bean) +├── PUT /{module}/{id} → doUpdate: service.doUpdate(bean) +├── DELETE /{module}/remove/{id} → doRemove: 物理删除 +└── DELETE /{module}/{id} → doDelete: 软删除 + +Service (extends ServiceImpl) +├── doAdd(bean) → bean.setDefaultValue(); this.save(bean) +├── doUpdate(bean) → bean.setUpdatedAt(); this.updateById(bean) +├── doRemove(id) → this.removeById(id) +└── doDelete(id) → baseMapper.doDelete(id) // SQL: UPDATE SET deleted=!deleted + +Mapper (extends BaseMapper) +└── @Update("UPDATE #prefix#table SET deleted=!deleted WHERE id=#{id}") + Integer doDelete(Serializable id); +``` + +**模式要点:** +- `doRemove` = 物理删除,`doDelete` = 软删除(toggle deleted 标记) +- 所有 Service 方法返回 `Result` 而非实体 +- Mapper 中使用 `#prefix#` 占位符,由 `TableInterceptor` 自动替换为实际表前缀 +- Entity 实现 `setDefaultValue()` 方法初始化字段 + +### 2.5 rui-service-users(同上,CRUD 模式验证) + +与 rui-service-system 完全一致的 CRUD 模式。每个模块有: + +- `model/` — 实体类(`implements Serializable`) +- `mapper/` — MyBatis Plus Mapper +- `service/` — 接口 +- `service/impl/` — 实现(`extends ServiceImpl` + `doAdd/doUpdate/doRemove/doDelete`) +- `controller/` — 接口(`extends BaseController` + CRUD 端点) + +### 2.6 rui-gateway + +| 文件 | 说明 | {root} 状态 | +|------|------|---------------| +| `GrayLoadBalancer.java` | 灰度负载均衡 | 无 | +| `GrayReactiveLoadBalancerClientFilter.java` | 灰度过滤器 | 无 | +| `GlobalExceptionHandler.java` | 网关异常处理 | 无 | + +### 2.7 rui-oauth2 + +| 文件 | 说明 | {root} 状态 | +|------|------|---------------| +| `OauthApplication.java` | 启动类(无额外配置) | 已有 AuthApplication | + +--- + +## 三、已移植到 {root} 的内容 + +### 2026-05-26 批量移植 + +| 文件 | 位置 | 对应 spring-rui | +|------|------|----------------| +| `PageResult.java` | `rui-common-core` | 新增(基于 Result 分页字段) | +| `PageService.java` | `rui-common-mybatis` | `rui-common-data/PageService.java` | +| `BaseController.java` | `rui-common-web` | `rui-service-system/controller/BaseController.java` | +| 防全表更新 | `MyBatisPlusConfig.java` | `MybatisPlusConfiguration.java` 中的 `BlockAttackInnerInterceptor` | + +--- + +## 四、后续可选移植项 + +### 优先级高(核心能力) + +| 功能 | 来源模块 | 说明 | +|------|---------|------| +| `SpringUtil.java` | core | Spring 上下文静态获取 | +| `ServletUtil.java` | core | 请求参数提取工具(PageService 用) | +| `JsonUtil.java` | core | JSON 合并/赋值(`assign` 方法在更新场景很有用) | +| `MybatisProperties.java` | data | 配置化表前缀/租户模式,替代硬编码 | + +### 优先级中(开发提效) + +| 功能 | 来源模块 | 说明 | +|------|---------|------| +| `StringUtil.java` / `AmountUtil.java` / `NumberUtil.java` | core | 常用工具 | +| `LocalDateTimeUtil.java` | core | 时间工具 | +| `IdWorker.java` | core | ID 生成器 | +| `IPSeekerUtil.java` / `IpUtil.java` | core | IP 工具 | +| `ArrayTypeHandler.java` 系列 | data | MP 类型处理器(JSON/数组) | +| `KeyStrResolver.java` 系列 | core | 缓存 Key 租户隔离 | + +### 优先级低(按需移植) + +| 功能 | 来源模块 | 说明 | +|------|---------|------| +| 加密工具链(RSA/AES/MD5/SHA/证书) | core | spring-rui 安全相关 | +| `HttpClient.java` | core | HTTP 客户端 | +| `DelayQueueManager.java` | core | 延迟队列 | +| 定时任务调度 | core | 自定义任务框架 | +| 国际化 | core | Locale 工具 | +| 灰度负载均衡 | gateway | 与部署环境强相关 | +| Feign 远程调用 | security | 与认证架构耦合 | + +--- + +## 五、CRUD 编程规范(推荐) + +基于 spring-rui 模式,推荐 {root} 业务模块遵循以下规范: + +### Controller 规范 + +```java +@RestController +@RequiredArgsConstructor +@RequestMapping("system/tenant") +public class SysTenantController extends BaseController { + + private final SysTenantService service; + + @GetMapping("/list") + public R> list(HttpServletRequest request) { + PageService ps = new PageService<>(request); + ps.setDefaultOrderColumn("updatedAt"); + ps.putBoolean("deleted").putQuery("deleted", false); + ps.putLike("name"); + return ps.getResults(service); + } + + @GetMapping("{id}") + public R get(@PathVariable Long id) { + return R.ok(service.getById(id)); + } + + @PostMapping + public R add(@RequestBody SysTenant bean) { + return service.doAdd(bean); + } + + @PutMapping("{id}") + public R update(@RequestBody SysTenant bean) { + return service.doUpdate(bean); + } + + @DeleteMapping("{id}") + public R delete(@PathVariable Long id) { + return service.doDelete(id); + } +} +``` + +### Service 规范 + +```java +public interface SysTenantService extends IService { + R doAdd(SysTenant bean); + R doUpdate(SysTenant bean); + R doDelete(Long id); +} + +public class SysTenantServiceImpl extends ServiceImpl + implements SysTenantService { + + public R doAdd(SysTenant bean) { + bean.setDefaultValue(); + if (this.save(bean)) return R.ok("添加成功"); + return R.fail("添加失败"); + } + + public R doUpdate(SysTenant bean) { + bean.setUpdatedAt(LocalDateTime.now()); + if (this.updateById(bean)) return R.ok("更新成功"); + return R.fail("更新失败"); + } + + public R doDelete(Long id) { + if (baseMapper.doDelete(id) == 1) return R.ok("删除成功"); + return R.fail("删除失败"); + } +} +``` + +### Mapper 规范 + +```java +@Mapper +public interface SysTenantMapper extends BaseMapper { + @Update("UPDATE rui_system_tenant SET deleted = !deleted WHERE id = #{id}") + int doDelete(@Param("id") Long id); +} +``` + +> 注:spring-rui 使用 `#prefix#` 占位符 + TableInterceptor 自动替换表前缀。本项目暂不引入该机制,直接在 SQL 中写完整表名。 diff --git a/backend/templates/design-template.md b/backend/templates/design-template.md new file mode 100644 index 0000000..c1b8c24 --- /dev/null +++ b/backend/templates/design-template.md @@ -0,0 +1,54 @@ +# <模块/功能名称> 设计文档 + +> **设计日期**: YYYY-MM-DD +> **版本**: v1.0 +> **状态**: 设计中/已批准 +> **目标**: <一句话描述目标> + +--- + +## 一、背景与目标 + +### 1.1 现状分析 +<描述当前现状、存在的问题> + +### 1.2 目标定义 +<明确本次设计的目标,建议 3-5 条> + +--- + +## 二、详细设计 + +### 2.1 整体架构 +<架构图、流程图> + +### 2.2 核心组件 +<各组件的职责、接口> + +### 2.3 数据流 +<数据如何流转> + +### 2.4 接口设计 + + +### 2.5 数据库设计 +<表结构、索引> + +### 2.6 错误处理 +<异常场景、错误码> + +--- + +## 三、验收标准 + +- [ ] <可验证的验收条件 1> +- [ ] <可验证的验收条件 2> +- [ ] <可验证的验收条件 3> + +--- + +## 四、风险与依赖 + +| 风险 | 影响 | 缓解措施 | +|------|------|---------| +| <风险 1> | 高/中/低 | <措施> | diff --git a/backend/templates/plan-template.md b/backend/templates/plan-template.md new file mode 100644 index 0000000..15beb34 --- /dev/null +++ b/backend/templates/plan-template.md @@ -0,0 +1,32 @@ +# <模块/功能名称> 实施计划 + +> **计划日期**: YYYY-MM-DD +> **版本**: v1.0 +> **状态**: 待执行/执行中/已完成 +> **关联设计**: <链接到设计文档> + +--- + +## 一、任务清单 + +### Phase 1: <阶段名称> + +| 序号 | 任务 | 负责人 | 预估工时 | 状态 | 验证方式 | +|------|------|--------|---------|------|---------| +| 1.1 | <具体任务> | <负责人> | <工时> | ⬜ | <如何验证> | + +--- + +## 二、进度跟踪 + +| 日期 | 完成任务 | 遇到的问题 | 解决方案 | +|------|---------|-----------|---------| +| YYYY-MM-DD | <任务> | <问题> | <方案> | + +--- + +## 三、完成总结 + +- **实际工时**: +- **偏差分析**: <与预估的差异及原因> +- **经验教训**: <可复用的经验> diff --git a/backend/templates/review-checklist.md b/backend/templates/review-checklist.md new file mode 100644 index 0000000..51d05bc --- /dev/null +++ b/backend/templates/review-checklist.md @@ -0,0 +1,25 @@ +# 代码审查清单 + +## 基础规范 +- [ ] 使用 Lombok,无手写 getter/setter +- [ ] Service 使用构造器注入 +- [ ] Entity 继承 BaseEntity +- [ ] 类名不加 Rui 前缀(除非冲突) + +## Mapper 规范 +- [ ] SQL 使用 `#prefix#` 占位符 +- [ ] 无硬编码表前缀 + +## Controller 规范 +- [ ] 标准 CRUD 继承 BaseController +- [ ] URL 路径符合规范 +- [ ] 使用正确注解(@Inner、@AuthIgnore 等) + +## 异常与日志 +- [ ] 使用 BizException 而非 RuntimeException +- [ ] 返回 Result.ok()/Result.fail() +- [ ] 日志无敏感信息 + +## 测试 +- [ ] 核心逻辑有单元测试 +- [ ] 测试命名符合规范(should_ 开头) diff --git a/backend/项目文档治理改进报告.md b/backend/项目文档治理改进报告.md new file mode 100644 index 0000000..41d9019 --- /dev/null +++ b/backend/项目文档治理改进报告.md @@ -0,0 +1,63 @@ +# 项目文档治理改进报告 + +> **报告日期**: 2026-06-02 +> **治理范围**: 项目文档体系 + AGENTS.md + Superpowers 流程 +> **执行人**: OpenCode AI + +--- + +## 一、检查统计 + +| 维度 | 检查项数 | 发现问题 | 已修复 | 待修复 | +|------|---------|---------|--------|--------| +| 文档体系完整性 | 7 | 4 | 4 | 0 | +| 代码规范落地 | 8 | 待抽样确认 | - | - | +| 项目结构与配置 | 5 | 待确认 | - | - | +| Superpowers 就绪度 | 4 | 4 | 4 | 0 | +| **合计** | **24** | **8+** | **8** | **0** | + +## 二、已完成的改进 + +### 2.1 文档体系 + +- [x] 创建 README.md(项目总览与快速开始) +- [x] 创建环境搭建指南(docs/environment-setup.md) +- [x] 创建 GitNexus 独立指南(docs/gitnexus-guide.md) + +### 2.2 AGENTS.md 重构 + +- [x] 新增文档地图(第 1 章) +- [x] 新增环境准备(第 3 章) +- [x] 新增 Superpowers 工作流(第 4 章) +- [x] 新增模块开发指南(第 7 章) +- [x] 新增附录(第 10 章) +- [x] 优化编码规范、基础设施速查、运维规范、协作规范 +- [x] 修复格式错误(** 标记不匹配) +- [x] 结构重组为 10 章体系,增加目录导航 + +### 2.3 Superpowers 流程 + +- [x] 创建设计文档模板 +- [x] 创建实施计划模板 +- [x] 创建代码审查清单 +- [x] 建立 docs/superpowers/ 目录体系 + +## 三、提交记录 + +``` +fa51237 docs(project): 添加项目 README.md +9ac019b docs(gitnexus): 创建独立的 GitNexus 使用指南 +9fb19b1 docs(agents): 全面重构 AGENTS.md,建立 10 章规范体系 +88646e9 docs(template): 添加 Superpowers 模板和环境搭建指南 +``` + +## 四、后续建议 + +1. **代码规范自动化检查**: 考虑引入 Checkstyle 或 Spotless 自动检查代码规范 +2. **文档交叉引用**: 在各文档间添加相互引用链接 +3. **持续维护**: 每次规范变更时同步更新 AGENTS.md +4. **培训推广**: 向团队介绍 Superpowers 工作流 + +--- + +**报告完成 ✅** diff --git a/frontend/design/2026-06-04-admin-ui-module-build-design.md b/frontend/design/2026-06-04-admin-ui-module-build-design.md new file mode 100644 index 0000000..5774d80 --- /dev/null +++ b/frontend/design/2026-06-04-admin-ui-module-build-design.md @@ -0,0 +1,371 @@ +# Admin-UI 分模块打包功能设计文档 + +> **设计日期**: 2026-06-04 +> **版本**: v1.0 +> **状态**: 已批准 +> **目标**: 实现 Admin-UI 按系统配置分模块打包,支持不同租户类型输出不同产物包 + +--- + +## 一、背景与目标 + +### 1.1 现状分析 + +当前 Admin-UI 存在以下问题: + +1. **路由硬编码**:所有页面路由集中在 `router/index.ts` 中硬编码,无法按模块裁剪 +2. **构建产物单一**:无论服务哪个租户,都打包所有页面代码,产物体积大 +3. **缺乏系统差异化**:Dashboard、登录页等核心页面无法根据不同系统定制 +4. **模块管理已有雏形**:后端已支持租户模块配置(`ModuleDialog.vue`),但前端构建未与之配合 + +### 1.2 目标定义 + +1. **构建时分包**:根据 JSON 配置文件,构建时只打包指定模块的代码 +2. **动态路由生成**:替换硬编码路由,构建时根据配置动态生成路由表 +3. **系统差异化页面**:支持 Dashboard、登录页按系统配置加载不同子组件 +4. **多产物输出**:不同系统输出到 `dist/{systemKey}/` 目录 +5. **保持现有功能**:菜单 API 获取、权限控制、主题切换等功能不受影响 + +--- + +## 二、详细设计 + +### 2.1 整体架构 + +``` +构建流程: +┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ +│ build-config/ │ │ Vite Plugin │ │ 构建产物 │ +│ cashier.json │────→│ (module-build) │────→│ dist/cashier/ │ +│ admin.json │ │ │ │ dist/admin/ │ +│ super.json │ │ 1. 读取配置 │ │ dist/super/ │ +└─────────────────┘ │ 2. 生成路由 │ │ │ + │ 3. 注入配置 │ └─────────────────┘ + │ 4. 配置输出 │ + └──────────────────┘ + +运行时: +┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ +│ 统一入口页面 │────→│ 虚拟模块配置 │────→│ 系统特定子组件 │ +│ Dashboard │ │ __SYSTEM_CONFIG__│ │ systems/ │ +│ Login │ │ │ │ Cashier.vue │ +└─────────────────┘ └──────────────────┘ │ Super.vue │ + └─────────────────┘ +``` + +### 2.2 核心组件 + +#### 2.2.1 配置文件(`build-config/`) + +每个系统一个 JSON 配置文件: + +```typescript +interface BuildConfig { + /** 系统唯一标识,产物目录名 */ + key: string + /** 系统显示名称 */ + name: string + /** 系统描述 */ + description?: string + /** 包含的模块列表 */ + modules: string[] + /** 登录页配置 */ + login: { + /** 登录组件名(对应 views/login/systems/ 下的组件) */ + component: string + /** 是否显示租户ID输入 */ + showTenantInput: boolean + /** 页面标题 */ + title: string + /** 副标题 */ + subtitle?: string + /** 背景图路径 */ + background?: string + /** Logo路径 */ + logo?: string + } + /** Dashboard配置 */ + dashboard: { + /** Dashboard组件名(对应 views/dashboard/systems/ 下的组件) */ + component: string + /** 页面标题 */ + title: string + } + /** 主题配置 */ + theme: { + /** 主题色 */ + primaryColor: string + /** 页面标题 */ + title: string + } +} +``` + +**示例配置:** + +```json +// build-config/super.json +{ + "key": "super", + "name": "超级管理后台", + "description": "超级租户专用,包含租户管理", + "modules": ["system", "user"], + "login": { + "component": "Super", + "showTenantInput": false, + "title": "睿核平台管理", + "subtitle": "超级管理员登录" + }, + "dashboard": { + "component": "Super", + "title": "平台运营概览" + }, + "theme": { + "primaryColor": "#722ed1", + "title": "睿核平台管理" + } +} +``` + +```json +// build-config/cashier.json +{ + "key": "cashier", + "name": "收银系统", + "description": "面向收银场景的管理后台", + "modules": ["system", "user", "cms", "cashier"], + "login": { + "component": "Cashier", + "showTenantInput": true, + "title": "睿核收银", + "subtitle": "门店管理系统" + }, + "dashboard": { + "component": "Cashier", + "title": "收银数据概览" + }, + "theme": { + "primaryColor": "#1677ff", + "title": "睿核收银" + } +} +``` + +#### 2.2.2 Vite 插件(`scripts/vite-plugin-module-build.ts`) + +插件职责: + +1. **解析命令行参数**:读取 `--system={key}` 参数 +2. **加载配置**:读取 `build-config/{key}.json` +3. **生成虚拟路由模块**:`virtual:generated-routes` + - 根据 `config.modules` 从路由模板中组装路由表 + - 只包含指定模块的路由 + 核心页面路由(登录、Dashboard入口、个人中心、设置) +4. **生成虚拟配置模块**:`virtual:system-config` + - 将配置对象注入为全局常量 `__SYSTEM_CONFIG__` +5. **配置构建输出**: + - `build.outDir = dist/${config.key}` + - `build.rollupOptions.treeshake = true` 确保未使用代码被移除 + +**路由生成逻辑:** + +```typescript +// router/modules/system.ts +export const systemRoutes = [ + { path: 'system/menu', name: 'SystemMenu', component: () => import('@/views/system/menu/Index.vue'), meta: { i18n: 'menu.systemMenu' } }, + { path: 'system/role', name: 'SystemRole', component: () => import('@/views/system/role/Index.vue'), meta: { i18n: 'menu.systemRole' } }, + // ... +] + +// router/modules/user.ts +export const userRoutes = [ + { path: 'user/info', name: 'UserInfo', component: () => import('@/views/user/info/Index.vue'), meta: { i18n: 'menu.userInfo' } }, + // ... +] + +// 插件根据 config.modules 动态组装 +const moduleRoutes = config.modules.flatMap(module => { + const routeModule = routeModules[module] + return routeModule ? routeModule.routes : [] +}) +``` + +#### 2.2.3 统一入口页面 + +**Dashboard 入口(`views/dashboard/Index.vue`):** + +```vue + + + +``` + +**登录页入口(`views/login/Index.vue`):** + +```vue + + + +``` + +### 2.3 模块映射关系 + +建立 `src/views/` 下的页面目录与模块标识的映射: + +| 模块标识 | 对应目录 | 包含页面 | +|---------|---------|---------| +| `system` | `views/system/*` | 菜单、角色、部门、岗位、字典、配置、日志、登录日志、租户、租户套餐、数据权限、OAuth2客户端 | +| `user` | `views/user/*` | 用户信息、用户详情、等级、等级日志、地址、账户 | +| `order` | `views/order/*` | 订单列表、退款记录 | +| `cms` | `views/cms/*` | 文章、分类、轮播图 | +| `marketing` | `views/marketing/*` | 优惠券、活动管理 | +| `demo` | `views/demo/*` | 图标演示、列表演示 | +| `cashier` | `views/cashier/*` | 门店、包间、定价、订单、商品、报表 | + +**核心页面(所有系统默认包含,不依赖模块配置):** +- `views/login/Index.vue` - 登录页入口 +- `views/login/systems/*.vue` - 系统特定登录组件 +- `views/dashboard/Index.vue` - Dashboard 入口 +- `views/dashboard/systems/*.vue` - 系统特定 Dashboard 组件 +- `views/profile/Index.vue` - 个人中心 +- `views/settings/Index.vue` - 系统设置 + +### 2.4 目录结构 + +``` +admin-ui/ +├── build-config/ # 系统打包配置 +│ ├── cashier.json +│ ├── admin.json +│ ├── super.json +│ └── default.json # 默认配置(全模块,用于开发) +├── scripts/ # 构建脚本 +│ └── vite-plugin-module-build.ts # Vite 插件 +├── src/ +│ ├── router/ +│ │ ├── index.ts # 改造:使用虚拟路由模块 +│ │ └── modules/ # 新增:按模块拆分路由配置 +│ │ ├── core.ts # 核心路由(登录、Dashboard入口等) +│ │ ├── system.ts +│ │ ├── user.ts +│ │ ├── order.ts +│ │ ├── cms.ts +│ │ ├── marketing.ts +│ │ ├── demo.ts +│ │ └── cashier.ts +│ ├── views/ +│ │ ├── login/ +│ │ │ ├── Index.vue # 改造:统一入口 +│ │ │ └── systems/ # 新增:系统特定登录组件 +│ │ │ ├── Default.vue # 默认登录页 +│ │ │ ├── Super.vue # 超级租户登录页 +│ │ │ └── Cashier.vue # 收银系统登录页 +│ │ ├── dashboard/ +│ │ │ ├── Index.vue # 改造:统一入口 +│ │ │ └── systems/ # 新增:系统特定 Dashboard +│ │ │ ├── Default.vue # 默认 Dashboard +│ │ │ ├── Cashier.vue # 收银系统 Dashboard +│ │ │ └── Super.vue # 超级租户 Dashboard +│ │ └── ... # 业务页面(保持现有结构) +│ ├── types/ +│ │ └── system-config.d.ts # 系统配置类型定义 +│ └── ... +├── package.json # 改造:添加构建命令 +└── vite.config.ts # 改造:注册插件 +``` + +### 2.5 构建命令 + +```json +// package.json +{ + "scripts": { + "dev": "vite --port 3000", + "dev:cashier": "vite --port 3000 -- --system=cashier", + "dev:super": "vite --port 3000 -- --system=super", + "build": "vue-tsc && vite build", + "build:cashier": "vue-tsc && vite build -- --system=cashier", + "build:super": "vue-tsc && vite build -- --system=super", + "build:admin": "vue-tsc && vite build -- --system=admin", + "build:all": "pnpm build:cashier && pnpm build:super && pnpm build:admin" + } +} +``` + +**产物输出:** + +``` +dist/ +├── cashier/ # 收银系统(system + user + cms + cashier) +├── super/ # 超级租户(system + user) +├── admin/ # 普通后台(system + user + order + cms + marketing) +└── default/ # 默认(全模块,用于开发测试) +``` + +### 2.6 主题配置应用 + +系统配置中的 `theme` 字段在运行时应用: + +```typescript +// App.vue 或布局组件 +import systemConfig from 'virtual:system-config' + +// 设置页面标题 +document.title = systemConfig.theme.title + +// 设置主题色(Element Plus) +const el = document.documentElement +el.style.setProperty('--el-color-primary', systemConfig.theme.primaryColor) +``` + +--- + +## 三、验收标准 + +- [ ] 执行 `pnpm build:super` 成功构建,产物输出到 `dist/super/`,只包含 system 和 user 模块的页面 +- [ ] 执行 `pnpm build:cashier` 成功构建,产物输出到 `dist/cashier/`,包含 system、user、cms、cashier 模块的页面 +- [ ] 不同系统的 Dashboard 显示不同的子组件内容 +- [ ] 不同系统的登录页显示不同的子组件内容(超级租户无租户ID输入) +- [ ] 构建产物中不包含未配置模块的页面代码(Tree Shaking 生效) +- [ ] 现有菜单 API 获取、权限控制、主题切换功能正常 +- [ ] 开发模式 `pnpm dev:cashier` 正常工作,热更新无问题 + +--- + +## 四、风险与依赖 + +| 风险 | 影响 | 缓解措施 | +|------|------|---------| +| Vite 插件开发复杂度 | 中 | 插件逻辑清晰拆分:配置读取、路由生成、虚拟模块、输出配置 | +| Tree Shaking 不彻底 | 中 | 使用 `import()` 动态导入,配合 Rollup 的 `treeshake` 配置,构建后检查产物 | +| 动态组件加载失败 | 低 | 添加错误处理,加载失败时回退到 Default 组件 | +| 现有功能回归 | 中 | 构建后逐一验证核心功能:登录、菜单、CRUD、主题切换 | +| 多人协作冲突 | 低 | 配置文件集中管理,模块路由独立文件,减少冲突 | + +--- + +## 五、后续扩展 + +1. **国际化支持**:配置文件中可扩展 `locales` 字段,支持系统特定的翻译覆盖 +2. **模块懒加载**:未来可考虑运行时动态加载模块(Module Federation) +3. **版本管理**:配置文件支持 `version` 字段,用于产物版本控制 +4. **CI/CD 集成**:构建命令可直接接入 Jenkins/GitHub Actions,参数化构建不同系统