AI 编程助手(OpenCode / DeepSeek TUI)工作指引 — 进入仓库后首先阅读本文件
Forge Admin — 基于 Vue3 + Spring Boot 3 的企业级中后台管理框架,微内核插件化架构。
- 后端: Java 17 + Spring Boot 3.5.13 + MyBatis-Plus 3.5 + Sa-Token 1.38 + Flowable 7.0
- 前端: Vue 3.5 + Naive UI 2.42 + Vite 7 + Pinia 3 + UnoCSS 66
- 数据库: MySQL 8.0+ / Redis 6.0+
- 构建: Maven (后端) + pnpm (前端)
- 核心能力: RBAC 权限、多租户隔离、AI 代码生成、Flowable 工作流、消息中心、AI 数据大屏
forge-server/ # 后端根目录
├── forge-admin-server/ # 主应用入口(Spring Boot)
├── forge-report-server/ # 大屏报表服务
├── forge-app-server/ # App 接口服务
├── forge-flow/ # 独立流程引擎服务
├── forge-framework/ # 核心框架层(插件 + 启动器)
│ ├── forge-plugin-parent/ # 业务插件(system/generator/job/message/flow/ai)
│ └── forge-starter-parent/ # 技术启动器(auth/cache/orm/tenant/crypto … 共 20 个)
├── forge-business/ # 业务模块
forge-admin-ui/ # 前端主项目
forge-docs/ # VitePress 文档站
code-copilot/ # AI 辅助编码规则 & 变更管理
.agents/ # 项目级 Agent Skill 目录(进入仓库后统一识别)
.opencode/ # OpenCode 配置 & 记忆文件
遵循 No Spec No Code 原则。所有变更产物存放在
code-copilot/changes/[变更名]/
| 命令 | 用途 |
|---|---|
/spec-init |
初始化项目上下文 |
/propose <需求> |
创建变更提案(生成 spec.md + tasks.md) |
/apply <变更名> |
按 Spec 执行编码 |
/fix <变更名> |
Review 后增量修正 |
/review <变更名> |
两阶段审查(Spec 合规 + 代码质量) |
/test <变更名> |
按自动化测试标准增量生成/执行测试 |
/archive <变更名> |
归档并沉淀知识 |
执行
/test、阶段收尾验证、Review 后修复验证或归档前验收时,必须先读取code-copilot/rules/automated-testing-standard.md,复用当前变更已有test-spec.md、execution-log.md、spec.md、tasks.md,按本轮差异做增量验证;禁止每次从零开始重新规划测试流程。
# 构建全项目(跳过测试加速)
cd forge-server && mvn clean install -DskipTests
# 启动 admin 服务(默认 localhost:8580)
cd forge-server/forge-admin-server && mvn spring-boot:run
# 启动 flow 服务(默认 localhost:8581)
cd forge-server/forge-flow/forge-flow-server && mvn spring-boot:run
# 指定环境
mvn spring-boot:run -Dspring-boot.run.profiles=devcd forge-admin-ui
# 安装依赖
pnpm install
# 开发模式(默认 localhost:5173)
pnpm dev
# 生产构建
pnpm build
# Lint & 自动修复
pnpm lint:fix默认登录凭证:
admin/123456
| 文件 | 用途 |
|---|---|
forge-server/forge-admin-server/src/main/resources/application-dev.yml |
后端本地配置(数据库/Redis) |
forge-server/forge-admin-server/src/main/resources/application-dev.example.yml |
后端配置模板(可提交) |
forge-admin-ui/.env.local |
前端本地环境变量 |
forge-admin-ui/.env.example |
前端环境变量模板(可提交) |
所有 AI 编程助手进入仓库后必须统一按本节识别和使用项目级 Skill,避免不同 Agent 使用不同规则。
- 项目级 Skill 目录固定为
.agents/skills/(目录名为复数agents)。其它 Agent 启动后必须优先扫描该目录下的*/SKILL.md,并将其作为 Forge 项目专用 Skill 来源;若工具链默认识别.agent/skills/,必须在适配层映射到本目录,禁止在仓库内复制两套 Skill。 - 不要使用
superpowers/目录承载 Forge 项目规范;项目内专用能力统一沉淀到.agents/skills/,全局个人能力才放到用户级技能目录。 - 触发即读取:当用户请求明确命中某个 Skill 描述,或任务类型明显匹配该 Skill(例如 CRUD 生成、流程开发、UI 检查),执行前必须完整读取对应
SKILL.md。 - 最小必要原则:只读取本轮任务需要的 Skill;多个 Skill 同时适用时按任务链路排序读取,避免无关上下文污染判断。
- Forge 编码类任务默认遵循本文件第 5 章关键约定;需要更细规范时继续读取
code-copilot/rules/coding-style.md和forge-docs/guide/conventions.md。若当前环境额外暴露用户级forge-coding-standardsSkill,可作为补充,但不得替代本文件和项目级.agents/skills/。 - 前端 UI/交互/样式变更必须先读取
forge-admin-ui/DESIGN.md,遵循其中的界面设计、公共组件、列表卡片、按钮操作区和禁用项规范;涉及/flow/model或同类资产卡片时,必须遵循其“流程/资产卡片列表规范”,禁止左侧装饰色条、随机彩色图标块和营销化发布图标。 - CRUD 代码生成/审查优先使用
.agents/skills/forge-codegen-crud/SKILL.md;流程业务开发/审查优先使用.agents/skills/forge-business-flow-development/SKILL.md。 - Skill 规范优先级:
AGENTS.md> 当前变更spec.md>.agents/skills/*/SKILL.md>code-copilot/rules/*> 其它参考文档。若 Skill 与本文件冲突,以本文件为准。
forge/
├── forge-admin-server/ # 【主应用】Spring Boot 入口,聚合所有插件
│ └── src/main/java/com/mdframe/forge/admin/
│ ├── controller/ # REST 控制器
│ ├── service/ # 业务服务
│ └── config/ # 应用配置
│
├── forge-framework/ # 【框架层】不依赖具体业务
│ ├── forge-dependencies/ # 统一依赖版本管理(BOM)
│ │
│ ├── forge-plugin-parent/ # 【业务插件】可插拔功能模块
│ │ ├── forge-plugin-system/ # 系统管理(用户/角色/菜单/部门/岗位/租户/字典)
│ │ ├── forge-plugin-generator/ # 代码生成器(AI 驱动)
│ │ ├── forge-plugin-job/ # 定时任务(Quartz / SnailJob)
│ │ ├── forge-plugin-message/ # 消息中心(站内信/邮件/短信)
│ │ ├── forge-plugin-flow/ # 流程引擎(Flowable)
│ │ └── forge-plugin-ai/ # AI 供应商管理
│ │
│ └── forge-starter-parent/ # 【技术启动器】底层能力封装
│ ├── forge-starter-core/ # 核心工具类、异常、统一响应
│ ├── forge-starter-web/ # Web 层封装(Undertow + 全局异常处理)
│ ├── forge-starter-auth/ # 认证授权(Sa-Token + 权限注解)
│ ├── forge-starter-orm/ # ORM(MyBatis-Plus + 动态数据源 + 分页)
│ ├── forge-starter-cache/ # 缓存(Redis + Redisson 分布式锁)
│ ├── forge-starter-tenant/ # 多租户( TenantLineInnerInterceptor )
│ ├── forge-starter-datascope/ # 数据权限( DataScopeInterceptor )
│ ├── forge-starter-crypto/ # API 加解密(@ApiEncrypt / @ApiDecrypt)
│ ├── forge-starter-excel/ # Excel 导入导出(EasyExcel)
│ ├── forge-starter-file/ # 文件存储(OSS / RustFS / 本地)
│ ├── forge-starter-log/ # 操作日志(@OperationLog)
│ ├── forge-starter-idempotent/ # 幂等性(注解 + Redisson 分布式锁)
│ ├── forge-starter-id/ # 分布式 ID(雪花算法)
│ ├── forge-starter-config/ # 动态配置刷新(@RefreshScope)
│ ├── forge-starter-trans/ # 分布式事务
│ ├── forge-starter-social/ # 社交登录
│ ├── forge-starter-websocket/ # WebSocket
│ ├── forge-starter-message/ # 消息服务
│ ├── forge-starter-job/ # 任务调度基础设施
│ ├── forge-starter-api-config/ # API 行为动态配置
│ └── forge-flow-client/ # 流程客户端(@FlowBind / @FlowStart / @FlowCallback)
│
├── forge-flow/ # 独立流程服务(可选部署)
├── forge-report-server/ # 大屏报表服务
├── forge-app-server/ # App 接口服务
└── forge-business/ # 业务模块
Controller 层 → 接收请求、参数校验、协议转换
↓
Service 层 → 业务编排、事务边界(禁止互相注入导致循环依赖)
↓
Manager 层 → [可选] 领域能力、单一职责、可复用
↓
Mapper 层 → 纯数据访问(MyBatis-Plus + XML)
包结构约定(每个 plugin 内部):
plugin-xxx/
├── controller/ # REST 控制器
├── service/ # 服务接口
│ └── impl/ # 服务实现
├── mapper/ # MyBatis Mapper 接口 + XML
├── entity/ # 数据库实体
├── dto/ # 请求 DTO
├── vo/ # 响应 VO
├── constant/ # 常量
└── listener/ # 事件监听器
| 子系统 | 关键类/注解 | 文档 |
|---|---|---|
| 认证授权 | SaTokenInterceptor, @SaCheckPermission |
forge-starter-auth |
| 多租户 | TenantLineInnerInterceptor(自动追加 WHERE tenant_id = ?) |
forge-starter-tenant |
| 数据权限 | DataScopeInterceptor(按 mapperMethod 精确匹配 XML SQL 改写) |
forge-starter-datascope |
| API 加解密 | @ApiEncrypt, @ApiDecrypt |
forge-starter-crypto |
| 操作日志 | @OperationLog |
forge-starter-log |
| 幂等控制 | @Idempotent |
forge-starter-idempotent |
| 流程引擎 | @FlowBind, @FlowStart, @FlowCallback |
forge-plugin-flow |
| 统一响应 | RespInfo.success(data) / RespInfo.error(msg) |
forge-starter-core |
| 全局异常 | GlobalExceptionHandler(@RestControllerAdvice) |
forge-starter-web |
| 前端(UI/组件) | 后端(API/Entity) |
|---|---|
AiCrudPage 组件 |
GET /page, POST /, PUT /, DELETE /:id |
DictSelect / DictTag |
sys_dict_type + sys_dict_data 表 |
RegionTreeSelect |
sys_region_code 表 |
useDict() |
GET /system/dict/data/type/{type} |
request 工具 |
SaTokenInterceptor 鉴权 |
postEncrypt 工具 |
@ApiDecrypt 注解 |
| 技术 | 版本 | 用途 |
|---|---|---|
| Vue 3 | 3.5 | 组合式 API(<script setup>) |
| Naive UI | 2.42 | 组件库(NButton, NTable, NTree, NModal …) |
| Vite | 7 | 构建工具 + HMR |
| Pinia | 3 | 状态管理(useUserStore, useAppStore …) |
| Vue Router | 4.5 | 路由(动态路由 + 权限过滤) |
| UnoCSS | 66 | 原子化 CSS(text-primary, p-4, flex …) |
| Axios | 1.11 | HTTP 客户端(封装在 @/utils/request) |
| ECharts | 6 | 图表 |
| BPMN.js | 17 | 流程设计器 |
| CodeMirror | 6 | 代码编辑器 |
forge-admin-ui/src/
├── api/ # API 接口定义(按模块拆分)
├── components/ # 公共组件
│ ├── ai-form/ # AI 表单组件
│ ├── ai-modal/ # AI 弹窗组件
│ ├── bpmn/ # BPMN 流程设计器
│ ├── common/ # 通用工具组件(AuthImage 等)
│ ├── file-upload/ # 文件上传
│ ├── form-designer/ # 表单设计器
│ ├── DictSelect.vue # 字典选择器
│ ├── DictTag.vue # 字典标签
│ ├── RegionTreeSelect.vue # 行政区划树选择器
│ └── IconSelector.vue # 图标选择器
├── composables/ # 组合式 API(useDict, usePermission …)
├── layouts/ # 布局组件
├── router/ # 路由配置(动态路由生成)
├── stores/ # Pinia Store
├── utils/ # 工具函数(request, encrypt-request, file …)
├── views/ # 页面视图(system/, flow/, generator/, message/ …)
├── styles/ # 全局样式
└── config/ # 应用配置
- 统一请求工具:
import { request } from '@/utils/request' - 加密请求:
import { postEncrypt } from '@/utils/encrypt-request'(对应后端@ApiDecrypt) - 接口路径格式:
METHOD@/api/module/action(AiCrudPageapi-config使用) - 占位符格式:
:id(冒号),不是{id}(花括号) - 分页参数:前端传
pageNum+pageSize,后端必须用相同命名接收
| 组件 | 路径 | 用途 |
|---|---|---|
AiCrudPage |
内建组件 | 零代码 CRUD 页面(配置 api-config + schema) |
DictSelect |
@/components/DictSelect.vue |
字典下拉选择 |
DictTag |
@/components/DictTag.vue |
字典标签渲染(自动映射颜色) |
RegionTreeSelect |
@/components/RegionTreeSelect.vue |
行政区划树选择 |
AuthImage |
@/components/common/AuthImage.vue |
鉴权图片(fetch + Bearer Token) |
IconSelector |
@/components/IconSelector.vue |
图标选择器 |
使用 UnoCSS 语义化颜色类区分操作类型:
| 类名 | 颜色 | 场景 |
|---|---|---|
text-primary |
蓝 | 编辑、查看、授权 |
text-info |
灰蓝 | 详情、统计、在线用户 |
text-warning |
黄 | 刷新缓存、重置、封禁 |
text-error |
红 | 删除、强制下线 |
text-success |
绿 | 启用、发布、通过 |
<a class="text-primary cursor-pointer hover:text-primary-hover" @click="handleEdit(row)">编辑</a>
<a class="text-error cursor-pointer hover:text-error-hover" @click="handleDelete(row)">删除</a>以下规则违反会直接导致编译失败、运行时异常或数据问题。
查询类 SQL 禁止在 Service 层用 LambdaQueryWrapper 构建。必须写在 Mapper XML 中。
- 原因:
DataScopeInterceptor按mapperMethod精确匹配改写 SQL;XML 更易审查和优化 - 例外:仅单表
selectById、insert、updateById、deleteById等 MyBatis-Plus 内置方法允许
- 业务数据(字典、配置等)的
tenant_id必须设为1(默认租户),禁止设0 TenantLineInnerInterceptor自动追加WHERE tenant_id = 当前租户ID,0的数据对所有租户不可见sys_resource(菜单/权限)表不受租户拦截,tenant_id设为1即可
- 前端传
pageNum+pageSize - 后端 Controller 必须用
@RequestParam(defaultValue = "1") Integer pageNum,不能用page
- URL 占位符用 冒号格式:
:id、:dictId - 禁止花括号格式:
{id}— 组件只识别includes(':id')
imageUpload组件存储的是 fileId,不是 URL- 表格列渲染图片用
AuthImage组件(自动带 Token),禁止直接用NAvatarsrc - 获取下载链接用
getFileUrl(fileId)from@/utils/file
- Service 之间禁止互相注入
- 跨 Service 协调逻辑上提到 Controller 层
- 下拉选项、状态标签 必须使用字典组件(
DictSelect/DictTag/useDict) - Schema 必须定义为
computed,确保字典异步加载后响应式更新 - 业务枚举和可配置枚举必须维护到
sys_dict_type+sys_dict_data,禁止在前端页面写死options或标签映射 - 新增内置字典必须通过
forge/db/migration/的 Flyway 脚本写入,脚本需具备NOT EXISTS防重复保护,tenant_id必须为1 - 字典类型命名使用小写下划线,系统级字典建议使用
sys_前缀;文件存储类型统一使用sys_file_storage_type - 前端读取字典时使用
useDict('<dict_type>'),表格回显优先使用DictTag,下拉选项使用computed(() => dict.value.<dict_type> || []) - 字典数据的
dict_value必须与后端枚举/存储策略/业务状态值保持一致,dict_label只负责展示文案,list_class负责标签样式
- RESTful:
GET /page(分页)、GET /:id(详情)、POST /(新增)、PUT /(修改)、DELETE /:id(删除) - 统一返回:
RespInfo.success(data)/RespInfo.error(msg) - 敏感接口:
@ApiDecrypt/@ApiEncrypt - 请求体禁止
Map:Controller 写接口必须用明确的 DTO/VO 接收@RequestBody,禁止@RequestBody Map<String, Object>再params.get("xxx") - 正确:
public RespInfo<?> approve(@RequestBody FlowTaskApproveDTO dto) - 错误:
public RespInfo<?> approve(@RequestBody Map<String, Object> params) - 允许的例外只有:低代码动态记录体、流程变量字段
variables、真正动态键值的元数据;taskId、comment、userId、action等固定字段必须是 DTO 属性,不能整份请求都用 Map - 新增或修改写接口时,先建 DTO/VO,再写 Controller;禁止先用 Map 占位再回头补类型
- Java 业务代码中的状态值禁止魔法数字/字符串(如
setStatus(2)、getStatus() == 1、"terminated"),必须使用枚举 - 通用启用/停用(
enabled、visible、userStatus、isEnabled及同类 0/1 开关)统一用com.mdframe.forge.starter.core.enums.EnableStatus:写入走EnableStatus.ENABLED.getCode(),比较走EnableStatus.ENABLED.matches(value) - 多状态业务字段必须建本模块枚举,提供
getCode()/matches();正确示例:entity.setStatus(FlowTaskStatus.APPROVED.getCode())、FlowTaskStatus.APPROVED.matches(entity.getStatus()) - 实体字段可继续用
Integer/String与数据库列对齐,禁止把实体字段改成枚举类型只为了少写getCode() - Mapper XML / SQL 允许字面量(
status = 0、status IN (2, 3, 7)),禁止在 XML 里写 Java 类全名(${@...Enum@XXX}),避免改包路径后运行时才失败 - 前端展示走字典(
DictSelect/DictTag/useDict),dict_value必须与后端枚举码一致 - 不要套
EnableStatus的字段:Boolean 开关、编码规则段配置、readonly/isDefault/validationPassed等非启用语义;这些要么保持原类型,要么建专用枚举 - 测试可用字面量 0/1 作为存储码,生产代码不行
- 禁止硬编码密钥、AK/SK、数据库密码
- 禁止提交包含用户个人信息的测试数据
- 禁止在日志中打印手机号、身份证、银行卡
- API Key/Secret 返回前端必须脱敏(保留前4后4,中间
****) - 涉及资金/状态流转/权限变更,必须在 Spec 中标注并经人工审查
- 外部接口调用必须设置超时(默认 3s)并做降级;状态变更必须走状态机
- 所有业务表必须包含:
id,tenant_id,create_by,create_time,create_dept,update_by,update_time - 字符集
utf8mb4,引擎InnoDB - 金额字段用
long,单位分 - 时间字段用
LocalDateTime
Forge 项目默认优先逻辑删除,只有明确属于运行时中间表、关系重建表、框架表或留存清理任务的场景才允许物理删除。
- 用户可见的主数据、配置数据、设计态元数据、业务单据、可恢复/可审计数据,删除必须走逻辑删除。
- 新增业务主表、配置表、设计态元数据表默认增加
del_flag字段;0表示未删除,非0表示已删除。没有“删除后允许同业务键重建”约束的普通表可以继续使用0/1。 - 历史表已经使用
deleted、status=0等字段表达软删除时,可以保持现有语义,但必须在实体、Mapper XML 和查询条件中保持一致。 - Flowable 引擎原生表(如
ACT_*)和定时任务框架自身运行表不纳入 Forge 逻辑删除改造。 sys_job_config、sys_job_log属于 Forge 内部表,不因“定时任务”命名而排除;行级删除按逻辑删除规范处理。日志留存清理类专用任务可以按策略物理清理历史数据,但必须在代码和 Spec 中说明。
- 表有逻辑删除字段时,实体必须显式声明对应字段并加
@TableLogic;禁止只依赖 MyBatis-Plus 全局配置兜底。 @TableLogic字段类型必须匹配数据库字段类型:tinyint用Integer,bigint用Long,char(1)/varchar用String。- 使用删除标记唯一索引的数值主键表,实体必须声明
@TableLogic(value = "0", delval = "主键数据库列名"),删除时由 MyBatis-Plus 原子写入当前行主键;自定义删除 SQL 也必须写主键,禁止固定写1。 - Mapper XML 中的查询必须显式过滤未删除数据,例如
AND del_flag = 0或AND deleted = 0;不要假设自定义 XML 会被 MP 自动补全。 - 删除接口协议可以保持不变(例如
DELETE /:id或既有POST /remove),但 Service/Mapper 底层必须从物理DELETE改为逻辑删除。 - 批量删除必须批量更新逻辑删除字段,避免循环逐条物理删除。
- 逻辑删除会改变唯一键语义;存在业务唯一键的表必须评估“已删除记录阻塞重新创建”的问题。
- 不是所有逻辑删除表都需要删除标记唯一索引:无业务唯一键,或业务键要求跨历史永久唯一时,不要机械附加删除标记。
- 业务键只要求“未删除记录唯一”且删除后允许同值重建时,数值主键表使用
del_flag BIGINT NOT NULL DEFAULT 0,并建立普通唯一索引UNIQUE (tenant_id, 业务键..., del_flag);有效行使用0,删除后写当前行主键。 - 禁止使用固定
0/1配合上述唯一索引,否则同一业务键最多只能保留一条已删除历史;禁止新增可见logic_delete_active生成列或依赖函数/部分索引表达该语义。 - 字符串主键表如需相同语义,
del_flag使用可容纳主键的字符串类型,并通过专用 Mapper 执行SET del_flag = 主键列;MyBatis-Plus 通用字符串逻辑删除会把列名当字面量,禁止调用。 - Flyway 迁移必须先扩展删除字段、回填存量删除行为主键墓碑,再替换唯一索引并改代码;脚本必须具备
information_schema防重复保护。 - 只给实体加
@TableLogic但数据库缺字段会导致运行时 SQL 报错,禁止这样提交。
- Flowable/Quartz/SnailJob 等第三方框架自带运行表,按框架语义处理。
- 纯关联关系重建表、临时表、缓存表、短期会话表、导入暂存表,可以物理删除,但必须确认无恢复/审计要求。
- 日志归档和留存清理任务可以物理清理超期历史数据;普通行级删除仍按该表的逻辑删除规则执行。
- 任何新增物理删除点必须在 Spec 或任务说明中写明原因、影响范围和回滚方式。
所有数据库结构和内置数据变更必须走统一脚本,不允许只改实体、Mapper 或本地数据库。
| 目录 | 用途 |
|---|---|
forge/db/migration/ |
Flyway 版本化迁移脚本,放表结构、索引、字段、系统资源等正式变更 |
forge/db/seed/required/ |
系统运行必需初始化数据 |
forge/db/seed/demo/ |
演示数据,默认不导入 |
forge/db/seed/optional/ |
可选模块数据 |
- 版本脚本统一命名:
V<版本号>__<lower_snake_case_description>.sql - 示例:
V1.0.2__add_dashboard_version_table.sql V1.0.0__baseline.sql是历史基线,新变更版本必须大于1.0.0- 版本号必须单调递增;同一版本号只能有一个脚本
- 已经执行到数据库并进入
forge_schema_history的脚本禁止修改;需要修正时新增下一个版本脚本
- 脚本必须可重复执行或具备防重复保护:
CREATE TABLE IF NOT EXISTS、INSERT ... SELECT ... WHERE NOT EXISTS、新增列/索引前查information_schema INSERT必须显式写列名,禁止依赖表字段顺序- 业务内置数据
tenant_id必须为1,禁止写0 sys_resource、sys_role_resource等权限资源脚本必须做NOT EXISTS防重复- 生产敏感数据、真实密码、Token、AK/SK、API Key 禁止提交到 SQL
- 涉及数据修复、状态流转、资金、权限放开的 SQL,必须在 Spec 中说明影响范围和回滚方式
forge-admin-server启动时由 Flyway 执行forge/db/migration脚本;forge-report-server单独启动不会执行这些迁移- 默认配置兼容不同启动目录:
filesystem:./db/migration,filesystem:../db/migration,filesystem:forge/db/migration - 若设置了
FORGE_FLYWAY_LOCATIONS或FORGE_FLYWAY_ENABLED,会覆盖默认配置;迁移未执行时优先检查这两个环境变量 - 验证迁移结果:
SELECT installed_rank, version, description, success
FROM forge_schema_history
ORDER BY installed_rank DESC;本节为全局硬性约束,适用于所有 AI 生成的与修改的前端代码,违反即打回。
- 能用 Pinia 的场景必须用 Pinia:凡涉及跨组件、跨面板、跨层级的共享状态或通信(设计器 schema、选中 ID、面板 UI 状态、多组件联动的业务状态等),必须沉淀到 Pinia store(
src/stores/下按领域建子目录,如stores/designer/)。 - 禁止纯 props/emit 层层透传:同一个状态经 props + emit 转手超过 2 层即视为违规,必须改用 store;子组件直接读写 store,父组件不再充当数据中转站。
- 存量巨型组件改造时遵循渐进式模式:入口组件接收 props 后
syncFromProps同步进 store 并 watch store 变化对外 emit(兼容存量父组件),内部面板子组件全部改为读写 store,逐步消灭中间 props 链。 - store 命名与文件:
useXxxStore对应stores/<domain>/xxxStore.js;一个 store 聚焦一个领域(如formDesignerStore、listDesignerStore),禁止一个“大杂烩 store”包揽全项目。
- 复杂页面必须拆分:Vue SFC 超过 800 行(模板 + script + style 合计)必须拆分;超过 2000 行禁止提交,必须先重构。
- 拆分方式:右侧/左侧属性面板按分区拆成独立子组件(如一个 collapse-item / 一个 tab-pane 一个文件);可复用逻辑抽 composables(
useXxx.js);纯函数工具下沉到模块级utils.js。 - 拆分后目录约定:同域组件放同目录子文件夹(如
forge-form-designer/panels/FooPanel.vue),禁止把拆出文件散落在无关目录。 - 禁止在一个 SFC 里同时堆积:多种组件类型的属性配置、多个业务域的状态、超长内联模板。发现即拆。
# 1. 数据库
mysql -u root -p -e "CREATE DATABASE forge DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;"
mysql -u root -p forge < forge-server/db/migration/V1.0.0__baseline.sql
# 2. 后端配置
cp forge-server/forge-admin-server/src/main/resources/application-dev.example.yml \
forge-server/forge-admin-server/src/main/resources/application-dev.yml
# 编辑 application-dev.yml,填入数据库/Redis 连接信息
# 3. 前端配置
cd forge-admin-ui
cp .env.example .env.local
# 编辑 .env.local(可选,默认代理到 localhost:8580)
# 4. 启动
cd forge-server/forge-admin-server && mvn spring-boot:run # 后端 :8580
cd forge-admin-ui && pnpm install && pnpm dev # 前端 :5173# === 后端 ===
# 改代码
vim forge-server/forge-framework/forge-plugin-system/src/main/java/.../XxxController.java
# 构建(确认编译通过)
cd forge-server && mvn clean install -DskipTests
# 重启服务
cd forge-server/forge-admin-server && mvn spring-boot:run
# 验证
curl -s http://localhost:8580/xxx/page?pageNum=1&pageSize=10
# === 前端 ===
# 改代码
vim forge-admin-ui/src/views/system/xxx/index.vue
# Lint 检查
cd forge-admin-ui && pnpm lint:fix
# HMR 自动热更新,浏览器验证 http://localhost:5173# 1. 登录获取 Token
curl -s -X POST http://localhost:8580/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"123456"}' | jq '.data.token'
# 2. 用 Token 调用业务接口
TOKEN="<上面获取的token>"
# 分页查询
curl -s http://localhost:8580/system/user/page?pageNum=1&pageSize=10 \
-H "Authorization: Bearer $TOKEN" | jq .
# 详情查询
curl -s http://localhost:8580/system/user/1 \
-H "Authorization: Bearer $TOKEN" | jq .
# 新增
curl -s -X POST http://localhost:8580/system/user \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"username":"test","nickname":"测试"}' | jq .
# 修改
curl -s -X PUT http://localhost:8580/system/user \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":123,"nickname":"新昵称"}' | jq .
# 删除
curl -s -X DELETE http://localhost:8580/system/user/123 \
-H "Authorization: Bearer $TOKEN" | jq .| 日志 | 路径 |
|---|---|
| 应用日志 | forge-server/forge-admin-server/logs/ |
| 前端开发日志 | 终端 pnpm dev 输出 |
| SQL 日志 | 配置 spring.datasource.dynamic.datasource.master.log: true(开发环境) |
自动化测试与验证统一遵循 code-copilot/rules/automated-testing-standard.md。执行前必须先复用已有验证基线,执行后必须把命令、结果、警告、跳过项和服务清理情况追加到当前变更的 execution-log.md。
| 检查项 | 后端命令 | 前端命令 |
|---|---|---|
| 编译 | cd forge-server && mvn clean compile |
cd forge-admin-ui && pnpm build |
| Lint | — | pnpm lint:fix |
| 测试 | cd forge-server && mvn test |
— |
| 全量构建 | cd forge-server && mvn clean install |
cd forge-admin-ui && pnpm build |
| 跳过测试构建 | mvn clean install -DskipTests |
— |
本项目 AI 编程助手的工作优先级(从高到低):
- 本文件(AGENTS.md) — 最高优先级;第 5 章是“违反会出问题”的短清单
code-copilot/changes/[变更名]/spec.md— 当前变更的 Spec(如在进行/apply时)code-copilot/rules/project-context.md— 工程上下文详细版code-copilot/rules/coding-style.md— 编码规范forge-admin-ui/DESIGN.md— 前端界面设计、公共组件、资产卡片和交互规范(前端 UI/样式变更必读)code-copilot/rules/domain-rules.md— 业务领域约束code-copilot/rules/security.md— 安全红线code-copilot/rules/automated-testing-standard.md— 自动化测试与验证标准(执行/test和阶段验证时必读)code-copilot/memory/pitfalls.md— 踩坑记录(每次新对话必读)code-copilot/memory/decisions.md— 项目决策记录code-copilot/memory/preferences.md— 用户偏好记录forge-docs/guide/conventions.md— 完整编码规范
规范只维护两处:本文件第 5 章,以及 code-copilot/rules/coding-style.md。Skill、踩坑、决策、偏好不要再抄同一条规范。踩坑只记真实故障和根因。
优先级规则:本文件与子文件冲突时,以本文件为准;Spec 文档与通用规则冲突时,以 Spec 为准。
| 文档 | 路径 | 说明 |
|---|---|---|
| 项目 README | README.md |
项目介绍、截图、快速开始 |
| 前端设计规范 | forge-admin-ui/DESIGN.md |
界面设计、公共组件、资产卡片和交互禁用项 |
| 编码规范 | forge-docs/guide/conventions.md |
完整命名、异常、日志、数据库规范 |
| SDD 工作流 | forge-docs/guide/sdd-workflow.md |
Spec 驱动开发全流程 |
| 工程上下文 | code-copilot/rules/project-context.md |
技术栈、模块依赖、详细配置 |
| code-copilot 目录规则 | code-copilot/AGENTS.md |
记忆文件写入规则 |
| 踩坑索引 | code-copilot/memory/pitfalls.md |
分类目录;正文在 memory/pitfalls/ |
| 项目决策 | code-copilot/memory/decisions.md |
架构决策记录 |
| 用户偏好 | code-copilot/memory/preferences.md |
编码风格偏好 |
| 更新日志 | CHANGELOG.md |
版本变更记录 |
| Nginx 部署 | NGINX_CONFIG.md |
生产环境 Nginx 配置 |
| 字典管理 | forge-admin-ui/DICT_MANAGEMENT_SETUP.md |
字典功能配置说明 |
| 文件 URL 指南 | forge-admin-ui/FILE_URL_GUIDE.md |
文件访问 URL 规范 |
此规则适用于所有含
region_code字段的业务表查询。
核心概念:虚拟组织节点 code 以 ALL 结尾(如 150000ALL),代表"本级 + 下级"聚合。
MyBatis XML 写法(推荐,写在 Mapper XML 中):
<if test="regionCode != null and regionCode != '' and regionCode.contains('ALL')">
AND (region_code = REPLACE(#{regionCode},'ALL','')
OR region_code IN (SELECT code FROM sys_region_code WHERE parent_code = REPLACE(#{regionCode},'ALL','')))
</if>
<if test="regionCode != null and regionCode != '' and !regionCode.contains('ALL')">
AND region_code = #{regionCode}
</if>规则说明:
- 选择虚拟组织(如
150100ALL):查询本级 + 所有下级区划 - 选择普通区划(如
150102):精确匹配 - 前端
RegionTreeSelect中虚拟组织节点disabled: true,不可选中
每次新对话开始:
- 必读
code-copilot/memory/preferences.md - 浏览
code-copilot/memory/pitfalls.md索引,只打开与当前任务相关的memory/pitfalls/<主题>.md - 需要架构背景时再检索
code-copilot/memory/decisions.md,不要通读
发现有价值信息时写入对应文件:真实故障写入 memory/pitfalls/<主题>.md,架构选择写入 decisions.md,用户偏好写入 preferences.md。编码规范只改第 5 章或 code-copilot/rules/coding-style.md。