开发指南
本地环境搭建、测试、代码规范与常见坑点。
先安装以下工具。
| 工具 | 版本 | 用途 |
|---|---|---|
| Node.js | 22 及以上 | 构建工具链的运行时 |
| bun | 1.3 及以上 | workers/ 与 frontend/ 的包管理器(packageManager: bun@1.3.14) |
| wrangler | 4 及以上 | Cloudflare Workers 命令行工具,用于本地调试 API |
如果还没装 bun:
curl -fsSL https://bun.sh/install | bash项目统一使用 bun,不要混入 npm、pnpm 或 yarn 的锁文件。
搭建本地环境
Section titled “搭建本地环境”准备两个终端。第一个安装 API 依赖,第二个安装前端依赖:
cd workers && bun installcd ../frontend && bun install配置环境变量
Section titled “配置环境变量”复制示例文件,再改掉本地开发需要的值:
cp workers/.dev.vars.example workers/.dev.vars至少把 JWT_SECRET 和 ENCRYPTION_KEY 换成独立的值。文件里已带好 SMTP、Turnstile、初始管理员等配置的开发默认值。
应用数据库迁移
Section titled “应用数据库迁移”对本地 D1 数据库执行迁移:
cd workersbunx wrangler d1 migrations apply picumet-db --local该命令会按顺序应用 workers/migrations/ 下所有待执行的迁移。新迁移文件按 NNNN_description.sql 命名,保证执行顺序稳定。
启动 API
Section titled “启动 API”在 workers/ 目录启动 Workers API:
cd workers && bun run devAPI 监听在 http://localhost:8787。
在第二个终端进入 frontend/ 启动前端开发服务器:
cd frontend && bun run dev前端监听在 http://localhost:5173。Vite 会把 /api/* 和 /webdav/* 代理到 http://localhost:8787,本地不需要配置 CORS。
打开下面的地址:
- 前端:
http://localhost:5173 - API:
http://localhost:8787
首次启动时,workers/src/seed.ts 会创建默认管理员、演示用户、默认 R2 Provider 和根挂载点,并生成演示文件夹。种子只在 KV 键 seed:done 未设置时执行一次。
开发种子账号:
| 角色 | 用户名 | 密码 |
|---|---|---|
| 管理员 | admin | admin123456 |
| 演示用户 | demo | demo123456 |
开发密码可用 .dev.vars 里的 ADMIN_PASSWORD、DEMO_PASSWORD 覆盖。生产环境必须提供强 ADMIN_PASSWORD;没有它时,种子不会创建管理员,业务 API 会一直返回 503,直到初始化完成。
运行测试与类型检查
Section titled “运行测试与类型检查”以下命令都在各自包目录下执行。
| 任务 | 命令 | 目录 |
|---|---|---|
| 后端测试 | bun run test | workers/ |
| 后端类型检查 | bun run typecheck | workers/ |
| 前端测试 | bun run test | frontend/ |
| 前端覆盖率门禁 | bun run test:coverage | frontend/ |
| 前端类型检查 | bun run typecheck | frontend/ |
| 前端构建 | bun run build | frontend/ |
后端测试共 127 个用例,跑在内存版 node:sqlite 模拟的 D1/KV/R2 上(见 tests/helpers.ts),不依赖 workerd。前端有 7 个用例,外加覆盖率门禁,聚焦安全关键模块 src/lib/escape.ts 与 src/pages/Register.tsx(lines 80%、functions 60%、branches 40%)。
.github/workflows/ci.yml 在推送到 main 或发起 PR 时运行。workers job 执行安装、类型检查和测试;frontend job 在此基础上增加覆盖率门禁和生产构建。CI 只做质量门禁,不自动部署,发布统一手动执行 wrangler deploy。
按下面的约定写代码,保持前后一致。
- 文件:kebab-case
- React 组件:PascalCase
- 函数和变量:camelCase
- 常量:UPPER_SNAKE_CASE
- 类型和接口:PascalCase
外部库在前,其次是 Cloudflare 绑定,然后是项目内部模块,类型导入放最后。
TypeScript
Section titled “TypeScript”- 保持
strict开启。 - 尽量避免
any;确需使用时要加注释说明原因。 - 每个函数都要显式标注返回类型。
- 改过类型后,在两个包分别跑
bun run typecheck。
改动下面这些模块时,必须补上对应的测试。
权限判定算法
Section titled “权限判定算法”services/permissions/check.ts 里的权限判定按优先级依次检查:管理员特权、挂载边界、用户根路径、API 密钥权限范围、路径规则、所有者回退、默认拒绝。测试要锁死路径段边界:/users/alice 绝不能匹配 /users/alice2。规则优先级、通配符模式和默认拒绝也要有用例。
上传会话按 pending → uploading → verifying → completed 流转,终态包括 failed、expired、aborted。分片上传还会经过 parts_uploaded 和 completing。要覆盖断点续传、中止,以及按分片覆盖度和最终 HEAD 大小做完成校验的逻辑。
配额更新必须原子。测试并发上传不会突破限额,删除和中止路径恰好释放一次预留。用原子的 UPDATE,不要用「读取-修改-写回」的序列。
改过认证、上传或存储后,重跑安全回归套件:自由模式凭据处理、WebDAV 鉴权、SSRF 校验、加密、限流 fail-closed、一次性下载令牌消费。
使用 Conventional Commits:type(scope): subject。正文用多个 -m 参数,每个参数一条要点。
git commit -m "feat(upload): add multipart upload support for large files" \ -m "- 实现分片会话 API 与断点续传契约" \ -m "- 服务端记录分片 ETag 用于完成校验"git commit -m "fix(permission): 修复规则匹配的路径边界绕过" \ -m "- 用 isPathWithinBoundary 替换 startsWith" \ -m "- 补充 /users/alice 与 /users/alice2 的边界测试"提交信息用英文或中文都可以。类型与 scope 的取值如下。
| 类型 | 含义 |
|---|---|
feat | 新功能 |
fix | 缺陷修复 |
docs | 仅文档改动 |
style | 格式化,行为不变 |
refactor | 重构,行为不变 |
perf | 性能优化 |
test | 测试增改 |
chore | 维护性改动 |
| Scope | 范围 |
|---|---|
auth | 认证与会话 |
permission | 权限算法与规则 |
storage | 存储 Provider |
upload | 上传与分片流程 |
download | 下载网关与令牌 |
ui | 前端组件与页面 |
api | API 路由与 schema |
db | 迁移与数据仓库 |
质量门禁清单
Section titled “质量门禁清单”提交前对照这份清单逐项检查。
- 功能在真实 UI 或 API 上端到端跑通。
- 边界条件和错误路径的行为与文档一致。
strict类型检查通过,没有未说明的any。- 命名和导入顺序符合上面的约定。
- 没有死代码、残留的调试输出或注释掉的代码块。
- 新行为有对应测试,且测试能在可复现的回归上失败。
- 两个包都通过
bun run test和bun run typecheck。
- 权限检查基于规范化后的路径。
- 对象存储密钥与凭据不落到客户端或日志。
- fail-closed 路径保持关闭:限流、自由模式、SSRF。
- 数据库写入用原子语句,配额不做读改写。
- 热点请求路径避免无谓的分配与拷贝。
- 新增或改动端点时,同步更新
docs/API.md。 - 规范或结构变化时,更新本文档与
docs/ARCHITECTURE.md。
用 isPathWithinBoundary,别用 startsWith
Section titled “用 isPathWithinBoundary,别用 startsWith”startsWith 按字符串前缀比较,/users/alice 能匹配到 /users/alice2。utils/path.ts 的 isPathWithinBoundary 按路径段比较,不会有这个问题。
先删元数据,再异步清理对象
Section titled “先删元数据,再异步清理对象”先在一个事务里删除数据库元数据,之后异步清理对象存储;清理失败的对象记入 orphan_objects,交给对账任务处理。先删对象再删元数据的话,元数据删除一旦失败,对象就丢了。
配额更新要原子
Section titled “配额更新要原子”不要「读取配额 → 修改 → 写回」,并发场景下会竞态。直接用一条 UPDATE user_quotas SET used_storage = used_storage + ? ...。
授权前先规范化路径
Section titled “授权前先规范化路径”权限检查前对每个入站路径调用 normalizePath,/users/../admin/secrets 会归一到 /admin/secrets,无法绕过规则。
改完代码重启 wrangler dev
Section titled “改完代码重启 wrangler dev”Workers API 的热重载不可靠。改了 workers/ 源码后重启进程;保险起见删掉 .wrangler 再重跑迁移,从干净状态起步。
代码库按依赖顺序分阶段构建,后一阶段依赖前一阶段,每阶段验收标准全部通过才算完成。
| 阶段 | 内容 | 依赖 |
|---|---|---|
| 0 | 环境搭建 | — |
| 1 | 认证系统 | 0 |
| 2 | 核心权限系统 | 1 |
| 3 | 对象存储连接(R2) | 2 |
| 4 | 基础文件管理 | 3 |
| 5 | 配额管理 | 4 |
| 6 | 移动与重命名 | 5 |
| 7 | 密码保护与分享 | 6 |
| 8 | API 密钥与 WebDAV | 7 |
| 9 | 高级 UI | 8 |
| 10 | 外观定制与国际化 | 9 |
| 11 | 管理员功能 | 10 |
| 12 | 安全加固 | 11 |
| 13 | 分片上传 | 12 |
| 14 | 扩展存储源(S3/Oracle) | 13 |
| 15 | 自由模式 | 14 |
| 16 | 测试与部署 | 15 |
这条顺序上的关键里程碑:
- M1(阶段 4):可用的文件管理系统
- M2(阶段 8):完整的 API 与分享能力
- M3(阶段 11):多用户生产系统
- M4(阶段 15):全功能版本
- M5(阶段 16):正式发布
后续规划新功能时,可以按这张表判断前置依赖。