# code-questions **Repository Path**: dfkj-web/code-questions ## Basic Information - **Project Name**: code-questions - **Description**: No description available - **Primary Language**: TypeScript - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 8 - **Created**: 2026-08-25 - **Last Updated**: 2026-09-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 企业内部人员管理系统(People Management System) TypeScript 全栈项目:Hono 跨运行时后端 + React 前端,存储支持本地文件持久化与 PostgreSQL 两种实现。 --- ## 运行环境要求 | 运行环境 | 版本要求 | 说明 | | --- | --- | --- | | Node.js | `^18.0.0 \|\| ^20.0.0 \|\| >=22.0.0` | 由 Vite 6 决定,推荐 20 LTS 及以上 | | npm | >= 9 | 随 Node 安装 | | Bun | >= 1.0 | 可选,仅运行 Bun 入口时需要 | | Deno | >= 1.40 | 可选,仅运行 Deno 入口时需要 | | PostgreSQL | >= 13 | 可选,未配置 `DATABASE_URL` 时不需要数据库 | | Wrangler | >= 3 | 可选,仅部署 Cloudflare Workers 时需要 | --- ## 依赖版本 ### dependencies | 包 | 声明版本 | 实际锁定版本 | 用途 | | --- | --- | --- | --- | | `hono` | `^4.6.14` | 4.13.5 | 后端 Web 框架(WinterCG Fetch 标准) | | `drizzle-orm` | `^0.38.3` | 0.38.4 | ORM / 表结构定义 | | `postgres` | `^3.4.5` | 3.4.x | PostgreSQL 驱动(Node / Bun / Deno) | | `react` | `^18.3.1` | 18.3.1 | 前端框架 | | `react-dom` | `^18.3.1` | 18.3.1 | React DOM 渲染 | ### devDependencies | 包 | 声明版本 | 实际锁定版本 | 用途 | | --- | --- | --- | --- | | `typescript` | `^5.7.2` | 5.9.3 | 类型系统 | | `vite` | `^6.0.5` | 6.4.3 | 前端构建 / 开发服务器 | | `tsx` | `^4.19.2` | 4.23.12 | Node 侧 TypeScript 直接运行 | | `@hono/node-server` | `^1.13.7` | 1.13.x | Hono 的 Node 适配层 | | `@neondatabase/serverless` | `^0.10.4` | 0.10.x | Workers 环境的 PostgreSQL HTTP 驱动 | | `@vitejs/plugin-react` | `^4.3.4` | 4.3.x | Vite React 插件 | | `drizzle-kit` | `^0.30.1` | 0.30.x | 迁移生成与执行 | | `@types/react`、`@types/react-dom` | `^18.3.18`、`^18.3.5` | 18.3.x | React 类型声明 | 无 axios 等额外请求库,前端使用原生 `fetch`。 --- ## 快速开始 ```bash npm install npm run dev:node # 后端 API → http://localhost:3000 npm run dev:frontend # 另开终端:前端 → http://localhost:5173 ``` 未配置 `DATABASE_URL` 时自动使用本地文件持久化(`.data/store.json`),无需安装数据库,重启后数据保留。 --- ## 运行命令 | 命令 | 作用 | | --- | --- | | `npm run dev:node` | Node.js 启动后端(`tsx watch`,热重载) | | `npm run dev:bun` | Bun 启动后端(`--hot`) | | `npm run dev:deno` | Deno 启动后端(`--watch`) | | `npm run start:node` | Node.js 生产启动 | | `npm run start:bun` | Bun 生产启动 | | `npm run wrangler` | Cloudflare Workers 本地开发(`wrangler dev`) | | `npm run dev:frontend` | 前端开发服务器(Vite,`/api` 代理到 3000) | | `npm run build:frontend` | 前端生产构建 | | `npm run typecheck` | 全量类型检查(`tsc --noEmit`) | | `npm run seed` | 灌入内置初始数据 | | `npm run db:generate` | 由 schema 生成迁移文件 | | `npm run db:migrate` | 执行迁移 | | `npm run db:push` | schema 直接同步到数据库 | --- ## 环境变量 | 变量 | 必填 | 说明 | | --- | --- | --- | | `DATABASE_URL` | 否 | PostgreSQL 连接串。未配置时使用本地文件存储;配置后切换到 PostgreSQL | | `PORT` | 否 | 后端端口,默认 `3000` | Cloudflare Workers 部署时通过 `wrangler secret put DATABASE_URL` 注入。 --- ## 项目文件结构 ``` . ├── package.json # 依赖与脚本(含各运行时启动命令) ├── tsconfig.json # TypeScript 编译配置 ├── vite.config.ts # 前端构建配置 + /api 代理到后端 ├── drizzle.config.ts # Drizzle 迁移配置 ├── wrangler.toml # Cloudflare Workers 配置 ├── migrations/ │ └── 0000_init.sql # 初始表结构 SQL ├── src/ # 后端(领域类型与前端共享) │ ├── types.ts # Person / Tag 类型与 Repo 存储接口 │ ├── httpError.ts # HttpError(携带 HTTP 状态码的异常) │ ├── app.ts # Hono 路由与统一错误处理 │ ├── db/ │ │ ├── schema.ts # Drizzle 表定义 │ │ ├── mock.ts # 内置初始数据 │ │ ├── fileRepo.ts # 本地文件持久化实现(.data/store.json) │ │ ├── pgRepo.ts # PostgreSQL 实现 │ │ ├── index.ts # 数据库连接(多驱动切换) │ │ ├── repo.ts # 存储工厂(按 DATABASE_URL 选择实现) │ │ └── seed.ts # 种子脚本 │ └── server/ │ ├── node.ts # Node.js 入口 │ ├── bun.ts # Bun 入口 │ ├── deno.ts # Deno 入口 │ └── worker.ts # Cloudflare Workers 入口 └── frontend/ # 前端(React + Vite) ├── index.html └── src/ ├── main.tsx # 应用挂载入口 ├── App.tsx # 主界面:树形人员列表 / 标签筛选 / 汇报链 / 维护 ├── api.ts # 原生 fetch 封装 └── styles.css # 样式 ``` 运行时生成、未纳入版本管理的目录:`node_modules/`、`.data/`(文件存储数据)、`dist/`(前端构建产物)。 --- ## 分层结构 ``` 浏览器 (React + 原生 fetch) │ /api ▼ Hono (src/app.ts) —— 路由,仅依赖 Repo 接口 ▼ Repo 接口 (src/types.ts) ├─ FileRepo (.data/store.json) ← 未配置 DATABASE_URL └─ PgRepo (PostgreSQL / Drizzle) ← 配置 DATABASE_URL └─ Workers 环境自动切 Neon HTTP 驱动 ``` 后端业务代码与运行时无关,`src/server/` 下四个入口仅负责各运行时的启动适配。 --- ## 数据库表结构 ```mermaid erDiagram persons { VARCHAR id PK VARCHAR name VARCHAR title VARCHAR department VARCHAR employee_number VARCHAR email VARCHAR phone VARCHAR level VARCHAR manager_id "FK -> persons.id,null 表示顶级" TIMESTAMP synced_at } tags { VARCHAR id PK VARCHAR name UK "标签名唯一" } person_tags { VARCHAR person_id PK,FK VARCHAR tag_id PK,FK } persons ||--o{ persons : "manager_id 自引用" persons ||--o{ person_tags : "拥有" tags ||--o{ person_tags : "被关联" ``` - `persons.manager_id` 自引用同表 `id`,`null` 表示顶级人员。 - `tags.name` 唯一约束,标签为全局共享词表。 - `person_tags` 为多对多中间表,复合主键 `(person_id, tag_id)`,外键级联删除。 - 索引:`manager_id`、`person_id`、`tag_id`。 ### 建表 ```bash # 方式一:直接执行 SQL psql "$DATABASE_URL" -f migrations/0000_init.sql # 方式二:drizzle-kit export DATABASE_URL=postgres://user:pass@host:5432/db npm run db:migrate ``` 建表后执行 `npm run seed` 灌入初始数据(后端启动时也会自动 seed)。 --- ## API 所有接口前缀 `/api`,请求与响应均为 JSON。 | 方法 | 路径 | 说明 | | --- | --- | --- | | GET | `/api/persons?tag=技术` | 人员列表,可按标签名筛选(前端多选为 OR 语义) | | GET | `/api/persons/:id` | 单个人员详情(含标签) | | GET | `/api/persons/:id/chain` | 人员及其向上汇报链条 | | GET | `/api/tags` | 全部标签 | | PATCH | `/api/persons/:id/manager` | 设置上级,`body: { managerId: string \| null }`,`null` 置为顶级 | | POST | `/api/persons/:id/tags` | 追加标签,`body: { name: string }` | | DELETE | `/api/persons/:id/tags/:tagId` | 移除某人员的某标签 | | PATCH | `/api/tags/:id` | 重命名全局标签,`body: { name: string }` | 错误码:`400` 参数非法或设置上级会形成环、`404` 资源不存在、`409` 标签名重复。 --- ## 说明 - 人员基础信息无写接口,可维护字段为 `manager_id` 与标签。 - 设置上级时校验新上级的汇报链,禁止形成循环引用。 - `FileRepo` 面向单进程本地运行;多实例部署请配置 `DATABASE_URL` 使用 PostgreSQL。 - CORS 默认全开,按部署环境自行收窄。