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

117 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 开发环境(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. 起基础设施
```bash
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. 后端
```bash
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
```
自检:
```bash
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. 前端
```bash
cd web
npm install
npm run dev # http://127.0.0.1:5180,/api 代理到 8100
npm run build # 产物必须在仓库 HEAD 上构建,禁止本地构建后上传
```
## 6. 测试
```bash
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` 后用**后台作业**前台跑:
```powershell
.\.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。