Files
DadaoTask/2.Design/DEVELOPMENT.md
T
Steven b40ea77eec
CI / backend (push) Canceled after 0s
docs(m0): 用实测结果重写 M0 清单 + 补 PR 模板
- 0.1–0.9 全部标为完成,但不是"代码写完"就算完成:
  33 条测试全绿、ruff/format 通过、真机 uvicorn 冒烟(/health /version 登录 建工作区 列表 /auth/me)通过
  之后才敢打勾;没跑过的(downgrade、mypy、CI 在 Gitea 实跑、Web/Android 联调)保持未勾并写明原因。
- 记录 5 处"计划与实际不符"的偏差及理由:
  JWT 30min/14d、refresh 无状态不可撤销、权限用 ROLE_RANK 而非 PERMISSIONS 字典、
  app_user 故意不加 RLS(登录发生在租户绑定之前)、minio 与 pgvector 推迟到 M3。
- 新增「环境现状与阻塞」一节:Docker 起不来用便携 PG、外网 TLS 被拦走 HTTP 镜像、
  pip 必须 --no-cache-dir(否则写缓存卡死)、pg_ctl restricted token 报错、fnsvr-01 只有 8418/3306。
- 验收用例表加"现状"列,区分已验证 / 部分 / 未做。

顺带修:
- alembic downgrade 之前直接失败:workspace 的 RLS 策略引用了 member,
  不先 DROP POLICY 就 drop table,报 "cannot drop table member because other objects depend on it"。
  现已按策略先删后删表,downgrade base → upgrade head 全通。
- npm 依赖必须 --ignore-scripts 才能装(沙箱禁止 lifecycle 脚本派生进程),
  已写进 DEVELOPMENT.md;web 首次构建成功(tsc -b + vite,177KB/gzip 58KB)。

验收:pytest 33 passed / ruff 干净 / alembic 升降级往返通过 / web build 通过。
2026-10-28 03:28:06 +08:00

4.8 KiB
Raw Blame History

开发环境(M0)

目标:新人在 20 分钟内把后端跑起来并让 pytest 全绿。

1. 依赖

组件 版本 说明
Python 3.10+(CI 用 3.11) 后端
Node 20+ 前端
Docker Desktop 任意近期版本 只用来跑 Postgres / Redis

2. 端口约定(别改用默认端口)

服务 端口 为什么
PostgreSQL 5433 避开机器上可能已有的 5432
Redis 6380 同上
后端 API 8100 前端 dev 代理指向它
前端 dev 5180 与 CORS 默认值一致

3. 起基础设施

cd deploy
docker-compose -f docker-compose.dev.yml up -d     # 老版 CLI 是 docker-compose,新版是 docker compose

首次初始化会自动执行 deploy/postgres/init/01-roles.sql,创建两个角色:

  • dadao_owner —— 拥有库、可以建表,只有 alembic 用。
  • dadao_app —— 应用连接用,无 DDL、无 BYPASSRLS,行级安全对它生效。

为什么必须两个角色:PostgreSQL 的 RLS 会对表 owner 和 superuser 直接跳过。 如果应用用 owner 连库,多租户隔离就是摆设,而且测试会"假通过"。

4. 后端

cd backend
python -m venv .venv
.venv\Scripts\activate            # Linux/macOS: source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env              # Windows: copy .env.example .env

alembic upgrade head              # 建表 + RLS 策略(人工复核过再上)
uvicorn app.main:app --reload --port 8100

自检:

curl http://127.0.0.1:8100/health
curl http://127.0.0.1:8100/version     # commit 必须等于 git rev-parse --short HEAD

开发环境验证码固定为 SMS_DEV_CODE(默认 123456),且 /auth/sms/send 会把 dev_code 回显在响应里—— 只有 ENV=dev 才允许,ENV=prod 时启动即失败。

5. 前端

cd web
npm install
npm run dev          # http://127.0.0.1:5180,/api 代理到 8100
npm run build        # 产物必须在仓库 HEAD 上构建,禁止本地构建后上传

6. 测试

cd backend
pytest -q                          # 必须全绿才能提交
ruff check . && ruff format --check .

测试会真连数据库、真跑迁移、真走 HTTP 栈。跑之前确保 Postgres 在 5433。

隔离测试(tests/test_tenant_isolation.py)是本仓库最重要的一组用例,改动任何租户表都必须重跑它。

7. 常见坑

现象 原因 处理
pytest 报 attached to a different loop 连接池跨事件循环复用 测试环境已用 NullPool,别改回去
迁移报 permission denied for schema public 用的是应用角色 MIGRATION_DATABASE_URL 必须指向 owner
接口返回空列表而不是报错 忘了 bind_tenant,RLS 过滤掉了一切 走 MemberDep / TenantDep 依赖
pip 报 UnicodeDecodeError: 'gbk' codec requirements.txt 里有非 ASCII 该文件保持纯 ASCII
docker compose 报 unknown command 只装了 compose v1 用 docker-compose
Docker 起不来 Docker Desktop 未启动 / 需要管理员 先启动 Desktop,docker info 有输出再继续
迁移报 cannot insert multiple commands into a prepared statement asyncpg 走预备语句,一次只能一条 SQL 多语句 DDL 拆成每语句一次 op.execute()

本机特例(2026-10 实测,换机器可跳过)

这台开发机的 Docker Desktop 起不来,且外网 TLS 被拦,实际用的是:

  • 便携 PostgreSQL 16.4 放在 .local/pg(已在 .gitignore),initdb 后用后台作业前台跑:
    .\.local\pg\pgsql\bin\postgres.exe -D .\.local\pg\pgdata -p 5433 `
      -c listen_addresses=127.0.0.1 -c fsync=off -c synchronous_commit=off
    
    不要用 Start-Process:父进程一退出,子进程就被带走;pg_ctl 在本机会报 could not create restricted token: error code 87。
  • 装包只能走 HTTP 镜像:PyPI http://mirrors.aliyun.com/pypi/simple/, npm http://mirrors.huaweicloud.com/repository/npm/。
  • pip 必须加 --no-cache-dir:不加时写缓存会卡死(无输出、CPU 空转,实测 25 分钟无进展)。
  • 安装类命令一律写日志文件再 tail,不要用管道截断输出,否则看不到进度也不知道卡在哪。
  • npm install 要加 --ignore-scripts:沙箱不允许 npm 的 lifecycle 脚本派生进程(EPERM spawn)。

8. 提交前自检清单

  1. pytest 全绿,ruff 无告警。
  2. 新增租户表时:workspace_id NOT NULL + RLS 策略 + 跨租户测试,三者齐全。
  3. 迁移文件提交前人工复核(alembic revision --autogenerate 只做草稿)。
  4. 改了接口就更新 2.Design/API.md(M1 建立该文档)。
  5. 推送到远端,生产部署后 curl /version 校验 commit。