Files
DadaoTask/2.Design/ROADMAP-M0-M1.md
T
Steven 0c53aa7062 feat(m0): 后端骨架 + Web/安卓前端骨架 + 设计文档
- backend: FastAPI 应用工厂、统一错误信封、JWT、短信登录、工作区/成员/邀请、幂等中间件
- alembic 0001: workspace/member/invitation/audit_log/app_user + RLS 策略 + 双角色 GRANT
- tests: 认证/工作区/租户隔离/幂等 四组用例(尚未在本机执行)
- web: React18+Vite 骨架(登录、工作区、邀请落地页)
- android: Compose 骨架(登录、工作区列表)
- 2.Design: PRODUCT-PLAN / ROADMAP-M0-M1 / NAMING / DEVELOPMENT
2026-10-28 02:38:53 +08:00

8.1 KiB
Raw Blame History

M0–M1 实施清单

来源:2.Design/PRODUCT-PLAN.md v1.0 第 12 节 粒度:每项 0.3–1.5 人日,2 人并行 ≈ 2 周一个里程碑 状态标记:[ ] 未开始 [~] 进行中 [x] 完成


M0 · 骨架(第 1–2 周,10 人日)

里程碑目标:一个能注册、能建团队、能证明"两个租户互相看不见"的空壳,部署在服务器上,CI 全绿。

0.1 仓库与约定(0.5d)

  • 目录结构:backend/ web/ android/ deploy/ 2.Design/
  • AGENTS.md:提交纪律(改完必 push)、前端产物只能由 HEAD 构建、文档落点
  • .gitignore / .editorconfig / README.md
  • 分支策略:main 受保护,功能走 feat/*;提交信息 feat(module): 中文描述
  • 验收:Gitea 上能看到仓库,PR 模板可用

0.2 本地环境(1d)

  • deploy/docker-compose.dev.yml:postgres:16(含 pgvector)+ redis:7 + minio
  • postgres 初始化脚本:CREATE EXTENSION vector, pg_trgm, pgcrypto
  • .env.example 全量注释
  • 验收:docker compose up -d 后 psql 能连、扩展已装

0.3 配置与日志(0.5d)

  • pydantic-settings 分层配置(dev/prod),启动即校验必填项
  • 结构化日志(JSON)+ request_id 贯穿 + 敏感字段脱敏中间件(api_key/token/password)
  • 验收:一个请求在日志里能用 request_id 串起来,密钥不会出现在日志里

0.4 数据库基座(1d)

  • alembic init,autogenerate 接入,env.py 读应用配置
  • 基础表迁移:workspace user member invitation audit_log
  • 通用列约定:id uuid、created_at、updated_at、version、deleted_at
  • 验收:空库 alembic upgrade head 一次成功;downgrade 可回滚

0.5 租户上下文 + RLS(1.5d)★ 核心

  • 请求依赖:解析 JWT → 校验成员身份 → SET LOCAL app.ws_id
  • 全部租户表启用 RLS,策略 workspace_id = current_setting('app.ws_id')::uuid
  • 仓储基类强制 ws_id 为必填构造参数(不给默认值)
  • 测试:租户 A 的 token 读租户 B 的资源 → 0 行 / 403
  • 验收:pytest -k tenant_isolation 全绿;故意删掉一条 where 条件时测试必须变红(用变异测试验证一次)

0.6 认证(1.5d)

  • 手机号 + 验证码注册/登录(开发环境固定码 123456,短信通道留接口)
  • 邮箱 + 密码(argon2)作为备选
  • JWT:access 15min / refresh 30d 轮换,refresh 落库可撤销
  • 登录限流(IP + 账号维度)
  • 验收:注册 → 登录 → 刷新 → 登出 全链路可用;错误码清晰(不是 500)

0.7 权限守卫(0.5d)

  • PERMISSIONS 字典:(资源, 动作) → 最低角色,FastAPI 依赖注入统一执行
  • 四个角色:owner / admin / member / guest
  • 验收:guest 调管理接口 403;member 调 admin 接口 403

0.8 接口规范(0.5d)

  • 统一响应体 {code, message, data, request_id}
  • 错误码表(2.Design/API.md 里维护)
  • 写接口支持 Idempotency-Key(Redis 落 24h)
  • 分页规范:cursor 优先,limit 上限 100

0.9 健康与版本(0.3d)

  • /health(DB/Redis 探活)、/version(返回 commit + 构建时间)
  • 验收:部署后 curl /version 与 git rev-parse --short HEAD 一致

0.10 CI(0.7d)

  • ruff + mypy(宽松起步)+ pytest
  • 迁移检查:alembic upgrade head 后再 alembic check 无差异
  • 镜像构建 + 推送到私有 registry(或直接在服务器构建)
  • 验收:坏代码推上去 CI 变红,前端产物不入库

0.11 部署(1d)

  • deploy/docker-compose.prod.yml + nginx 反代 + TLS
  • 端口分配登记到 2.Design/DEPLOY.md(避开 PosSync 的 5888 / 5176)
  • 备份脚本接入现有每日备份(pg_dump + 保留 14 天)
  • 验收:从零一台机器 30 分钟内起完;重启后数据在;备份可恢复到临时库

0.12 三端契约(0.5d)

  • 导出 openapi.json,生成 TS 客户端与 Kotlin 客户端
  • make sdk 一键重生成
  • 验收:改一个后端字段,两端编译报错(说明契约真的在生效)

0.13 客户端壳(1d)

  • Web:Vite 起项目、路由、登录页、空白任务页、请求封装(含 refresh 重试)
  • Android:Compose 工程、登录页、空列表页、Retrofit+OkHttp 封装
  • 验收:两端都能真实登录并拿到空列表

不阻塞 M0 交付,但必须在写 integration 表之前做完,否则接法选错要返工。详见 PRODUCT-PLAN.md §10.3。

  • 用 DSH 插件(@michengai/dsh-im-connect)实际扫码绑定一个微信号,观察 bot 身份归属
  • 用第二个微信号私聊该 bot,确认多用户共用一号时消息是否互不串
  • 压一下:连续 20 条消息的延迟与是否触发风控;断网 5 分钟后 syncBuf 能否续上
  • 记录 bot_token 失效表现(多久失效、失效后是报错还是静默)
  • 产出:2.Design/SPIKE-WECHAT-ILINK.md,明确回答"用户自带号"还是"平台统一号"
  • 验收:文档里三个问题都有实测结论,不是推测

M1 · 任务域(第 3–4 周,10 人日)

里程碑目标:自己开始每天用它记待办,连续 3 天不别扭。

1.1 数据(1d)

  • item item_assignee tag item_tag comment activity 迁移
  • 索引:(ws_id, status, due_at)、(ws_id, owner_id, status)、deleted_at 部分索引
  • 全文索引:zhparser 或 pg_bigm 建在 title + body_md

1.2 领域(1.5d)

  • 状态机 inbox→todo→doing→done(+ blocked/canceled),非法流转拒绝并给提示
  • 所有变更写 activity(含 changed_fields 增量)
  • version 乐观锁,冲突返回 409 带当前版本

1.3 API(1.5d)

  • 增删改查、批量状态变更、排序(手动 sort_order)
  • 视图查询:inbox / today / week / all,支持标签与关键词过滤
  • 搜索接口(标题 + 正文,返回高亮片段)

1.4 Web(3d)

  • 四视图 + 看板拖拽(列 = 状态)
  • 详情侧栏:优先级/截止/标签/备注/子任务(一层)/评论
  • 全局快速录入(Ctrl+K 或顶部输入框,支持 #标签 !优先级 @人 语法)
  • 键盘流:j/k 上下、Enter 完成、e 编辑

1.5 安卓(1.5d)

  • 列表 + 详情 + 勾选完成
  • 下拉刷新、只读缓存(Room,仅离线展示,改动必须联网)

1.6 通知与提醒(0.8d)

  • 站内通知表与未读角标
  • 每日摘要邮件(可关)

1.7 测试与验收(0.7d)

  • 每个接口一条 happy path + 一条越权用例
  • 前端关键交互 e2e(Playwright 起 3 条:登录、建任务、拖动状态)

M1 完成定义(DOD)

  • 连续 3 天所有待办都记在里面,没有回到微信/备忘录
  • 冷启动到"建完第一个任务"< 90 秒(新账号实测)
  • 1000 条任务下四视图首屏 < 300ms
  • 跨租户测试、越权测试全绿

关键验收用例(M0–M1 必须通过)

# 用例 期望
1 租户 A 用户请求租户 B 的 item id 404(不是 403,避免泄露存在性)
2 同一手机号注册两次 第二次提示已存在并引导登录
3 被移出团队的成员拿旧 token 请求 401,且 refresh 失效
4 并发两次提交同一任务的不同状态 一次成功,一次 409 并可重试
5 网络中断后重新提交 幂等键保证不产生两条
6 删除任务后全局搜索 搜不到,且回收站可恢复
7 停掉 Redis /health 变 503,业务接口给明确错误而非 500
8 部署后 /version commit 与仓库 HEAD 一致

下一步排期建议

第1周  0.1–0.7(另一个人并行做 0.13 客户端壳)
第2周  0.8–0.12(另一个人并行做 Web 登录与请求封装)
第3周  1.1–1.3 + 1.4 开工
第4周  1.4–1.7 + 自己开始 dogfooding