AAEasy 是一个 Cloudflare-native 的多人分账 PWA。前端、API、关系数据、实时协作与 PDF 导出均运行在 Cloudflare 平台上。
flowchart LR
Browser["React SPA / PWA"] -->|"HTTPS + JSON"| Worker["Hono Worker"]
Browser <-->|"WebSocket"| Worker
Worker -->|"Drizzle D1 binding"| D1["Cloudflare D1"]
Worker -->|"事件发布"| DO["Durable Objects"]
Worker -->|"HTML + CSS"| BrowserRun["Cloudflare Browser Run"]
Browser -->|"OIDC + PKCE"| Auth["Pangda Auth / KeyForge"]
AI["MCP-compatible AI"] -->|"Streamable HTTP + OAuth"| Worker
AI -->|"Authorization code + PKCE"| Auth
Worker -->|"Token introspection"| Auth
| 层 | 实现 |
|---|---|
| 前端 | Vite、React 19、React Router、TanStack Query、Tailwind CSS |
| API | Cloudflare Worker + Hono |
| 数据 | Cloudflare D1(SQLite)+ Drizzle ORM |
| 实时 | Durable Objects + WebSocket Hibernation |
| 登录 | Pangda Auth OIDC authorization code + PKCE |
| 导出 | CSV + Cloudflare Browser Run PDF |
| AI 记账 | MCP Streamable HTTP;复用账本权限、校验、审计与实时事件 |
| 测试 | Vitest、TypeScript、ESLint、Wrangler dry-run |
金额在 D1 中以十进制 TEXT 保存,并在 Drizzle 边界映射为 bigint,避免 D1 JavaScript 数字的精度损失。多语句写入使用 D1 batch();费用乐观锁额外使用内部 mutation token,防止陈旧请求改写分摊或审计记录。
需要 Node.js 22.12+ 和 pnpm 10+,不再需要 Docker 或本地 PostgreSQL。
pnpm install
cp .dev.vars.example .dev.vars
pnpm auth:setup
pnpm devpnpm dev 会先把 migrations/ 应用到 Wrangler 的本地 D1,再由 Cloudflare Vite plugin 同时提供 SPA 与 Worker。打开 http://localhost:5173。
本地登录默认使用 http://localhost:17001 的 KeyForge。pnpm auth:setup 会创建或修复 aaeasy client,并把一次性 client secret 写入 .dev.vars。
把 https://<你的域名>/mcp 配置给支持 MCP OAuth 的客户端;客户端会自动通过 KeyForge 登录、同意并获取绑定到该 resource 的 token。AAEasy 不再创建或保存独立 MCP Token。服务提供账本列表、账本上下文和费用创建工具;AI 写入仍受 KeyForge scope 以及现有角色、成员绑定、归档状态、金额/分摊校验与审计约束。详细配置见 MCP AI 记账文档。
pnpm db:migrate:local # 应用到本地 D1
pnpm db:migrations:list # 查看本地迁移状态
pnpm db:generate # schema 变化后生成迁移
pnpm db:migrate:remote # 应用到生产 D1初始 schema 位于 migrations/0000_military_jack_murdock.sql;0001_d1_write_guards.sql 增加两个重要保护:归档账本前校验结算快照完整性,以及禁止向已归档账本写入费用。
从旧 PostgreSQL 搬迁已有业务数据:
DIRECT_DATABASE_URL="$AAEASY_SOURCE_POSTGRES_URL" \
AAEASY_USER_IDENTITY_MAP_FILE="$AAEASY_IDENTITY_MAP" \
pnpm exec tsx scripts/export-postgres-to-d1.ts > "$AAEASY_EXPORT_SQL"
pnpm exec wrangler d1 execute aaeasy-production \
--remote --env production --file "$AAEASY_EXPORT_SQL"导出脚本只用于一次性切换,默认不导出旧登录和分享 session,并要求提供经过验证的 Neon → KeyForge 身份映射。导出的 SQL 和身份映射包含用户数据,必须放在安全的临时位置并在导入后删除。Cloudflare 不支持直接导入 PostgreSQL dump,因此脚本会转换身份引用、时间戳、JSON、数组、布尔值和内部 mutation token。正式操作见 PostgreSQL → D1 数据导入手册。
先创建 dev/production D1,分别把 Wrangler 返回的 ID 写入 wrangler.jsonc 顶层和 env.production.d1_databases:
pnpm exec wrangler d1 create aaeasy-dev
pnpm exec wrangler d1 create aaeasy-production
pnpm db:migrate:remote
pnpm run deploy生产部署还需要配置 OIDC secrets、Browser Run、Durable Objects 和自定义域名。完整步骤见 Cloudflare 部署手册。
pnpm dev # 本地 D1 + Worker + SPA
pnpm dev:pdf # 使用远程 Browser Run 测试 PDF(消耗账户配额)
pnpm build # 使用 production Cloudflare environment 构建
pnpm typecheck # SPA、共享包和 Worker 类型检查
pnpm lint # ESLint
pnpm test # Vitest
pnpm check # 全量质量检查
pnpm cf:typegen # 重新生成 Cloudflare binding 类型src/ React SPA、页面、组件和客户端 action wrappers
worker/src/ Hono API、Durable Objects、PDF、认证
packages/contracts/ API schema 与 DTO
packages/core/ 金额、分摊、账本与清算纯函数
packages/db/ D1/SQLite Drizzle schema 与 binding client
migrations/ Wrangler D1 migrations
scripts/ 配置检查、数据导出、本地登录初始化
docs/ 架构与部署手册
- 所有写请求经过 CSRF origin 校验和服务端权限校验。
- MCP token 由 KeyForge 签发并在线 introspect,严格绑定
https://aaeasy.pangda.app/mcpaudience;AAEasy 不保存 token,且不提供 Super Admin 旁路。 - OIDC token 使用服务端 AES-GCM 加密后保存;应用不接收密码或 Passkey。
- 分享解锁、用户搜索和 PDF 导出由 Durable Object 限流。
- 分享访客不能导出完整账本;只读分享不能写费用。
- 费用写入使用
version乐观锁,账本事件使用单调revision修复断线缺口。 - 成员、角色、分享、邀请、费用与结算写入都会记录
audit_logs。