- root deno.json workspace (nodeModulesDir auto), npm versions registered once in imports, deno.lock; remove pnpm-lock/pnpm-workspace/root package.json; members keep minimal package.json (name/type/exports) - tasks: dev, typecheck (tsc 7.0.2 per member + deno check), lint/fmt (biome, useImportExtensions), test (vitest via deno), check:tokens, build (web + deno compile), ci, db:migrate/reset, gen:types - tsconfig base moved to config/ (no root tsconfig.json); deno types -> types/deno.d.ts; web drops baseUrl - server: Deno.serve entry with graceful shutdown, --role migrate|preflight|probe, WEB_ROOT static SPA hosting; drop @hono/node-server, tsx, esbuild build.mjs - logger: redact child() bindings and serialize err by message/stack; sync stdout destination; tests - relative imports get explicit extensions (sites/mp-sync paths left for follow-up) - crash-recovery tests spawn `deno run -A`; tasks tests use unique per-file schemas - single-container Dockerfile + entrypoint (migrate -> preflight -> api+worker watchdog), docker-compose.yml - docs: README, runbook, ADR-001 superseded, plan §1 validation row Co-Authored-By: Claude Fable 5.1 <[email protected]>
79 lines
4.8 KiB
Markdown
79 lines
4.8 KiB
Markdown
# 开发环境运行手册
|
|
|
|
## 前置
|
|
|
|
- Deno 2.9.7(锁定;`curl -fsSL https://deno.land/install.sh | sh -s v2.9.7`)、Docker。不需要 Node.js / pnpm。
|
|
- 端口:web 5180、API 4380、PG 55433。本机 3000/5175/5176/55432 已被其他项目占用,不要改用。
|
|
|
|
## 首次启动
|
|
|
|
```sh
|
|
cp .env.example .env # 按需修改;server 与 db 脚本都读仓库根 .env
|
|
deno task db:up # 起 postgres:16-alpine(docker-compose.dev.yml,数据卷 umt-pg-data)
|
|
deno install # 按 deno.lock 装依赖到 node_modules(成员包软链到 node_modules/@umt/*)
|
|
deno task db:migrate # 执行 packages/db/migrations 下全部迁移
|
|
deno task dev # 同时起 server(4380)与 web(5180)
|
|
```
|
|
|
|
单独起:`deno task dev:server`(`deno run --watch`,默认 `--role all`,API + worker 同进程)、`deno task dev:web`。
|
|
|
|
## 验证
|
|
|
|
```sh
|
|
curl localhost:4380/api/v1/health
|
|
# 开发模式可用 .env 的 DEV_ADMIN_KEY 作 admin
|
|
curl -N -H "Authorization: Bearer umt-dev-admin-key" "localhost:4380/api/v1/events?after=0"
|
|
```
|
|
|
|
- OpenAPI:http://localhost:4380/api/openapi.json,文档页 http://localhost:4380/api/docs
|
|
- 控制台:http://localhost:5180,右上角钥匙按钮设置 API Key(存 localStorage `umt-api-key`)
|
|
|
|
## 常用命令
|
|
|
|
| 命令 | 作用 |
|
|
|---|---|
|
|
| `deno task ci` | typecheck(tsc 7.0.2 + deno check)→ lint(biome)→ test(vitest)→ check:tokens → build,提交前必须全绿 |
|
|
| `deno task typecheck` | `deno types` 生成 `types/deno.d.ts` 后,逐个成员跑 tsc 7.0.2,再跑 `deno check`(Deno 内置 TS 6.0.3) |
|
|
| `deno task lint` / `deno task fmt` | biome 检查 / 自动修复(含 import 排序;相对 import 必须带扩展名) |
|
|
| `deno task test` | 逐个成员跑 vitest(`deno run -A npm:vitest run`);单包:`cd packages/<x> && deno task test` |
|
|
| `deno task db:reset` | 清空 public schema 并重新迁移(生产环境拒绝执行) |
|
|
| `deno task gen:types` | 从已迁移的库反射生成 `packages/db/src/types.ts` |
|
|
| `deno task gen:tokens` | 改了 app.css 后重新生成 token 登记表 |
|
|
| `deno task build` | web 构建到 `apps/web/build/client` + server 编译为单文件 `dist/umt-server` |
|
|
| `cd apps/server && deno task start` | 以受限权限(net/env/sys/read)直接跑源码 |
|
|
|
|
依赖:npm 包版本只在根 `deno.json` 的 `imports` 里登记(web 的前端依赖仍在 `apps/web/package.json`)。改完跑 `deno install` 更新 `deno.lock`。有安装脚本的新依赖需要 `deno approve-scripts` 显式批准。
|
|
|
|
## 进程角色
|
|
|
|
`umt-server --role api|worker|all`(源码:`deno run ... apps/server/src/main.ts --role ...`)。`all` 下 worker 心跳会发布到进程内事件总线,SSE 可见;分进程部署时事件总线需改为 PG 投影(W2)。
|
|
|
|
一次性子命令(容器入口用):`--role migrate`(迁移到最新,迁移文件已编进二进制)、`--role preflight`(启动自检:生产环境拒绝占位符密钥与 root、DB 可达、`WEB_ROOT/index.html` 存在)、`--role probe`(打本机 `/api/v1/health`,HEALTHCHECK 用)。
|
|
|
|
设置 `WEB_ROOT` 后 API 进程在同一端口托管 web 构建产物:存在的文件直接返回,其余非 `/api` 路径回退 `index.html`。
|
|
|
|
## Docker 单容器部署
|
|
|
|
```sh
|
|
export SECRET_MASTER_KEY=$(openssl rand -hex 32) POSTGRES_PASSWORD=$(openssl rand -hex 16)
|
|
docker compose up -d --build # 服务:app(4380)+ postgres(数据卷 umt-pg-data)
|
|
curl localhost:4380/api/v1/health
|
|
```
|
|
|
|
- 镜像:`denoland/deno:2.9.7` 构建 web 与 `deno compile` 出二进制,运行时 `debian:trixie-slim`,非 root(uid 10001),约 270 MB。
|
|
- 入口 `docker/entrypoint.sh`:迁移 → 自检 → 同时起 api 与 worker 两个进程;任一退出则停掉另一个并以非 0 退出,由 `restart: unless-stopped` 拉起。
|
|
- 二进制编译时固定权限:`--allow-net --allow-env --allow-sys --allow-read=/app`,不给 `--allow-run` / 写权限。
|
|
- 构建版本号:`APP_VERSION=v0.1.0 docker compose build`(写入 web 的 `version.json`)。
|
|
|
|
## 测试数据库
|
|
|
|
需要 PG 的测试(db、tasks)默认连 `DATABASE_URL` 或 55433 开发库,不可达时跳过。tasks 包可用 `TASKS_TEST_DATABASE_URL` 指定独立库;每个测试文件使用带 pid+随机后缀的独立 schema,结束时删除,多份测试并发跑也不冲突。
|
|
|
|
## 排障
|
|
|
|
- `配置无效`:按提示检查 `.env`,`SECRET_MASTER_KEY` 至少 16 字符,`DATABASE_URL` 必须是 postgres://。
|
|
- health 返回 `db: "down"`:`docker compose -f docker-compose.dev.yml ps` 看容器健康状态。
|
|
- `deno check` 报找不到 `Deno`:检查根目录是否误放了 `tsconfig.json`(tsc 基座在 `config/tsconfig.base.json`)。
|
|
- tsc 报 `Deno` 未定义:先跑 `deno task types` 生成 `types/deno.d.ts`(已 gitignore)。
|
|
- 日志中的 passkey/token/cookie/authorization/password 字段与 URL query 参数会被替换为 `[REDACTED]`(含 `logger.child()` 绑定字段与 `err` 的 message/stack);若发现明文,属于缺陷。
|