22 KiB
DataEase 开发规范
本文件适用于整个工作区,供开发者和编码代理共同遵守。子目录存在更具体的 AGENTS.md 时,优先遵循其局部约定;用户当前明确的任务范围优先。默认使用中文沟通,保留代码中的既有命名。
0. 产品版本、开源边界与协作分支
- 当前工作区是 DataEase 产品 V3 源码,以下仓库属性和协作规则由项目维护者明确指定。
- 主仓库:
https://github.com/dataease/dataease,是开源项目;遵循根目录LICENSE,不要将其简化描述为没有附加条件的 GPLv3。 - 子模块:
https://github.com/dataease/de-xpack,不是开源项目。本地可见、存在 GitHub 地址或可作为插件加载,均不表示可以将其实现公开。 - 不把 XPack 实现源码、专有资源或内部差异复制到开源主仓库、公开 PR/Issue 或公开文档;跨仓库协作通过必要的公共契约和兼容性说明完成,不能为解决构建缺失直接搬运专有实现。
- 两个仓库的开发目标分支均为
dev-v3。主仓库通过 PR 合入,XPack 按维护者指定流程直接推送;具体步骤见第 9 节。旧文档中的dev-v2目标不适用于本工作区。
1. 工作原则
- 开始前读取相关代码及
git status --short,确认已有修改。只处理本次任务,不覆盖、回退、暂存或提交他人的改动。 - 用户要求分析、审查或只读时,仅执行读取操作;不执行安装、格式化、构建、启动应用或可能写数据库的命令。
- 沿现有调用链修复问题,优先最小且完整的改动。不顺带升级依赖、大范围重命名、格式化或抽象重构。
- 先定位真实入口和所有调用方,再修改公共契约。不要根据目录名、旧文档或其他 DataEase 版本推断当前实现。
- 版本、脚本、Profile、端口以当前
pom.xml、package.json和配置文件为准;旧文档中的版本、完整构建说明和默认分支不作为事实依据。 - 不读取或输出与任务无关的密码、Token、密钥、真实连接信息;日志和交付说明中的敏感信息应脱敏。
- 普通局部开发按既有模式自行推进;涉及破坏性数据变更、范围不明的外部操作时,先说明具体影响并取得必要授权。不得擅自执行安装器、发布或部署。
2. 项目地图与依赖边界
| 位置 | 职责与修改边界 |
|---|---|
core/core-frontend |
Vue 3 / TypeScript / Vite 主前端,多页面与嵌入库入口 |
core/core-backend |
Java 21 / Spring Boot 核心应用,业务编排与查询执行 |
sdk/common |
公共实体、认证基础、缓存、异常、响应、日志、国际化、迁移接口 |
sdk/api/api-base |
核心业务 API、DTO、请求和响应模型 |
sdk/api/api-permissions |
权限契约 |
sdk/api/api-sync |
同步契约 |
sdk/extensions |
图表、数据源、填报和同步扩展契约 |
de-xpack/xpack-permissions |
用户、组织、认证、资源权限、数据集权限等实现 |
de-xpack/xpack-base |
电子表格、报表、填报、阈值、日志等扩展功能 |
de-xpack/xpack-sync |
数据同步实现 |
de-xpack/xpack-frontend* |
扩展前端实现,是否参与构建以其 POM 为准 |
installer、Dockerfile |
安装、部署、容器编排和配置模板 |
drivers、mapFiles、staticResource |
驱动、地图及静态资源 |
- SDK 承载共享契约,不依赖
core-backend的实现类;核心与 XPack 尽量通过既有 API/扩展契约协作,避免形成循环依赖。 de-xpack是独立 Git 子模块。涉及它时,额外检查git -C de-xpack status --short和其差异;不要把子模块修改当成主仓库普通文件,也不要自动更新子模块指针或切换版本。- 根 Maven 当前只聚合
sdk;core/pom.xml聚合前后端,de-xpack/pom.xml单独聚合扩展。根目录 Maven 构建不代表整个产品构建完成。 .gitignore包含后端、测试、文档和锁文件等路径,但其中部分文件已受 Git 跟踪。先用git ls-files核对;普通rg未找到时,在明确的源码目录使用rg --no-ignore,并排除target、node_modules、dist等产物。- 不手工修改
target/、dist/、.flattened-pom.xml、生成的 QueryDSL Q 类或后端打包生成的resources/static/。应修改生成它们的源码或构建配置。
3. 后端分层与接口规范
典型调用方向:sdk API → server → manage → Repository / Provider。
server/实现 SDK API,负责 HTTP 边界、参数校验和调用编排;可复用业务规则放入manage/或现有业务服务。dao/auto/、dao/ext/放持久化和查询相关代码。部分mapper目录实际使用 JPA,不得仅因目录名新增 MyBatis 实现。- 新增或修改接口时,同步检查 SDK 方法、请求/响应模型、实现类、前端封装、权限注解及扩展实现;保持现有路径和序列化兼容性。
- 复用已有
DEException、错误码、统一响应和国际化机制,不新增平行的响应包装。不通过捕获所有异常并返回成功或空数据隐藏业务失败。 - 数据库实体与 API 模型各司其职;避免直接暴露包含内部状态或敏感字段的实体。
- 新增 Java 代码采用 4 空格缩进,沿用所在模块的注入与命名风格;JPA、Servlet、Validation 等使用
jakarta.*。不要批量替换所有javax.*:JCache 当前仍使用javax.cache,JDK 中的javax.sql等也不属于 Jakarta 迁移范围。 - 对跨多次写入的业务操作明确事务边界;不要让外部数据源查询、网络调用和长时间导出无必要地占用元数据库事务。
- JDBC 连接、结果集、文件流等资源必须可靠关闭;异步任务复用现有调度与生命周期管理机制。
- 异步调用按需显式传递用户、组织及审计上下文,不假定请求上下文自动跨线程传播。使用
IPUtils、CommunityUtils等 ThreadLocal 时,按现有生命周期在finally中清理,避免线程池复用串用上下文。
4. 持久化、字段更新与迁移
- 系统元数据主要使用 Spring Data JPA / QueryDSL。新逻辑沿用 JPA Repository、Specification 或 QueryDSL,不引入另一套 ORM。
- 实体使用
jakarta.persistence,优先@Getter/@Setter,避免对 JPA 实体直接使用可能引入关联递归的@Data。新增表和字段补充含义、长度、可空性及必要注释。 - 业务资源 ID 遵循现有
Long/SnowflakeUtil约定,不擅自改为数据库自增。版本记录等特殊实体沿用自身规则。 - 修改保存逻辑前阅读
core/core-backend/src/main/java/io/dataease/config/JpaUpdateNonNullAspect.java:它拦截save、saveAndFlush、saveAll、saveAllAndFlush,对已存在实体合并非空属性。 - 不假设向
save()传null就能清空字段。需要清空时,用明确的 QueryDSL 更新或带@Modifying的 JPQL 等现有可控方式,在事务中执行,并验证持久化上下文和后续读取结果。区分“未提供字段”和“显式清空”。 - 非空合并切面不等于并发控制或完整的 PATCH 语义;受管实体脏检查、批量更新和绕过 Repository 的路径需分别验证。
saveAll也会逐项尝试读取旧实体,批量操作应检查查询次数,不能直接假定只有一次批量 SQL。 - 查询兼顾项目支持的数据库,留意大小写、保留字、布尔值、分页、日期和空值语义。数据库特有 SQL 必须进入现有方言/Provider 分支,不散落在通用业务代码中。
- 数据库变更同时检查实体、QueryDSL 使用处和版本化
SqlBlock。InitSqlListener会执行迁移,部分配置启用ddl-auto: update;不能据此省略历史数据迁移和兼容设计。 - 新迁移应具备安全重试能力,检查版本组、执行顺序、默认值和存量数据;不要改写已执行迁移来替代新增迁移。
- 启动应用可能执行迁移并写入配置或业务数据。验证前确认使用隔离的开发/测试环境,不能为代码验证直接连接并改动生产或用户业务数据。
5. 数据查询、图表与权限
核心业务链:数据源 → 数据集 → 图表 → 仪表板/大屏。
图表取数阅读入口:
core/core-frontend/src/api/chart.ts的getData()。- SDK
ChartDataApi与后端ChartDataServer。 ChartDataManage.calcData():字段、数据集权限、行列权限、筛选和钻取编排。chart/charts/中的 Handler、engine/中的 SQL 转换逻辑及数据源 Provider。- 前端
views/chart/components/js/panel/中的渲染实现。
- 区分元数据持久化和分析数据查询;分析数据走既有 Provider / Calcite / JDBC 链路,不用元数据库 Repository 替代。
- 图表类型专属计算优先放入对应 Handler;方言和连接相关行为放入对应 Provider;不要持续向公共编排方法堆叠类型分支。
- 修改数据查询时保留字段编解码、计算字段、筛选、排序、聚合、钻取、行列权限和脱敏语义。导出、预览、嵌入与分享是否受影响必须检查。
- SQL 值优先参数化;表名、字段名、排序等不能绑定的结构输入,应通过已有元数据、白名单和方言转义构造,不能直接拼接未校验输入。
- 前端隐藏菜单或按钮不等于鉴权。后端必须检查实际资源、操作和访问身份;复用
DePermit、DeLinkPermit及既有权限管理逻辑。 - 权限变更同时审查 SDK 契约、核心调用、
substitute/permissions和 XPack 实现。保留条件 Bean 与版本差异,禁止用替补实现或默认放行掩盖权限失败。 - 分享链接、嵌入 Token、管理员代理等访问上下文沿用现有传递与校验方式;缓存键应保留所需用户、组织、权限和筛选维度,防止跨身份复用结果。
- 缓存复用
DECacheService/CacheUtils,检查写入后的失效路径及配置选用的实现。当前 JCache 在建缓存时设置过期策略,expTime <= 0默认一分钟;Redis 按键设置过期,expTime <= 0不设过期。不要假设两者 TTL 或对象引用语义相同;修改缓存对象前检查是否需要复制,缓存行为改动应覆盖实际支持的实现。 - 资源 ID、权限编码、组件配置和图表类型属于持久化契约。修改时考虑旧仪表板、模板、复制和导入导出的兼容性。
6. 前端开发规范
- 使用 Vue 3 Composition API 和 TypeScript,沿用附近组件结构;复用现有组件、hooks、类型和工具,不为局部功能引入新的 UI 或状态管理体系。
- 遵循前端
.editorconfig、prettier.config.js和 ESLint 配置:2 空格缩进、单引号、不加尾分号。仅格式化本次改动范围。 - UI 依赖沿用
element-plus-secondary,内部导入优先使用已有@/别名。不要无关替换路由包、UI 包或图表库。 - HTTP 调用通过
src/api/和src/config/axios/,保留已有认证、HMAC、语言、分享/嵌入 Token、取消和错误处理;组件不另建绕过拦截器的 Axios 实例。 - 跨页面共享状态放入既有 Pinia Store;局部临时状态留在组件或 composable。编辑器改动检查快照、撤销/重做、复制、组合、图层和锁定行为。
- 编辑器区分需要重新取数的
calcData和只需重绘的renderChart快照通知;沿用snapshot.ts的记录与刷新机制,避免样式变更引发无谓取数或绕过撤销/重做。 - 新接口和复杂业务对象优先补齐类型;不要为消除报错扩大
any或关闭类型检查。后端LongID 沿用既有传输和处理方式,避免未经确认转换成可能丢精度的 JavaScript 数字。 - 新文案复用国际化机制并补充相关语言资源;不要在 i18n 尚未初始化的模块求值阶段捕获翻译函数。
- 新增路由/菜单检查
src/permission.ts、权限 Store 和动态路由生成逻辑,不只修改静态路由表。 - 修改共享页面或组件时,按影响范围核对主应用、
panel、移动端和lib嵌入入口。 config/pagesConfig.ts自动扫描非lib页面目录,多页面构建还需要对应 HTML 入口;新增页面时一起检查。config/lib.ts将 Vue 设为外部依赖,嵌入库修改需验证宿主兼容性,不擅自打包第二份 Vue。- XPack 前端通过
PluginComponent.vue等加载和桥接。修改组件映射、jsname、共享全局对象或调用方法时,同步核对扩展导出,并验证加载失败、无授权与加载完成前的方法调用;不能只验证开发模式下的一条加载路径。 - JSON 行为以
sdk/common的JacksonConfig和字段注解为准:当前默认保留空值,部分 ID 使用字段级字符串序列化。不得假设全局 Long 都转字符串,或为单个接口改动全局空值/数字规则。 - 图表视觉改动在实际渲染层验证:尺寸、长文本、空数据、图例筛选、重复更新/缩放、事件解绑及销毁。不能仅凭配置对象正确就认定效果正确。
- 渲染不可信富文本、URL 或 HTML 时复用现有净化机制;不得为展示效果关闭过滤。
7. 构建与验证
先选择最小但有意义的验证,再根据依赖影响扩大范围。纯文档或低风险样式改动不要求新增测试;查询、权限、迁移、字段更新等行为改动应尽量增加能复现问题的回归验证。
前端
以下命令在 core/core-frontend 执行,依赖需已安装:
| 命令 | 用途与边界 |
|---|---|
npm run ts:check |
TypeScript 检查;若存在基线问题,区分与本次改动的关系 |
./node_modules/.bin/eslint <改动文件路径> |
定向 lint,不加 --fix;占位符需替换为实际文件 |
npm run dev |
开发服务;当前配置端口 7070,代理后端 8100 |
npm run build:base |
base 模式构建 |
npm run build:distributed |
distributed 模式构建 |
npm run build:lib |
嵌入库构建 |
npm run lint和npm run lint:stylelint带自动修复,不能作为只读检查命令;避免造成无关文件改动。build:base/build:distributed会继续执行build:flush,其中包含子目录依赖安装和文件生成。执行前确认副作用与任务范围一致。- 前端没有统一
test脚本。饼图标签相关改动可按tests/pie-label-overflow/README.md使用现有 Vite 页面和 Playwright 验证;它不等于完整产品回归。 - 不自动升级依赖或重建全部锁文件;新增依赖需说明必要性,并检查许可证、体积和实际跟踪的锁文件。
后端与整包
- 根目录
mvn install用于当前聚合的 SDK 及父 POM;不会自动构建core和 XPack。 - 完整核心应用可在依赖就绪后使用
mvn -f core/pom.xml package -Pstandalone或任务所需的其他 Profile;这会触发前端构建及资源处理,不能用作轻量或只读检查。 - 后端局部编译可使用
mvn -f core/core-backend/pom.xml compile -Pstandalone,前提是父 POM、SDK 和所需前端产物已就绪。Maven 生命周期可能复制资源、生成 Q 类和 flattened POM;它不是无副作用的语法检查。 standalone默认启用;desktop使用桌面配置;distributed需要相应依赖并排除替补权限代码。以实际 POM 为准,不使用未定义的 Profile。- 前端 Maven 当前固定执行
build:distributed,不要认为后端-Pdesktop或-Pstandalone会自动切换前端模式。 - 后端 Surefire 当前有显式
<skip>true</skip>。普通mvn test成功不代表测试执行;必须核对有效配置、实际日志和本次生成的测试报告。不要假定添加-DskipTests=false就能覆盖该配置。 - 行为测试需要启用时,先确认可行的项目测试入口;若需调整构建配置,保持改动明确且符合任务范围。无法执行时说明原因,不把编译结果写成测试通过。
- 不默认执行
mvn clean:前端 Maven clean 会清理依赖和锁文件,后端部分 Profile 会清理生成的静态资源。只在确实需要清理时使用。 - 不直接修改已有 SDK 二进制或生成类来绕过编译错误;修复源码及依赖关系后重新生成。
验证覆盖选择
| 改动类型 | 优先验证 |
|---|---|
| API / DTO | 请求与响应兼容性、前端调用、核心和扩展实现编译 |
| 权限 | 允许/拒绝、不同用户或组织、相关分享/嵌入路径、导出路径 |
| 查询 / 图表计算 | 空值、筛选、排序、聚合、行列权限及受影响的数据源方言 |
| JPA 更新 / 迁移 | 保留未提交字段、显式清空、事务失败、存量升级与失败重试 |
| 编辑器 / 图表 UI | 实际渲染、重复交互、保存重开、相关移动端或嵌入入口 |
| 部署 / Profile | 构建产物、资源位置、外置配置与目标运行模式 |
只声明实际验证过的环境和行为;未覆盖的数据库、入口或 Profile 明确列为限制。
8. V2/V3 修复同步
- V2 与 V3 持续独立迭代,可能位于不同目录,也可能是同一仓库的不同分支。另一版本的提交、PR 或修复说明是调查线索,不是可直接合并的补丁;不得在有未提交改动的工作区为查看来源版本擅自切换分支。
- 用户明确要求跨版本同步,或提供另一版本的修复并要求在当前版本处理时,先依据用户提供的来源提交/PR、可访问的代码或复现信息,提取问题触发条件、预期行为、边界情况与回归场景。普通单版本任务不自动修改另一版本,也不因功能相似就自行扩大任务范围。
- 来源代码不在当前可访问范围时,先使用可用的提交/PR 和问题描述;不足以确认行为时,请用户提供差异或访问方式。读取来源版本不要求获得其长期写权限;跨版本修改分别在各自目标版本的工作区完成。
- 沿当前版本的实际入口和调用链确认问题是否存在,检查已有修复及版本特有行为。若已解决或功能不适用,给出代码或验证依据,不为保持两边代码形式一致而制造改动。
- 从 V2 同步到 V3 时,按 V3 的 JPA/QueryDSL、数据库方言、迁移机制及重构后的权限契约重新实现;不得直接移植 MyBatis Mapper、仅适用于 MySQL 的 SQL、旧权限判断或 Flyway 脚本。前端、API 和 XPack 也应分别核对当前契约与实现边界。
- 验证目标版本的回归场景和受影响入口;涉及持久化、查询或权限时,按第 7 节覆盖相关数据库、身份和拒绝路径。完成说明记录来源版本及提交/PR(如有)、目标版本对应改动、行为差异、已执行验证和未覆盖项。
- 两个版本各自遵守本仓库的分支、提交和发布流程。跨版本同步不授权自动提交、推送或创建 PR;只有任务包含相应交付要求时才按第 9 节执行。
9. Git、提交与交付
DataEase 主仓库:PR 合入 dev-v3
- 开发目标为
dev-v3,交付时使用任务分支创建 PR,不直接推送主仓库dev-v3。 - 任务分支沿用维护者命名:
pr@dev-v3@fix_something、pr@dev-v3@perf_something、pr@dev-v3@chore_something,后缀描述实际任务。PR base 明确为dev-v3。 - 提交消息遵循
.github/PULL_REQUEST_TEMPLATE.md要求的 Conventional Commits,例如fix(chart): 修复标签越界。分支命名与提交消息格式是两个不同约定。 - 在已有工作区准备 PR 时,保留用户未提交/已暂存的内容;按具体路径选择本次修改,不使用全量暂存把无关变更带入 PR。
de-xpack:直接同步 dev-v3
- 维护者已指定 XPack 可直接推送
dev-v3,不要求套用主仓库 PR 流程。在任务明确进入提交/推送阶段时按此执行,无需仅因“直推”再次征求相同许可;纯分析或规范维护任务不会因此自动触发 Git 发布。 - 先检查子仓库分支、状态和本地待推送提交;确认本次代码已验证并提交、工作区适合 rebase、不会夹带其他任务的提交。不要擅自 stash、丢弃用户修改或在 detached HEAD 上盲目执行。
- 在主仓库根目录依次执行以下命令;第一条成功且冲突已解决、验证完成后,才执行第二条:
git -C de-xpack pull origin dev-v3 --rebase
git -C de-xpack push origin dev-v3
- rebase 冲突按双方业务意图解决,不机械采用整边覆盖。推送遇到非快进时重新同步并检查结果,不使用强制推送绕过远端更新;认证或网络错误应报告实际原因。
- 本地
origin可能采用fit2cloud.github.com等 SSH Host 别名;核对仓库身份即可,不为统一 URL 形式擅自改 remote。
跨仓库交付与检查
-
同时修改 SDK/主程序和 XPack 时,检查接口新旧版本兼容性,按依赖关系安排交付;XPack 直推与主仓库 PR 合并不是原子操作,不能让尚未合入的契约变更无说明地破坏另一仓库。
-
需要更新主仓库的子模块指针时,先确认目标 XPack 提交已推送可获取,再将指针更新纳入主仓库 PR。只修改主仓库时,不顺带提交工作区中原有的子模块指针差异。
-
检查本次差异和
git diff --check;涉及子模块时单独检查其差异。忽略目录内的新文件要核实跟踪状态,不直接修改全局忽略规则或把生成物强制加入仓库。 -
确认没有混入密码、业务数据、构建产物、依赖缓存或与任务无关的格式化修改。
-
仅在任务包含提交/交付要求时暂存、提交或推送,按本节约定执行;已获得的授权持续有效。用户已有暂存内容保持原状,不擅自改写远端历史。
-
完成说明应包含:解决的问题、主要修改文件、已运行的验证及结果、未验证项与原因。涉及 SDK/XPack、历史数据或配置迁移时说明影响。
-
PR 按实际问题和最终行为描述,遵循仓库模板,目标分支为维护者指定的
dev-v3;不要把计划中的验证写成已完成。两仓库的提交、推送和 PR 状态分别报告。