docs: initialize harness coding docs
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
# AGENTS.md
|
||||
|
||||
> Codex / AI coding agent 的仓库级入口。进入本仓库后,先读本文,再读 `docs/00-ai-start-here.md`。
|
||||
|
||||
## 项目定位
|
||||
|
||||
Dingding HRM 是一个 Go + Gin 本地 Web 应用,用于同步、浏览、搜索和导出钉钉多站点部门与人员数据。
|
||||
|
||||
本项目从旧 Python 脚本迁移而来。旧脚本只负责从钉钉 OpenAPI 拉取 JSON 文件;新项目要提供 SQLite 持久化、REST API、原生前端页面和可手动触发的数据同步。
|
||||
|
||||
## Harness Coding 文档入口
|
||||
|
||||
本项目后续编码所需的 harness coding 文档都在 `docs/` 目录中。Codex 开始编程时,不需要查找 `README.md` 或历史分析文件,直接按下面顺序读取 `docs/` 即可。
|
||||
|
||||
| 文档 | 用途 |
|
||||
| --- | --- |
|
||||
| `docs/00-ai-start-here.md` | AI coding agent 的启动入口、阅读顺序、任务领取规则 |
|
||||
| `docs/01-vision.md` | 项目目标、用户、产品原则、非目标 |
|
||||
| `docs/02-requirements.md` | MVP 需求、用户故事、验收标准 |
|
||||
| `docs/03-tech-stack.md` | Go + Gin、SQLite、原生前端等技术选型 |
|
||||
| `docs/04-architecture.md` | 系统结构、职责边界、数据模型、开发顺序 |
|
||||
| `docs/05-coding-rules.md` | 写代码前必须遵守的硬规则 |
|
||||
| `docs/06-tasks.md` | 分阶段任务看板,每轮只领取一个任务 |
|
||||
| `docs/api.md` | REST API 合约、错误格式、分页筛选约定 |
|
||||
| `docs/routes.md` | 原生前端页面路由和模块归属 |
|
||||
| `docs/current-state.md` | 当前代码现实、可运行命令、下一步任务 |
|
||||
|
||||
## 必读顺序
|
||||
|
||||
每次开始工作前,按顺序读取:
|
||||
|
||||
1. `AGENTS.md`
|
||||
2. `docs/00-ai-start-here.md`
|
||||
3. `docs/05-coding-rules.md`
|
||||
4. `docs/current-state.md`
|
||||
5. 与当前任务相关的具体文档
|
||||
|
||||
如果准备写代码,还必须查看 `docs/06-tasks.md`,只领取第一个状态为 `TODO` 且依赖均完成的任务。
|
||||
|
||||
## 技术硬约束
|
||||
|
||||
- 后端使用 Go + Gin。
|
||||
- 数据库使用 SQLite。
|
||||
- 前端不使用 Vue、React、Svelte、Angular、Element Plus、Vite 等框架或构建链。
|
||||
- 前端使用原生 HTML/CSS/JavaScript,静态文件由 Gin 托管。
|
||||
- 钉钉 OpenAPI 只能由后端调用,浏览器端不得直接请求钉钉接口。
|
||||
- 密钥、token、真实手机号等敏感数据不得写入代码或文档样例。
|
||||
|
||||
## 工作规则
|
||||
|
||||
- 需求、API、数据模型或路由变化时,先更新 `docs/` 中对应文档。
|
||||
- 代码实现必须服从 `docs/03-tech-stack.md`、`docs/04-architecture.md` 和 `docs/api.md`。
|
||||
- 不要引入旧方案中的 Vue / chi 技术栈;最终约束以 `docs/` 为准。
|
||||
- 不要在未确认的情况下引入前端依赖、后台任务库或 ORM。
|
||||
- 每轮只做一个任务,做完后更新 `docs/06-tasks.md` 和 `docs/current-state.md`。
|
||||
|
||||
## 验证
|
||||
|
||||
当前尚未初始化代码。初始化后至少维护这些命令:
|
||||
|
||||
```powershell
|
||||
go test ./...
|
||||
go build ./...
|
||||
```
|
||||
|
||||
如果前端只是静态文件,验证应包含:
|
||||
|
||||
- Gin 启动后 `/` 可访问。
|
||||
- `/api/health` 返回正常。
|
||||
- 页面能通过同源 `/api/*` 请求后端。
|
||||
@@ -0,0 +1,49 @@
|
||||
# CLAUDE.md
|
||||
|
||||
> Claude Code 的仓库级上下文。进入本仓库后,先读本文,再读 `docs/00-ai-start-here.md`。
|
||||
|
||||
## 仓库用途
|
||||
|
||||
本仓库用于实现 Dingding HRM:一个用 Go + Gin 编写的钉钉部门和人员浏览、搜索、同步管理工具。
|
||||
|
||||
项目不使用前端框架。Gin 后端既提供 REST API,也托管原生前端静态文件。
|
||||
|
||||
## Harness Coding 文档入口
|
||||
|
||||
本项目后续 Claude Code 编程所需的 harness coding 文档都在 `docs/` 目录中。不要依赖根目录 `README.md` 或历史分析文件作为入口。
|
||||
|
||||
| 文档 | 用途 |
|
||||
| --- | --- |
|
||||
| `docs/00-ai-start-here.md` | AI coding agent 的启动入口、阅读顺序、任务领取规则 |
|
||||
| `docs/01-vision.md` | 项目目标、用户、产品原则、非目标 |
|
||||
| `docs/02-requirements.md` | MVP 需求、用户故事、验收标准 |
|
||||
| `docs/03-tech-stack.md` | Go + Gin、SQLite、原生前端等技术选型 |
|
||||
| `docs/04-architecture.md` | 系统结构、职责边界、数据模型、开发顺序 |
|
||||
| `docs/05-coding-rules.md` | 写代码前必须遵守的硬规则 |
|
||||
| `docs/06-tasks.md` | 分阶段任务看板,每轮只领取一个任务 |
|
||||
| `docs/api.md` | REST API 合约、错误格式、分页筛选约定 |
|
||||
| `docs/routes.md` | 原生前端页面路由和模块归属 |
|
||||
| `docs/current-state.md` | 当前代码现实、可运行命令、下一步任务 |
|
||||
|
||||
## 关键事实
|
||||
|
||||
- 新项目技术事实以 `docs/03-tech-stack.md` 为准。
|
||||
- 新项目架构、数据库和目录边界以 `docs/04-architecture.md` 为准。
|
||||
- API 合约以 `docs/api.md` 为准。
|
||||
- 页面与静态前端结构以 `docs/routes.md` 为准。
|
||||
|
||||
## 工作方式
|
||||
|
||||
1. 先确认当前任务是写文档、初始化代码、实现接口、实现页面,还是做同步逻辑。
|
||||
2. 写代码前按 `docs/00-ai-start-here.md` 的顺序读取上下文。
|
||||
3. 从 `docs/06-tasks.md` 领取一个任务,不跳步。
|
||||
4. 修改后运行对应验证命令,并在回复中说明结果。
|
||||
5. 如果发现文档和代码现实冲突,优先更新 `docs/current-state.md` 并说明冲突。
|
||||
|
||||
## 不要做
|
||||
|
||||
- 不要使用 Vue、React、Element Plus 或 Vite。
|
||||
- 不要让浏览器直接访问钉钉 OpenAPI。
|
||||
- 不要把真实 app_key、app_secret、access_token、手机号写入仓库。
|
||||
- 不要从旧 JSON 文件中推断未记录的字段含义。
|
||||
- 不要一次性生成完整大系统;按任务看板小步实现。
|
||||
@@ -0,0 +1,96 @@
|
||||
# AI 开发入口
|
||||
|
||||
> 给 AI coding agent 的项目入口。这里负责导航和流程,硬性编码规则见 [`05-coding-rules.md`](05-coding-rules.md)。
|
||||
|
||||
## 一句话定位
|
||||
|
||||
Dingding HRM 是一个 Go + Gin + SQLite 本地 Web 应用,用于同步、浏览、搜索和导出钉钉多站点部门与人员数据。
|
||||
|
||||
第一版 MVP 只做:多站点配置、手动全量同步、部门树浏览、人员搜索筛选、JSON/CSV 导出、Gin 托管原生前端。
|
||||
|
||||
## 必读顺序
|
||||
|
||||
每次开始写代码前,按这个顺序建立上下文:
|
||||
|
||||
1. [`01-vision.md`](01-vision.md):为什么做、为谁做、什么不做。
|
||||
2. [`02-requirements.md`](02-requirements.md):MVP 要什么、怎么算达成。
|
||||
3. [`03-tech-stack.md`](03-tech-stack.md):既定技术选型。
|
||||
4. [`04-architecture.md`](04-architecture.md):系统结构、职责划分、数据模型和关键难点。
|
||||
5. [`05-coding-rules.md`](05-coding-rules.md):写代码前必须遵守的规则。
|
||||
6. [`06-tasks.md`](06-tasks.md):领取本轮唯一任务。
|
||||
7. [`current-state.md`](current-state.md):当前代码现实、可运行命令、下一步任务。
|
||||
|
||||
仓库根目录的 `AGENTS.md`、`CLAUDE.md` 也必须先读。仓库级规则优先。
|
||||
|
||||
## 当前阶段
|
||||
|
||||
当前项目处于:MVP 起步,尚未初始化 Go 代码。
|
||||
|
||||
优先路径:
|
||||
|
||||
1. Phase 0:Go + Gin + SQLite + 静态文件托管的最小可运行地基。
|
||||
2. Phase 1:验证钉钉 token、部门、用户接口封装。
|
||||
3. Phase 2:实现同步入库和查询 API。
|
||||
4. Phase 3:实现原生前端部门浏览、人员搜索、导出。
|
||||
5. Phase 4:验收、打包、运行文档。
|
||||
|
||||
## 领取任务规则
|
||||
|
||||
从 [`06-tasks.md`](06-tasks.md) 领取任务时:
|
||||
|
||||
- 只领取第一个状态为 `TODO` 且依赖均为 `DONE` 的任务。
|
||||
- 开始前把该任务状态改为 `DOING`。
|
||||
- 本轮只完成这一个任务。
|
||||
- 验收通过后把状态改为 `DONE`。
|
||||
- 做完即停,汇报验证结果,等待下一步指令。
|
||||
|
||||
如果代码实际状态和任务看板冲突,先说明冲突,不要擅自跳步。
|
||||
|
||||
## MVP 边界
|
||||
|
||||
MVP 只做:
|
||||
|
||||
- 站点配置管理,保存多站点 app_key / app_secret。
|
||||
- 手动全量同步部门和人员数据。
|
||||
- 后端缓存并刷新 access_token。
|
||||
- 部门树浏览。
|
||||
- 人员列表、关键词搜索、部门筛选、分页。
|
||||
- JSON/CSV 导出。
|
||||
- 原生 HTML/CSS/JavaScript 前端,由 Gin 托管。
|
||||
|
||||
MVP 不做:
|
||||
|
||||
- 登录、多用户权限、审计审批。
|
||||
- 钉钉回调事件订阅。
|
||||
- 复杂组织变更历史追踪。
|
||||
- 前端框架、组件库或独立前端构建链。
|
||||
- 云部署、Docker、分布式任务队列。
|
||||
|
||||
## 事实来源
|
||||
|
||||
项目事实只信:
|
||||
|
||||
- `docs/` 中已定稿的需求、技术栈、架构、API 和路由。
|
||||
- 后续代码中的数据库迁移和模型定义。
|
||||
- 实现过程中通过钉钉 OpenAPI 官方响应和本地测试确认的字段事实。
|
||||
|
||||
不要把以下内容当事实来源:
|
||||
|
||||
- 未导入仓库的旧 Python 源码猜测。
|
||||
- 临时 JSON 导出中未被文档确认的字段含义。
|
||||
|
||||
## 验证命令
|
||||
|
||||
当前尚未初始化代码。初始化后维护这些命令:
|
||||
|
||||
```powershell
|
||||
go test ./...
|
||||
go build ./...
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- 改后端后跑:`go test ./...`。
|
||||
- 改构建或入口后跑:`go build ./...`。
|
||||
- 改静态前端后至少启动 Gin 并人工访问 `/` 与相关 `/api/*`。
|
||||
- 如果命令当前不可运行,回复里必须说明原因。
|
||||
@@ -0,0 +1,40 @@
|
||||
# 项目愿景
|
||||
|
||||
## 一、核心目标
|
||||
|
||||
Dingding HRM 要解决:现有钉钉组织和人员数据只能通过 Python 脚本导出 JSON,缺少集中浏览、搜索、同步和导出的管理界面。
|
||||
|
||||
> 让内部管理人员能够在一个本地 Web 工具中查看多站点钉钉部门架构和人员信息,并快速搜索、筛选、导出。
|
||||
|
||||
它不是完整 HR 系统,也不是钉钉替代品,而是一个围绕钉钉组织通讯录数据的轻量管理工具。
|
||||
|
||||
## 二、目标用户
|
||||
|
||||
- 内部管理员:配置站点密钥、触发同步、查看同步状态。
|
||||
- HR / 行政人员:按站点、部门、姓名、手机号、工号查找人员。
|
||||
- 开发维护者:维护钉钉 API 适配、数据库迁移、导出逻辑和本地部署。
|
||||
|
||||
## 三、产品原则
|
||||
|
||||
- 核心查询优先:先保证部门树、人员列表、搜索筛选可靠。
|
||||
- 数据真实优先:以钉钉 OpenAPI 返回和 SQLite 入库结果为准,不用演示数据冒充真实数据。
|
||||
- 本地单体优先:MVP 用单个 Go 服务完成 API、同步、静态前端托管。
|
||||
- 低依赖优先:不引入前端框架,不引入复杂后台任务系统。
|
||||
- 密钥安全优先:真实 app_secret、token 不进入代码、文档样例或日志明文。
|
||||
|
||||
## 四、核心价值主张
|
||||
|
||||
| 价值点 | 说明 |
|
||||
| --- | --- |
|
||||
| 集中查看 | 把梅州、东莞、合肥等站点的组织和人员数据放入统一界面 |
|
||||
| 快速检索 | 支持按姓名、手机号、工号、部门筛选人员 |
|
||||
| 可控同步 | 管理员可手动同步钉钉数据,并查看成功或失败状态 |
|
||||
| 简单部署 | Go 单体服务托管 API 和静态页面,减少前后端分离复杂度 |
|
||||
|
||||
## 五、不做什么(非目标)
|
||||
|
||||
- 不做人事档案全生命周期管理。
|
||||
- 不做薪酬、考勤、审批、绩效等 HR 模块。
|
||||
- 不做复杂权限系统,MVP 默认本地受信环境使用。
|
||||
- 不做前端框架版本,不引入 Vue / React / Element Plus。
|
||||
- 不在浏览器端直接调用钉钉 OpenAPI。
|
||||
@@ -0,0 +1,75 @@
|
||||
# 需求
|
||||
|
||||
> 本文只描述要什么与怎么算达成,用产品 / 用户语言表达。技术方案、数据结构、字段定义见 [架构设计](04-architecture.md)。
|
||||
|
||||
## 一、业务现状
|
||||
|
||||
| 项 | 状态 |
|
||||
| --- | --- |
|
||||
| 用户 | 内部管理员、HR / 行政人员需要查看多站点钉钉组织和人员数据 |
|
||||
| 数据 | 旧 Python 脚本可从钉钉 OpenAPI 拉取部门、部门用户 ID、用户详情,并保存为 JSON |
|
||||
| 现有系统 | 当前仓库尚未有应用代码;旧项目位于 `D:\PythonP\snippets\DingtalkHRM` |
|
||||
| 约束 | 钉钉 OpenAPI 有 CORS 和密钥安全限制,必须由后端代理调用 |
|
||||
|
||||
## 二、用户角色
|
||||
|
||||
- 管理员:配置站点、维护 app_key / app_secret、触发同步、查看同步日志。
|
||||
- 查询用户:浏览部门树、搜索人员、导出当前人员数据。
|
||||
- 未登录用户:MVP 暂不做登录,默认运行在本地或受信内网。
|
||||
|
||||
## 三、功能清单
|
||||
|
||||
### 第一版 MVP(最小闭环)
|
||||
|
||||
| 功能 | 用户能做什么 | 优先级 |
|
||||
| --- | --- | --- |
|
||||
| 站点配置 | 新增、修改、删除梅州 / 东莞 / 合肥等站点配置 | P0 |
|
||||
| 手动全量同步 | 对指定站点拉取部门和人员详情并写入 SQLite | P0 |
|
||||
| 部门浏览 | 选择站点后查看部门树,点击部门查看成员 | P0 |
|
||||
| 人员搜索筛选 | 按姓名、手机号、工号关键词搜索,按部门和状态筛选 | P0 |
|
||||
| 分页列表 | 以表格分页展示人员核心字段 | P0 |
|
||||
| 数据导出 | 导出当前站点或筛选结果为 JSON / CSV | P0 |
|
||||
| 同步日志 | 查看最近同步时间、状态和错误信息 | P0 |
|
||||
|
||||
### 后续迭代
|
||||
|
||||
| 功能 | 描述 | 阶段 |
|
||||
| --- | --- | --- |
|
||||
| 定时同步 | 按配置周期自动同步站点数据 | V2 |
|
||||
| 登录权限 | 增加管理员账号和访问控制 | V2 |
|
||||
| 增量同步 | 优先同步变更数据,减少 OpenAPI 调用 | V3 |
|
||||
| 变更历史 | 记录部门和人员字段变化 | V3 |
|
||||
|
||||
## 四、核心用户故事(MVP)
|
||||
|
||||
1. 作为管理员,我打开系统后能看到已配置站点和每个站点的同步状态。
|
||||
2. 我可以选择一个站点并点击同步,系统会拉取钉钉部门和人员数据。
|
||||
3. 我可以打开部门页面,看到树形部门结构,并查看某个部门下的人员。
|
||||
4. 我可以在人员页面输入姓名、手机号或工号,快速定位员工。
|
||||
5. 我可以导出当前站点或当前筛选条件下的人员数据。
|
||||
6. 当钉钉接口失败或密钥错误时,系统会展示失败状态和可读错误信息。
|
||||
|
||||
## 五、验收标准(MVP)
|
||||
|
||||
- 站点配置:新增站点后刷新页面仍存在;密钥字段不在列表页明文展示。
|
||||
- 手动同步:点击同步后生成同步日志;成功后部门和人员数据可查询;失败时保存错误信息。
|
||||
- 部门浏览:选中站点后展示部门层级;点击部门后右侧人员列表随之过滤。
|
||||
- 人员搜索筛选:关键词、部门、状态、分页参数可组合使用;结果数量和列表一致。
|
||||
- 数据导出:JSON 返回 UTF-8 JSON;CSV 可用 Excel 打开且包含表头。
|
||||
- 静态前端:访问 `/` 可打开应用;所有前端请求使用同源 `/api/*`。
|
||||
|
||||
## 六、范围边界与决策
|
||||
|
||||
| 问题 | 决策 |
|
||||
| --- | --- |
|
||||
| 第一版平台 | 本地 / 内网 Web 应用 |
|
||||
| 是否需要账号 | MVP 不做登录,后续再评估 |
|
||||
| 第一版范围 | 站点配置、同步、浏览、搜索、导出 |
|
||||
| 暂不支持 | 前端框架、云部署、多用户权限、钉钉回调 |
|
||||
|
||||
## 七、待确认 / 风险点
|
||||
|
||||
- 钉钉接口配额:需要在同步服务中记录错误和失败位置,避免静默丢数据。
|
||||
- 部门与用户关系:用户可能属于多个部门,MVP 需保留 `dept_id_list` 原始 JSON 字段。
|
||||
- 旧 JSON 迁移:是否需要导入旧 JSON 作为初始数据,待实现同步前确认。
|
||||
- 密钥存储:MVP 先存 SQLite,后续可评估本机加密或环境变量覆盖。
|
||||
@@ -0,0 +1,54 @@
|
||||
# 技术栈(Tech Stack)
|
||||
|
||||
> “用什么”的统一速查表。选型与理由在此集中维护;“怎么把它们搭起来”见 [架构设计](04-architecture.md)。
|
||||
|
||||
## 一、技术栈一览
|
||||
|
||||
| 维度 | 选型 | 状态 | 理由 / 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| 前端框架 | 无,原生 HTML/CSS/JavaScript | 已定 | 降低构建复杂度,由 Gin 直接托管 |
|
||||
| UI 样式方案 | 手写 CSS | 已定 | MVP 页面数量少,避免引入组件库 |
|
||||
| 状态管理 | 浏览器内存状态 + URL 查询参数 | 已定 | 站点、部门、筛选条件简单可控 |
|
||||
| 后端 | Go + Gin | 已定 | 用户指定;路由、中间件和静态文件托管成熟 |
|
||||
| 数据库 | SQLite | 已定 | 本地单体应用,无需独立数据库服务 |
|
||||
| SQLite 驱动 | `modernc.org/sqlite` 优先 | 待验证 | 纯 Go,Windows 构建更简单;如遇兼容问题再评估 `mattn/go-sqlite3` |
|
||||
| 鉴权方式 | MVP 无账号 | 已定 | 默认本地或受信内网运行 |
|
||||
| 钉钉 API 客户端 | Go `net/http` | 已定 | 标准库足够,便于测试和超时控制 |
|
||||
| 部署方式 | 单个 Go 进程 + SQLite 文件 + 静态文件 | 已定 | 简单可复制 |
|
||||
| 测试 | `go test ./...` | 已定 | 覆盖服务层、数据层、handler |
|
||||
|
||||
## 二、决策记录与演进
|
||||
|
||||
- 不引入前端框架:当前页面是管理工具界面,原生 DOM 和 fetch 足够完成 MVP。
|
||||
- 使用 Gin 托管前端:避免前后端两个开发服务器和 CORS 配置。
|
||||
- SQLite 作为唯一持久化:站点配置、token、部门、人员、同步日志都入库。
|
||||
- 不引入 ORM:优先使用 `database/sql` 和小型 repository,避免隐藏 SQL 行为。
|
||||
- 定时任务 V2 再做:MVP 先实现手动同步和 token 按需刷新。
|
||||
|
||||
## 三、构建与运行命令
|
||||
|
||||
当前尚未初始化代码,以下是目标命令:
|
||||
|
||||
| 用途 | 命令 |
|
||||
| --- | --- |
|
||||
| 初始化依赖 | `go mod tidy` |
|
||||
| 本地开发 | `go run .` |
|
||||
| 构建 | `go build ./...` |
|
||||
| 测试 | `go test ./...` |
|
||||
| 格式化 | `gofmt -w .` |
|
||||
|
||||
Windows PowerShell:
|
||||
|
||||
```powershell
|
||||
go mod tidy
|
||||
go run .
|
||||
go test ./...
|
||||
go build ./...
|
||||
```
|
||||
|
||||
## 四、依赖纪律
|
||||
|
||||
- 新增第三方依赖前,先说明用途、替代方案和维护成本。
|
||||
- 不允许引入 Vue、React、Element Plus、Vite、Webpack 等前端框架或构建链。
|
||||
- 不允许同一职责并存两套路由、数据库访问或状态管理方案。
|
||||
- 钉钉 SDK 不是默认选择;除非标准 HTTP 封装无法满足需求。
|
||||
@@ -0,0 +1,185 @@
|
||||
# 架构设计
|
||||
|
||||
> 本文讲系统结构、职责划分、数据模型、技术难点、开发顺序。具体技术选型见 [技术栈](03-tech-stack.md)。
|
||||
|
||||
## 一、系统结构
|
||||
|
||||
```text
|
||||
浏览器
|
||||
|
|
||||
| GET /, /static/*
|
||||
| fetch /api/*
|
||||
v
|
||||
Go + Gin 单体服务
|
||||
| |
|
||||
| +-- 托管 web/ 静态前端文件
|
||||
|
|
||||
+-- REST handlers
|
||||
+-- services: 钉钉 API、同步、导出
|
||||
+-- repositories: SQLite 读写
|
||||
| |
|
||||
| +-- SQLite 数据库
|
||||
|
|
||||
+-- 钉钉 OpenAPI
|
||||
```
|
||||
|
||||
## 二、职责划分
|
||||
|
||||
**原生前端**
|
||||
|
||||
- 渲染站点选择、同步状态、部门树、人员表格、筛选表单。
|
||||
- 使用 `fetch` 调用同源 `/api/*`。
|
||||
- 只保存当前页面交互状态,不保存密钥和 token。
|
||||
- 不直接访问钉钉 OpenAPI。
|
||||
|
||||
**Gin 后端**
|
||||
|
||||
- 托管 `web/` 静态文件。
|
||||
- 提供 REST API。
|
||||
- 负责请求参数校验、错误响应、分页与导出。
|
||||
- 封装钉钉 OpenAPI 调用、token 获取与复用。
|
||||
- 执行同步流程并记录同步日志。
|
||||
|
||||
**SQLite / repository**
|
||||
|
||||
- 持久化站点配置、access token、部门、人员、同步日志。
|
||||
- 保存钉钉返回的关键字段和必要原始 JSON 字段。
|
||||
- 提供按站点、部门、关键词、状态分页查询。
|
||||
|
||||
## 三、数据模型
|
||||
|
||||
### 3.1 站点与 token
|
||||
|
||||
```sql
|
||||
CREATE TABLE sites (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
code TEXT NOT NULL UNIQUE,
|
||||
name TEXT NOT NULL,
|
||||
app_key TEXT NOT NULL,
|
||||
app_secret TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE access_tokens (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
site_id INTEGER NOT NULL REFERENCES sites(id) ON DELETE CASCADE,
|
||||
token TEXT NOT NULL,
|
||||
expires_in INTEGER NOT NULL,
|
||||
fetched_at INTEGER NOT NULL,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
```
|
||||
|
||||
### 3.2 部门
|
||||
|
||||
```sql
|
||||
CREATE TABLE departments (
|
||||
site_id INTEGER NOT NULL REFERENCES sites(id) ON DELETE CASCADE,
|
||||
dept_id INTEGER NOT NULL,
|
||||
parent_id INTEGER NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
raw_json TEXT,
|
||||
updated_at TEXT NOT NULL,
|
||||
PRIMARY KEY (site_id, dept_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_departments_site_parent ON departments(site_id, parent_id);
|
||||
```
|
||||
|
||||
### 3.3 人员
|
||||
|
||||
```sql
|
||||
CREATE TABLE users (
|
||||
site_id INTEGER NOT NULL REFERENCES sites(id) ON DELETE CASCADE,
|
||||
userid TEXT NOT NULL,
|
||||
name TEXT,
|
||||
mobile TEXT,
|
||||
title TEXT,
|
||||
job_number TEXT,
|
||||
active INTEGER,
|
||||
avatar TEXT,
|
||||
unionid TEXT,
|
||||
dept_id INTEGER,
|
||||
dept_id_list TEXT,
|
||||
dept_name TEXT,
|
||||
hired_date INTEGER,
|
||||
raw_json TEXT,
|
||||
updated_at TEXT NOT NULL,
|
||||
PRIMARY KEY (site_id, userid)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_users_site_name ON users(site_id, name);
|
||||
CREATE INDEX idx_users_site_mobile ON users(site_id, mobile);
|
||||
CREATE INDEX idx_users_site_job_number ON users(site_id, job_number);
|
||||
CREATE INDEX idx_users_site_dept ON users(site_id, dept_id);
|
||||
```
|
||||
|
||||
### 3.4 同步日志
|
||||
|
||||
```sql
|
||||
CREATE TABLE sync_logs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
site_id INTEGER REFERENCES sites(id) ON DELETE SET NULL,
|
||||
sync_type TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
message TEXT,
|
||||
started_at TEXT NOT NULL,
|
||||
finished_at TEXT
|
||||
);
|
||||
```
|
||||
|
||||
## 四、关键技术难点
|
||||
|
||||
| 难点 | 说明 | 应对 |
|
||||
| --- | --- | --- |
|
||||
| token 过期 | access_token 有有效期,接口失败可能由 token 过期导致 | 按需获取;过期前刷新;失败日志可见 |
|
||||
| 部门递归 | 需要从根部门 `dept_id=1` 拉完整树 | 先实现 BFS/队列同步,并测试重复和空子部门 |
|
||||
| 用户多部门 | 用户可能属于多个部门,单 `dept_id` 不足 | 保留 `dept_id_list` 原始 JSON,MVP 用主部门筛选 |
|
||||
| 密钥安全 | app_secret 需要存储但不能泄露 | 列表和日志不返回密钥;导出不包含密钥 |
|
||||
| 静态前端复杂度 | 原生 JS 容易膨胀 | 按页面拆分 `web/assets/*.js`,保持小模块 |
|
||||
|
||||
## 五、推荐开发顺序
|
||||
|
||||
1. 初始化 Go module、Gin、健康检查、静态文件托管。
|
||||
2. 建立 SQLite 连接、迁移和基础 repository。
|
||||
3. 实现站点 CRUD API。
|
||||
4. 实现钉钉 token、部门、用户 API client。
|
||||
5. 实现全量同步入库和同步日志。
|
||||
6. 实现部门、用户、导出 API。
|
||||
7. 实现原生前端页面。
|
||||
8. 完整验收和运行文档。
|
||||
|
||||
## 六、项目结构建议
|
||||
|
||||
```text
|
||||
dingding_hrm/
|
||||
├── docs/
|
||||
├── main.go
|
||||
├── go.mod
|
||||
├── internal/
|
||||
│ ├── config/
|
||||
│ ├── db/
|
||||
│ ├── dingtalk/
|
||||
│ ├── handler/
|
||||
│ ├── model/
|
||||
│ ├── repository/
|
||||
│ └── service/
|
||||
├── web/
|
||||
│ ├── index.html
|
||||
│ └── assets/
|
||||
│ ├── app.js
|
||||
│ └── style.css
|
||||
├── data/
|
||||
│ └── dingding_hrm.db
|
||||
├── AGENTS.md
|
||||
└── CLAUDE.md
|
||||
```
|
||||
|
||||
## 七、架构纪律
|
||||
|
||||
- `handler` 不直接拼 SQL,不直接调用钉钉 OpenAPI。
|
||||
- `service` 编排业务流程,但不处理 HTTP 细节。
|
||||
- `repository` 只负责 SQLite 读写和事务。
|
||||
- `dingtalk` 包只负责 OpenAPI 请求、响应解析和错误归一。
|
||||
- 前端只调用 `/api/*`,不保存密钥、token 或业务缓存文件。
|
||||
@@ -0,0 +1,80 @@
|
||||
# 编码规则(Coding Rules)
|
||||
|
||||
> 每次写代码前先读完本文件。这是让 AI 不跑偏、代码质量稳定的硬约束。
|
||||
|
||||
## 0. 黄金法则
|
||||
|
||||
1. 不臆造:钉钉字段、接口、依赖、文件,不确定就查证或询问。
|
||||
2. 守范围:只做当前任务要求的事,不顺手加 V2 功能。
|
||||
3. 照架构:使用 Go + Gin + SQLite + 原生前端,不擅自换栈。
|
||||
4. 小步改:一次只解决一个任务,不夹带无关重构。
|
||||
5. 可验证:改完必须能构建、能测试、对得上验收标准。
|
||||
|
||||
## 1. 动手前
|
||||
|
||||
- 按链路确认:`vision` -> `requirements` -> `tech-stack` -> `architecture` -> `tasks`。
|
||||
- 找到本任务对应的验收标准,写之前就知道怎么算做对。
|
||||
- 先找现有函数、包、SQL、页面和测试,复用优先。
|
||||
- 如果需求含糊,或改动会偏离 Go + Gin / 原生前端约束,先问。
|
||||
|
||||
## 2. 事实来源纪律
|
||||
|
||||
- 钉钉接口以 `docs/api.md`、`docs/04-architecture.md` 和实际 OpenAPI 响应为准。
|
||||
- 新项目技术事实以 `docs/03-tech-stack.md` 为准。
|
||||
- API 形状以 `docs/api.md` 为准。
|
||||
- 数据结构变化必须同步更新 `docs/04-architecture.md`、`docs/api.md` 和相关任务。
|
||||
- 不从旧 JSON 文件中推断未确认的字段含义。
|
||||
|
||||
## 3. 范围纪律
|
||||
|
||||
- MVP 只做 `02-requirements.md` 中列为 P0 的功能。
|
||||
- V2 / V3 功能只记录,不实现。
|
||||
- 不实现登录、权限、定时同步、变更历史,除非任务明确要求。
|
||||
- 不为将来可能用到提前抽象。
|
||||
|
||||
## 4. 架构纪律
|
||||
|
||||
- 后端必须用 Gin。
|
||||
- 前端必须是原生 HTML/CSS/JavaScript。
|
||||
- Gin 负责托管前端文件和 `/api/*`。
|
||||
- 不引入 Vue、React、Element Plus、Vite、Webpack。
|
||||
- 不让浏览器直接调用钉钉 OpenAPI。
|
||||
- 不把 SQL、钉钉调用和 HTTP 处理混在同一个函数里。
|
||||
|
||||
## 5. 代码规范
|
||||
|
||||
- Go 标识符使用英文,包名短小清晰。
|
||||
- UI 文案和文档默认中文。
|
||||
- 错误必须处理,不吞错。
|
||||
- HTTP 错误统一返回 `{"error":{"code":"...","message":"..."}}`。
|
||||
- 注释解释为什么,不复述做了什么。
|
||||
- Go 代码提交前运行 `gofmt`。
|
||||
|
||||
## 6. 测试与验证
|
||||
|
||||
完成前至少检查:
|
||||
|
||||
- [ ] 构建通过。
|
||||
- [ ] 相关测试通过。
|
||||
- [ ] 对得上需求验收标准。
|
||||
- [ ] 没有夹带无关改动。
|
||||
- [ ] 涉及文档事实变化时,文档已同步。
|
||||
- [ ] 回复里如实说明跑了什么命令、结果如何。
|
||||
|
||||
目标命令:
|
||||
|
||||
```powershell
|
||||
go test ./...
|
||||
go build ./...
|
||||
```
|
||||
|
||||
## 7. 绝不
|
||||
|
||||
- 绝不把真实 app_key、app_secret、access_token、手机号样本写进代码或文档。
|
||||
- 绝不为了让测试通过而删除断言、降低验收标准。
|
||||
- 绝不擅自删除用户已有文件或重置工作区。
|
||||
- 绝不在没说明的情况下改公共接口、迁移数据结构或升级依赖。
|
||||
|
||||
## 8. 拿不准就问
|
||||
|
||||
问题要具体,说明卡在哪里、有哪些选项、倾向哪个选项以及原因。
|
||||
@@ -0,0 +1,76 @@
|
||||
# 任务看板(Tasks)
|
||||
|
||||
> 把 MVP 拆成小步、可独立交付的任务,让 AI 一步一步开发,避免一次生成整个项目。
|
||||
|
||||
## 使用规则
|
||||
|
||||
1. 一次只做一个任务:每轮只领取一个状态为 `TODO`、且依赖均已 `DONE` 的任务,取最靠前的那个。
|
||||
2. 做完即停:完成该任务、自测通过、把状态改成 `DONE` 后,停下来汇报。
|
||||
3. 不跳步:依赖未完成的任务不能开工。
|
||||
4. 完成定义:以 [编码规则](05-coding-rules.md) 的验证清单为准。
|
||||
5. 动手前先读 `00-ai-start-here.md`、`05-coding-rules.md` 和 `current-state.md`。
|
||||
|
||||
## 状态图例
|
||||
|
||||
`TODO` 待开始 · `DOING` 进行中(同一时间最多 1 个)· `DONE` 已完成并验收 · `BLOCKED` 受阻(注明原因)
|
||||
|
||||
---
|
||||
|
||||
## Phase 0 · 地基
|
||||
|
||||
| ID | 任务 | 依赖 | 验收要点 | 状态 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| T-001 | 初始化 Go + Gin 项目骨架 | - | `go run .` 启动;`/api/health` 返回正常;`/` 返回静态首页 | TODO |
|
||||
| T-002 | 建立配置、日志和目录结构 | T-001 | 目录符合 `04-architecture.md`;配置不含真实密钥;默认数据库路径可用 | TODO |
|
||||
| T-003 | 建立 SQLite 迁移和基础测试 | T-002 | 表结构与架构文档一致;`go test ./...` 可运行 | TODO |
|
||||
|
||||
## Phase 1 · 钉钉接口验证
|
||||
|
||||
| ID | 任务 | 依赖 | 验收要点 | 状态 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| T-101 | 实现站点 CRUD API | T-003 | 可新增、查询、更新、删除站点;列表不返回明文 secret | TODO |
|
||||
| T-102 | 实现钉钉 token client | T-101 | 用站点配置获取 token;错误响应可读;不记录 token 明文 | TODO |
|
||||
| T-103 | 实现部门和用户 API client | T-102 | 能封装拉子部门、部门 userid、用户详情三个调用 | TODO |
|
||||
|
||||
## Phase 2 · 同步与查询 API
|
||||
|
||||
| ID | 任务 | 依赖 | 验收要点 | 状态 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| T-201 | 实现全量同步服务 | T-103 | 从根部门拉部门树、用户详情并写入 SQLite;同步日志完整 | TODO |
|
||||
| T-202 | 实现部门查询 API | T-201 | `/api/sites/{id}/departments` 返回可组树的数据 | TODO |
|
||||
| T-203 | 实现人员查询 API | T-201 | 支持 keyword、dept_id、active、page、size | TODO |
|
||||
| T-204 | 实现导出 API | T-203 | 支持 JSON 和 CSV;导出结果服从筛选参数 | TODO |
|
||||
| T-205 | 实现统计和同步日志 API | T-201 | 首页可获得站点概览和最近同步结果 | TODO |
|
||||
|
||||
## Phase 3 · 原生前端
|
||||
|
||||
| ID | 任务 | 依赖 | 验收要点 | 状态 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| T-301 | 实现应用外壳和站点概览 | T-205 | `/` 展示站点、统计、同步状态和入口按钮 | TODO |
|
||||
| T-302 | 实现站点配置页面 | T-101 | 可维护站点;secret 输入后不在列表明文展示 | TODO |
|
||||
| T-303 | 实现部门浏览页面 | T-202, T-203 | 左侧部门树,右侧部门成员列表 | TODO |
|
||||
| T-304 | 实现人员搜索页面 | T-203, T-204 | 关键词、筛选、分页、导出可用 | TODO |
|
||||
| T-305 | 接入同步操作和状态反馈 | T-201, T-205, T-301 | 页面可触发同步并展示成功 / 失败 | TODO |
|
||||
|
||||
## Phase 4 · 收尾与发布
|
||||
|
||||
| ID | 任务 | 依赖 | 验收要点 | 状态 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| T-401 | 完整验收 MVP | T-305 | `02-requirements.md` 的 P0 验收全部通过 | TODO |
|
||||
| T-402 | 完善运行和打包文档 | T-401 | `AGENTS.md`、`CLAUDE.md` 和 `docs/current-state.md` 写清运行方式;无真实密钥进入仓库 | TODO |
|
||||
|
||||
## 里程碑
|
||||
|
||||
- M1:最小 Go + Gin + SQLite 地基完成。
|
||||
- M2:钉钉接口封装验证完成。
|
||||
- M3:同步、查询、导出 API 完成。
|
||||
- M4:原生前端 MVP 完成。
|
||||
- M5:可交付 / 可运行。
|
||||
|
||||
## 待办池(Backlog)
|
||||
|
||||
- 定时同步。
|
||||
- 登录和权限。
|
||||
- 旧 JSON 数据导入。
|
||||
- 人员 / 部门变更历史。
|
||||
- 密钥本地加密存储。
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
# API 合约
|
||||
|
||||
> 本文定义 Go + Gin 后端 API 的目标形状。实现前可细化,但不要在代码里另起一套不兼容接口。
|
||||
|
||||
## 通用约定
|
||||
|
||||
- 传输:HTTP JSON,同源 `/api/*`。
|
||||
- 鉴权:MVP 无账号。
|
||||
- 请求体和响应体编码:UTF-8 JSON。
|
||||
- 时间格式:ISO 8601 字符串;钉钉原始时间戳字段保留原值。
|
||||
- 分页参数:`page` 从 1 开始,`size` 默认 20,最大 200。
|
||||
|
||||
通用错误响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": {
|
||||
"code": "bad_request",
|
||||
"message": "请求参数不正确"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 健康检查
|
||||
|
||||
### `GET /api/health`
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true
|
||||
}
|
||||
```
|
||||
|
||||
## 站点
|
||||
|
||||
### `GET /api/sites`
|
||||
|
||||
返回站点列表。不得返回 `app_secret` 明文。
|
||||
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"code": "meizhou",
|
||||
"name": "梅州",
|
||||
"has_secret": true,
|
||||
"updated_at": "2026-06-22T21:00:00+08:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `POST /api/sites`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "meizhou",
|
||||
"name": "梅州",
|
||||
"app_key": "example",
|
||||
"app_secret": "example"
|
||||
}
|
||||
```
|
||||
|
||||
### `PUT /api/sites/{site_id}`
|
||||
|
||||
更新站点名称、app_key、app_secret。未提交的 secret 保持不变。
|
||||
|
||||
### `DELETE /api/sites/{site_id}`
|
||||
|
||||
删除站点及其 token、部门、人员、同步日志。
|
||||
|
||||
## 同步
|
||||
|
||||
### `POST /api/sites/{site_id}/sync/full`
|
||||
|
||||
触发指定站点全量同步。
|
||||
|
||||
成功响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"log_id": 10,
|
||||
"status": "success",
|
||||
"departments": 120,
|
||||
"users": 3500
|
||||
}
|
||||
```
|
||||
|
||||
失败时返回 4xx / 5xx,并写入同步日志。
|
||||
|
||||
### `POST /api/sites/{site_id}/sync/token`
|
||||
|
||||
手动刷新 token。响应不返回 token 明文。
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"expires_at": "2026-06-22T23:00:00+08:00"
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /api/sync/logs`
|
||||
|
||||
查询同步日志。参数:`site_id`、`status`、`page`、`size`。
|
||||
|
||||
## 部门
|
||||
|
||||
### `GET /api/sites/{site_id}/departments`
|
||||
|
||||
返回平铺部门列表,前端组装树。
|
||||
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"dept_id": 1,
|
||||
"parent_id": 0,
|
||||
"name": "总部"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 人员
|
||||
|
||||
### `GET /api/sites/{site_id}/users`
|
||||
|
||||
参数:
|
||||
|
||||
- `keyword`:匹配姓名、手机号、工号。
|
||||
- `dept_id`:按主部门筛选。
|
||||
- `active`:`1` 或 `0`。
|
||||
- `page`:页码。
|
||||
- `size`:每页数量。
|
||||
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"userid": "u001",
|
||||
"name": "张三",
|
||||
"mobile": "138****0000",
|
||||
"title": "工程师",
|
||||
"job_number": "A001",
|
||||
"dept_id": 1,
|
||||
"dept_name": "研发部",
|
||||
"active": 1
|
||||
}
|
||||
],
|
||||
"page": 1,
|
||||
"size": 20,
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /api/sites/{site_id}/users/{userid}`
|
||||
|
||||
返回单个人员详情。默认不脱敏;如后续增加权限,再调整。
|
||||
|
||||
## 导出
|
||||
|
||||
### `GET /api/sites/{site_id}/export/users`
|
||||
|
||||
参数:
|
||||
|
||||
- `format`:`json` 或 `csv`。
|
||||
- 其余筛选参数同 `GET /users`。
|
||||
|
||||
响应:
|
||||
|
||||
- `format=json`:`application/json; charset=utf-8`
|
||||
- `format=csv`:`text/csv; charset=utf-8`
|
||||
|
||||
## 统计
|
||||
|
||||
### `GET /api/stats`
|
||||
|
||||
```json
|
||||
{
|
||||
"sites": [
|
||||
{
|
||||
"site_id": 1,
|
||||
"site_name": "梅州",
|
||||
"department_count": 120,
|
||||
"user_count": 3500,
|
||||
"last_sync_at": "2026-06-22T21:00:00+08:00",
|
||||
"last_sync_status": "success"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 待实现时确认
|
||||
|
||||
- 手机号列表页是否默认脱敏。
|
||||
- CSV 字段顺序。
|
||||
- 同步是否需要防并发锁。
|
||||
- 删除站点前是否需要二次确认。
|
||||
@@ -0,0 +1,67 @@
|
||||
# 当前实现状态
|
||||
|
||||
> 本文记录代码与任务看板的现实状态,帮助 AI coding agent 避免只看计划而忽略仓库现状。
|
||||
|
||||
## 当前快照
|
||||
|
||||
- 日期:2026-06-22
|
||||
- 阶段:MVP 起步
|
||||
- 技术栈:目标为 Go + Gin + SQLite + 原生 HTML/CSS/JavaScript
|
||||
- 生产代码:尚未初始化
|
||||
- 测试:尚无
|
||||
- 数据:旧 JSON 数据未进入当前仓库;项目事实以 `docs/` 为准
|
||||
|
||||
## 当前目录要点
|
||||
|
||||
| 路径 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `docs/` | 已有 | 当前项目规范化文档 |
|
||||
| `main.go` | 待建 | Go 服务入口 |
|
||||
| `internal/` | 待建 | 后端模块 |
|
||||
| `web/` | 待建 | 原生前端静态文件 |
|
||||
| `data/` | 待建 | SQLite 运行时数据目录 |
|
||||
|
||||
## 任务看板状态
|
||||
|
||||
以 [`06-tasks.md`](06-tasks.md) 为准。
|
||||
|
||||
- 已完成:文档初始化。
|
||||
- 正在进行:无。
|
||||
- 下一个可领取任务:T-001 初始化 Go + Gin 项目骨架。
|
||||
|
||||
## 当前可运行内容
|
||||
|
||||
当前尚无可运行应用代码。
|
||||
|
||||
目标命令:
|
||||
|
||||
```powershell
|
||||
# 本地开发
|
||||
go run .
|
||||
|
||||
# 测试
|
||||
go test ./...
|
||||
|
||||
# 构建
|
||||
go build ./...
|
||||
```
|
||||
|
||||
## 开始编码前检查
|
||||
|
||||
开始任意任务前:
|
||||
|
||||
1. 读仓库级 agent 规则文件 `AGENTS.md`。
|
||||
2. 读 `docs/00-ai-start-here.md`。
|
||||
3. 读 `docs/05-coding-rules.md`。
|
||||
4. 在 `docs/06-tasks.md` 取第一个 `TODO` 且依赖均 `DONE` 的任务。
|
||||
5. 将该任务状态改为 `DOING`。
|
||||
|
||||
## 维护规则
|
||||
|
||||
当实际代码状态发生变化时,同步更新本文件:
|
||||
|
||||
- 新增或移动入口文件。
|
||||
- 初始化框架或模块。
|
||||
- 任务从 `TODO` 进入 `DOING` 或 `DONE`。
|
||||
- 新增可运行命令。
|
||||
- 发现文档和代码现实不一致。
|
||||
@@ -0,0 +1,86 @@
|
||||
# 路由与页面结构
|
||||
|
||||
> 本文约定原生前端页面路由、页面职责和组件归属。
|
||||
|
||||
## 页面路由
|
||||
|
||||
MVP 不使用前端路由框架。Gin 对以下路径都返回同一个 `web/index.html`,页面 JS 根据 `location.pathname` 渲染对应视图。
|
||||
|
||||
| 路由 | 页面 | MVP 说明 |
|
||||
| --- | --- | --- |
|
||||
| `/` | 仪表盘 | 展示站点概览、同步状态和快速入口 |
|
||||
| `/sites` | 站点配置 | 管理站点 app_key / app_secret |
|
||||
| `/departments` | 部门浏览 | 站点切换、部门树、部门成员 |
|
||||
| `/users` | 人员搜索 | 搜索筛选、分页表格、导出 |
|
||||
| `/logs` | 同步日志 | 查看同步记录和错误信息 |
|
||||
|
||||
## 页面职责
|
||||
|
||||
### 仪表盘
|
||||
|
||||
- 展示每个站点的部门数、人员数、最后同步时间和状态。
|
||||
- 提供同步按钮。
|
||||
- 提供进入部门浏览、人员搜索、站点配置的入口。
|
||||
|
||||
### 站点配置
|
||||
|
||||
- 展示站点列表。
|
||||
- 新增、编辑、删除站点。
|
||||
- app_secret 输入后保存,但列表不明文展示。
|
||||
|
||||
### 部门浏览
|
||||
|
||||
- 左侧展示部门树。
|
||||
- 右侧展示当前部门下人员。
|
||||
- 支持站点切换。
|
||||
- 空部门、加载失败、未同步状态需要有明确提示。
|
||||
|
||||
### 人员搜索
|
||||
|
||||
- 支持站点切换。
|
||||
- 支持关键词、部门、状态筛选。
|
||||
- 支持分页。
|
||||
- 支持导出当前筛选结果。
|
||||
|
||||
### 同步日志
|
||||
|
||||
- 按站点和状态筛选日志。
|
||||
- 展示开始时间、结束时间、类型、状态、错误信息。
|
||||
|
||||
## 前端文件建议
|
||||
|
||||
```text
|
||||
web/
|
||||
├── index.html
|
||||
└── assets/
|
||||
├── style.css
|
||||
├── app.js
|
||||
├── api.js
|
||||
├── state.js
|
||||
├── dashboard.js
|
||||
├── sites.js
|
||||
├── departments.js
|
||||
├── users.js
|
||||
└── logs.js
|
||||
```
|
||||
|
||||
## 组件建议
|
||||
|
||||
这里的组件是 JS 函数或小模块,不是框架组件。
|
||||
|
||||
| 模块 | 归属 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `renderShell` | 全局 | 页面框架、导航、站点选择入口 |
|
||||
| `apiFetch` | 全局 | 封装 fetch、JSON 解析和错误展示 |
|
||||
| `renderDashboard` | 仪表盘 | 渲染站点统计和同步按钮 |
|
||||
| `renderSiteForm` | 站点配置 | 新增 / 编辑站点 |
|
||||
| `renderDeptTree` | 部门浏览 | 将平铺部门列表组装为树 |
|
||||
| `renderUserTable` | 部门 / 人员页 | 渲染分页人员表格 |
|
||||
| `renderLogs` | 同步日志 | 渲染日志列表 |
|
||||
|
||||
## 导航规则
|
||||
|
||||
- 顶部导航固定展示:仪表盘、站点配置、部门浏览、人员搜索、同步日志。
|
||||
- 站点选择应尽量保留在 URL 查询参数中,例如 `?site_id=1`。
|
||||
- 人员页筛选条件应保留在 URL 查询参数中,方便刷新后恢复。
|
||||
- API 失败时在页面内展示错误,不静默失败。
|
||||
@@ -0,0 +1,132 @@
|
||||
# Dingding HRM 项目任务拆分
|
||||
|
||||
> 项目级任务总表。实际编码时仍按 `docs/00-ai-start-here.md` 和 `docs/06-tasks.md` 的规则:每轮只领取一个可执行任务,完成后更新状态与 `docs/current-state.md`。
|
||||
|
||||
## 状态说明
|
||||
|
||||
- `TODO`:待开始
|
||||
- `DOING`:进行中,同一时间最多一个
|
||||
- `DONE`:已完成并通过验证
|
||||
- `BLOCKED`:受阻,必须写明原因
|
||||
|
||||
## Phase 0 · 项目地基
|
||||
|
||||
| ID | 任务 | 依赖 | 交付物 | 验收标准 | 状态 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| T-001 | 初始化 Go module | - | `go.mod`、`go.sum` | `go test ./...` 可执行;模块名明确 | TODO |
|
||||
| T-002 | 接入 Gin 最小服务 | T-001 | `main.go`、基础 router | `go run .` 启动;`GET /api/health` 返回 `{"ok":true}` | TODO |
|
||||
| T-003 | 托管原生前端静态文件 | T-002 | `web/index.html`、`web/assets/style.css`、`web/assets/app.js` | 访问 `/` 返回首页;刷新 `/sites`、`/users` 不 404 | TODO |
|
||||
| T-004 | 建立项目目录结构 | T-002 | `internal/config`、`internal/db`、`internal/handler`、`internal/service` 等目录 | 目录符合 `docs/04-architecture.md` | TODO |
|
||||
| T-005 | 建立配置加载 | T-004 | 配置模块 | 支持默认端口、数据库路径;不包含真实密钥 | TODO |
|
||||
| T-006 | 建立统一错误响应 | T-004 | handler 错误工具 | API 错误格式符合 `docs/api.md` | TODO |
|
||||
|
||||
## Phase 1 · SQLite 数据层
|
||||
|
||||
| ID | 任务 | 依赖 | 交付物 | 验收标准 | 状态 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| T-101 | 接入 SQLite 驱动 | T-005 | DB 初始化代码 | 默认创建或打开 `data/dingding_hrm.db` | TODO |
|
||||
| T-102 | 实现数据库迁移 | T-101 | migration 代码 | 建表 SQL 覆盖 sites、access_tokens、departments、users、sync_logs | TODO |
|
||||
| T-103 | 实现站点 repository | T-102 | site repo | 支持增删改查;code 唯一约束生效 | TODO |
|
||||
| T-104 | 实现 token repository | T-102 | token repo | 支持保存最新 token、查询未过期 token | TODO |
|
||||
| T-105 | 实现部门 repository | T-102 | department repo | 支持按站点 upsert、清理、查询平铺列表 | TODO |
|
||||
| T-106 | 实现人员 repository | T-102 | user repo | 支持 upsert、关键词查询、部门筛选、分页计数 | TODO |
|
||||
| T-107 | 实现同步日志 repository | T-102 | sync log repo | 支持创建 running、更新 success/failed、分页查询 | TODO |
|
||||
| T-108 | 数据层测试 | T-103 至 T-107 | repository tests | `go test ./...` 通过;覆盖关键约束和分页 | TODO |
|
||||
|
||||
## Phase 2 · 站点与基础 API
|
||||
|
||||
| ID | 任务 | 依赖 | 交付物 | 验收标准 | 状态 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| T-201 | 实现站点列表 API | T-103 | `GET /api/sites` | 返回 items;不返回 `app_secret` 明文 | TODO |
|
||||
| T-202 | 实现新增站点 API | T-103 | `POST /api/sites` | 参数校验;新增后可查询 | TODO |
|
||||
| T-203 | 实现更新站点 API | T-103 | `PUT /api/sites/{site_id}` | 支持更新名称、key、secret;未提交 secret 时保持原值 | TODO |
|
||||
| T-204 | 实现删除站点 API | T-103 | `DELETE /api/sites/{site_id}` | 删除站点级联清理关联数据 | TODO |
|
||||
| T-205 | 站点 API 测试 | T-201 至 T-204 | handler tests | 覆盖成功、参数错误、重复 code、删除不存在 | TODO |
|
||||
|
||||
## Phase 3 · 钉钉 OpenAPI Client
|
||||
|
||||
| ID | 任务 | 依赖 | 交付物 | 验收标准 | 状态 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| T-301 | 定义钉钉 client 接口 | T-004 | `internal/dingtalk` 接口和类型 | 方法覆盖 token、子部门、部门 userid、用户详情 | TODO |
|
||||
| T-302 | 实现获取 access_token | T-301 | token HTTP 调用 | 支持 app_key/app_secret;错误信息可读 | TODO |
|
||||
| T-303 | 实现获取子部门列表 | T-302 | department HTTP 调用 | 支持传入 `dept_id`;解析钉钉错误码 | TODO |
|
||||
| T-304 | 实现获取部门 userid 列表 | T-302 | listid HTTP 调用 | 支持传入 `dept_id`;返回 userid 切片 | TODO |
|
||||
| T-305 | 实现获取用户详情 | T-302 | user detail HTTP 调用 | 返回核心字段和 raw JSON | TODO |
|
||||
| T-306 | 钉钉 client 单元测试 | T-302 至 T-305 | httptest tests | 使用 mock server 覆盖成功、钉钉错误、网络错误 | TODO |
|
||||
|
||||
## Phase 4 · 同步服务
|
||||
|
||||
| ID | 任务 | 依赖 | 交付物 | 验收标准 | 状态 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| T-401 | 实现 token 按需获取服务 | T-104, T-302 | token service | 未过期复用;过期刷新;不向 API 返回 token 明文 | TODO |
|
||||
| T-402 | 实现部门 BFS 同步 | T-105, T-303, T-401 | department sync | 从 `dept_id=1` 拉完整部门树;支持空子部门 | TODO |
|
||||
| T-403 | 实现用户详情同步 | T-106, T-304, T-305, T-401 | user sync | 遍历部门 userid 并 upsert 用户详情 | TODO |
|
||||
| T-404 | 实现全量同步事务边界 | T-402, T-403, T-107 | full sync service | 记录 running/success/failed 日志;失败可定位阶段 | TODO |
|
||||
| T-405 | 实现同步防并发 | T-404 | sync lock | 同一站点并发同步被拒绝或排队,行为明确 | TODO |
|
||||
| T-406 | 同步服务测试 | T-404 | service tests | mock 钉钉 client,覆盖成功、失败、部分空数据 | TODO |
|
||||
|
||||
## Phase 5 · 查询、导出与统计 API
|
||||
|
||||
| ID | 任务 | 依赖 | 交付物 | 验收标准 | 状态 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| T-501 | 实现手动刷新 token API | T-401 | `POST /api/sites/{site_id}/sync/token` | 返回状态和过期时间;不返回 token | TODO |
|
||||
| T-502 | 实现全量同步 API | T-404 | `POST /api/sites/{site_id}/sync/full` | 成功返回部门数、人员数、log_id | TODO |
|
||||
| T-503 | 实现部门查询 API | T-105 | `GET /api/sites/{site_id}/departments` | 返回平铺部门列表 | TODO |
|
||||
| T-504 | 实现人员查询 API | T-106 | `GET /api/sites/{site_id}/users` | 支持 keyword、dept_id、active、page、size | TODO |
|
||||
| T-505 | 实现人员详情 API | T-106 | `GET /api/sites/{site_id}/users/{userid}` | 返回单人详情;不存在返回 404 | TODO |
|
||||
| T-506 | 实现 JSON 导出 | T-106 | export service/API | 导出结果服从筛选条件 | TODO |
|
||||
| T-507 | 实现 CSV 导出 | T-106 | export service/API | UTF-8 CSV,包含表头,Excel 可打开 | TODO |
|
||||
| T-508 | 实现统计 API | T-105, T-106, T-107 | `GET /api/stats` | 返回每站点部门数、人员数、最近同步状态 | TODO |
|
||||
| T-509 | 实现同步日志 API | T-107 | `GET /api/sync/logs` | 支持 site_id、status、page、size | TODO |
|
||||
| T-510 | 查询与导出 API 测试 | T-503 至 T-509 | handler tests | 覆盖分页、筛选、空结果、导出 content-type | TODO |
|
||||
|
||||
## Phase 6 · 原生前端基础
|
||||
|
||||
| ID | 任务 | 依赖 | 交付物 | 验收标准 | 状态 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| T-601 | 实现页面外壳 | T-003 | `web/index.html`、导航、布局 CSS | `/`、`/sites`、`/departments`、`/users`、`/logs` 可刷新访问 | TODO |
|
||||
| T-602 | 实现前端 API 封装 | T-601 | `web/assets/api.js` | 统一处理 JSON、错误提示、下载响应 | TODO |
|
||||
| T-603 | 实现前端状态和 URL 参数工具 | T-601 | `state.js` 或等价模块 | site_id、筛选参数可从 URL 恢复 | TODO |
|
||||
| T-604 | 建立前端基础样式 | T-601 | `style.css` | 页面清晰、表格和表单可用、移动端不严重错位 | TODO |
|
||||
|
||||
## Phase 7 · 原生前端功能页
|
||||
|
||||
| ID | 任务 | 依赖 | 交付物 | 验收标准 | 状态 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| T-701 | 实现仪表盘 | T-508, T-602 | dashboard view | 展示站点统计、最近同步状态、同步入口 | TODO |
|
||||
| T-702 | 实现站点配置页 | T-201 至 T-204, T-602 | sites view | 可新增、编辑、删除站点;secret 不明文展示 | TODO |
|
||||
| T-703 | 实现部门浏览页 | T-503, T-504, T-603 | departments view | 左侧部门树,右侧部门成员列表 | TODO |
|
||||
| T-704 | 实现人员搜索页 | T-504, T-506, T-507, T-603 | users view | 支持关键词、部门、状态、分页、导出 | TODO |
|
||||
| T-705 | 实现同步日志页 | T-509, T-602 | logs view | 支持按站点和状态筛选日志 | TODO |
|
||||
| T-706 | 接入同步按钮和反馈 | T-502, T-701 | sync UI | 展示同步中、成功、失败状态;失败信息可读 | TODO |
|
||||
|
||||
## Phase 8 · 集成验证与边界处理
|
||||
|
||||
| ID | 任务 | 依赖 | 交付物 | 验收标准 | 状态 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| T-801 | 完整 API 合约核对 | T-510 | API 对照记录 | 实现路径、参数、响应与 `docs/api.md` 一致 | TODO |
|
||||
| T-802 | 完整页面路由核对 | T-706 | 路由对照记录 | 实现页面与 `docs/routes.md` 一致 | TODO |
|
||||
| T-803 | 密钥和敏感信息检查 | T-706 | 检查记录 | 代码、日志、页面列表不泄露 secret/token | TODO |
|
||||
| T-804 | 空数据和错误状态验收 | T-706 | UI/API 边界处理 | 未配置站点、未同步、钉钉失败都有明确提示 | TODO |
|
||||
| T-805 | Windows 本地运行验收 | T-706 | 验收记录 | PowerShell 下可 `go run .`、访问页面、运行测试 | TODO |
|
||||
| T-806 | 文档同步更新 | T-801 至 T-805 | 更新后的 docs | `docs/current-state.md`、`docs/06-tasks.md` 与代码现实一致 | TODO |
|
||||
|
||||
## Phase 9 · 打包与交付
|
||||
|
||||
| ID | 任务 | 依赖 | 交付物 | 验收标准 | 状态 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| T-901 | 实现生产构建方式 | T-805 | build 命令或脚本 | 可生成 Windows 可执行文件 | TODO |
|
||||
| T-902 | 确认静态文件打包策略 | T-901 | 嵌入或随包分发方案 | 新目录运行时能访问 `/` 和 `/api/health` | TODO |
|
||||
| T-903 | 完成交付说明 | T-902 | 更新 `AGENTS.md`、`CLAUDE.md`、`docs/current-state.md` | 新 agent 可快速找到运行、测试、构建方式 | TODO |
|
||||
| T-904 | MVP 最终验收 | T-903 | 验收记录 | `docs/02-requirements.md` P0 全部通过 | TODO |
|
||||
|
||||
## Backlog · 后续迭代
|
||||
|
||||
| ID | 任务 | 说明 | 状态 |
|
||||
| --- | --- | --- | --- |
|
||||
| B-001 | 定时同步 | 按站点配置周期自动同步 | TODO |
|
||||
| B-002 | 登录和权限 | 管理员登录、查询用户权限区分 | TODO |
|
||||
| B-003 | 旧 JSON 数据导入 | 从旧脚本导出的 JSON 初始化 SQLite | TODO |
|
||||
| B-004 | 部门和人员变更历史 | 记录字段变化、支持对比 | TODO |
|
||||
| B-005 | 密钥本地加密 | 使用本机安全存储或加密文件降低泄露风险 | TODO |
|
||||
| B-006 | 操作审计 | 记录站点配置修改、同步触发、导出操作 | TODO |
|
||||
Reference in New Issue
Block a user