Files
lingxi/docs/开发计划/灵犀_A0工程骨架与契约基线_实施报告_V0.1.md
Stev_Wang 2f200fc9d9
ci / 质量门禁 (push) Canceled after 0s
docs(infra): 接入公网 RustFS 对象存储
背景:项目方提供公网 RustFS(https://oss.xinsenidea.com,桶 lingxi-dev)。
改动:.env.example 填入 endpoint / 桶名占位;README 与 A0 报告记录
对象存储接入方式与验证结果;真实密钥仅保存在本地 .env / .env.local。
影响面:环境变量样例与文档,无运行时代码变更。
回滚方式:还原 .env.example 与文档即可。
验证:list buckets、HEAD bucket、PUT/GET/DELETE 探针对象均成功;
format:check、lint、typecheck、test 全绿。
2026-11-02 18:32:38 +08:00

108 lines
8.9 KiB
Markdown
Raw Permalink 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.
# 灵犀 · A0 工程骨架与契约基线 实施报告 V0.1
> 对应开发计划:`docs/开发计划/灵犀_信息流素材生产平台_开发计划_V0.1.md` §6.1「A0 工程骨架与契约基线」
> 交付方式:仅 `main` 直推,仓库不再保留任何短分支
> 日期:2026-11-02
## 1. 完成范围
| WBS | 状态 | 落地内容 |
| --- | --- | --- |
| A0-INF-01 Monorepo / 工具链 | 完成 | pnpm workspace + Turborepo;TS strict、ESLint 9 flat + Prettier + commitlint + lint-staged + husky;`.nvmrc` / `engines` / `packageManager` / preinstall 仅允许 pnpm;目录与 AGENTS.md §5 一致 |
| A0-INF-02 本地依赖与迁移种子 | 完成(种子范围受限,见 §4.4) | 复用本机 `docker-postgres-1`(PostgreSQL 18,5432)与 `docker-redis-1`(6379);`pnpm check:dev` 预检;`.env.example`;Prisma 初始化与首版迁移;`system_configs` 幂等种子 |
| A0-INF-03 CI 与质量门禁 | 完成 | `.gitea/workflows/ci.yml`:install → format → lint → typecheck → test → build → migrate → test:int → openapi:export/diff → e2e;新增 `pnpm ci:local` 在无 runner 时本地执行同一门禁;失败阻断 |
| A0-BE-01 API 骨架 | 完成 | NestJS 11 + Fastify;Pino + `trace_id`;统一错误体 `{code,message,details,trace_id}`;`GET /health`;`/api/docs` 与 OpenAPI JSON;Zod 管道;CORS / Helmet |
| A0-BE-02 Prisma 基线 | 完成 | `PrismaService` 封装;`outbox_events` / `idempotency_keys` / `system_configs`;ULID `char(26)`、软删/时间字段约定;首版迁移可重复执行 |
| A0-SH-01 shared 包 | 完成 | 20 个错误码(40001–50003)、权限点常量与 `模块:动作` 规范、ULID、游标分页、时间/命名工具、通用 Zod schema;前后端共同引用 |
| A0-FE-01 Web 骨架 | 完成 | Vite 6 + React 19 + Router 7 + TanStack Query 5 + Zustand 5;Semi `@douyinfe/semi-ui-19` 与 React19 适配入口;路径别名;fetch 请求层(token 注入、单飞 401 刷新、统一错误提示) |
| A0-FE-02 UI 包基线 | 完成 | Semi 二次封装(表格/查询表单/弹窗/空态/错误态/加载骨架);`icons.ts` 统一图标出口;locale;主题 token;ESLint 拦截越过出口的图标/UI 库与内联色值 |
| A0-FE-03 布局与登录壳 | 完成 | 顶部模块菜单 + 左侧功能菜单 + 面包屑;用户菜单、任务角标占位;401/403/404/500 页;登录页;导航集中配置并按权限过滤 |
| A0-QA-01 冒烟与报告 | 完成 | 健康检查冒烟、OpenAPI 冒烟、Playwright 登录/403/404/模块切换 4 条;覆盖率报告;CI 归档 |
## 2. 关键实现位置
- 契约与工具:`packages/shared/src/`(`errors/codes.ts`、`errors/api-error.ts`、`permissions.ts`、`ulid.ts`、`naming.ts`、`schemas/`)
- UI 基线:`packages/ui/src/`(`icons.ts`、`components/`、`theme/tokens.css`、`locale.ts`)
- API:`apps/api/src/`(`bootstrap.ts`、`common/filters`、`common/pipes`、`modules/platform/health/`、`openapi/document.ts`、`scripts/export-openapi.ts`)
- 数据:`prisma/schema.prisma`、`prisma/migrations/20261102083445_init_platform_baseline/`、`prisma/seed.ts`、`prisma/SEED.md`
- Web:`apps/web/src/`(`layout/`、`navigation/nav-config.ts`、`api/client.ts`、`pages/`、`stores/auth-store.ts`、`styles/`)
- 本地依赖:`scripts/check-dev-deps.mjs`、`.env.example`
- 契约快照:`openapi/lingxi.openapi.json`、`apps/web/src/api/generated/openapi.d.ts`
## 3. 本地门禁实测
| 命令 | 结果 |
| --- | --- |
| `pnpm format:check` | 通过 |
| `pnpm lint` | 通过(0 error / 0 warning) |
| `pnpm typecheck` | 通过(10/10 turbo tasks) |
| `pnpm test` | 通过(shared 42、api 20、web 12) |
| `pnpm build` | 通过(8/8 turbo tasks) |
| `pnpm test:int` | 通过(真实 PostgreSQL + Redis,`/health` 200) |
| `pnpm test:e2e` | 通过(4/4,Playwright/Chrome) |
| `pnpm openapi:export` + `pnpm openapi:diff` | 通过;快照含 20 个错误码,OpenAPI `3.1.0` |
| `pnpm check:dev` | 通过;PostgreSQL `5432/lingxi` 与 Redis `6379` 均可连接,`/health` 与 `test:int` 验证连通 |
| API 启动 | `/health` 200、`/api/docs` 200、`/api/openapi.json` 200 |
| Worker 启动 | 连接 Redis 成功,收到 SIGTERM 后正常退出 |
| 种子幂等 | 连续执行两次,`system_configs` 保持 7 条 |
## 4. 与文档的差异与待确认
### 4.1 本地依赖来源(环境适配)
本地 PostgreSQL 与 Redis **复用本机已有 Docker 服务**,不另起容器:`docker-postgres-1`(PostgreSQL 18,`127.0.0.1:5432`,库 `lingxi`、用户 `postgres`、密码 `postgres`)与 `docker-redis-1`(`127.0.0.1:6379`)。仓库不包含任何数据库/缓存容器编排。CI services 使用标准 5432/6379,凭据同为 `postgres/postgres`。
### 4.2 对象存储接入公网 RustFS
本地 Docker 不提供 S3 服务,`minio/minio` 镜像在当前网络也不可拉取。项目方已提供公网 RustFS:`https://oss.xinsenidea.com`,桶 `lingxi-dev`。A0 代码不依赖对象存储(`/health` 只检查 DB 与 Redis),已在本地 `.env.local` / `.env` 配置 `S3_*` 并实测通过(list buckets、HEAD bucket、PUT / GET / DELETE 探针对象均成功)。三类产物(assets / renders / temp)暂共用 `lingxi-dev` 桶,A1 落地渲染链路时再按前缀或独立桶拆分。真实 access key / secret 不入库。
### 4.3 演示登录(A0 临时)
A1 才实现真实鉴权。A0 登录页在 `VITE_PUBLIC_DEMO_SESSION` 非 `false` 时使用本地演示会话进入布局,便于验收布局与权限过滤;A1 接入真实登录后删除该分支。
### 4.4 种子范围【待确认 Q-A0-01】
开发计划 A0-INF-02 要求种子包含「超管、示例角色、核心字典、电商行业包占位」,但 `users / roles / dict_* / industry_packages` 等表分别在 A1 / A3 / A4 / B0 批次建立。A0 不提前建业务表,仅 seed `system_configs` 7 项,并在 `prisma/SEED.md` 登记待补种子清单。**请确认是否接受该拆分**;若要求 A0 内建表,则需调整开发计划批次顺序。
### 4.5 错误码 HTTP 映射
工程规范 04 未规定 50002 / 50003 的 HTTP 状态。A0 将 `50002 依赖不可用` 映射为 **503**(与 `/health` 依赖异常返回值一致),`50003 超时` 映射为 504;如需改为 502 / 504,请确认后调整 `packages/shared/src/errors/codes.ts` 与 `codes.spec.ts`。
### 4.6 Prisma CLI 与环境文件
Prisma CLI 只自动读取 `.env`,不读取 `.env.local`。本地需执行 `cp .env.local .env`(两者均在 `.gitignore`);应用与种子脚本同时兼容 `.env.local` 与 `.env`。
### 4.7 OpenAPI 破坏性检查实现
npm 上 `oasdiff` 为占位包(0.0.1-security),A0 暂用自研 `scripts/openapi-diff.mjs` 做路径/操作/字段级破坏性检查;CI 可后续替换为 oasdiff 官方二进制,命令仍为 `pnpm openapi:diff`。
### 4.9 本地 CI 与数据库凭据
当前离线 Gitea 未部署 Actions runner,推送后远程 CI 会停留在 `queued`。A0 增加 `pnpm ci:local`:按 `.gitea/workflows/ci.yml` 的顺序在本地执行 compose、格式、Lint、类型、单测、构建、迁移与种子、集成、OpenAPI 契约与 e2e,全部通过才退出 0;runner 就绪后远程工作流可直接接管。
本地开发库为 `lingxi` / `postgres` / `postgres`,直接连接本机已有 PostgreSQL 容器;`.env.example` 与 CI services 保持一致;对象存储已接入公网 RustFS(见 §4.2)。
### 4.8 前端视觉方向
已按 oil-ui-pro 流程产出两轮方案:
- v1(概念化:剪辑台 / 稿纸 / 调度台)被否决;
- v2(传统且现代化:云白蓝 / 石墨 / 暖白青)经产品负责人选择 **A · 云白蓝**,已落地到 `packages/ui/src/theme/tokens.css`、`apps/web/src/styles/`、`apps/web/index.html`:
- 顶部模块菜单 + 左侧功能菜单 + 面包屑;
- 白色顶栏、`#F5F7FA` 工作区、白卡片、`#1677FF` 主色、6px 圆角;
- 工作台:4 指标卡 + 生产任务表 + 快速入口 + 最近素材;
- 登录页:左上品牌、居中白卡、浅灰背景。
设计探索产物位于 `design/a0-ui-v2/`(含 6 屏、对比页与截图),按 `.gitignore` 约定不入库,仅本地留存评审。
## 5. 已知风险与后续动作
1. **A1 必须移除演示登录**并接入真实 JWT / 刷新令牌 / 权限守卫。
2. 种子业务数据待 A1 / A3 / A4 / B0 表就绪后补齐(Q-A0-01)。
3. 对象存储为公网 RustFS 单桶,A1 需按产物类型落前缀或拆分桶,并在 CI 配置独立测试桶。
4. Web 主包约 599 kB(Semi 全量 CSS 689 kB),A0 接受;M1 前做路由级拆分与 Semi 按需样式。
5. 远程 CI 待 Gitea Actions runner 就绪后验证 services 与 Playwright 浏览器安装;当前以 `pnpm ci:local` 为准(已实测通过)。
## 6. 下一步(A1)
按开发计划进入 A1:identity / client 模块、真实登录与 RBAC、`ScopeContext`、客户与组织基础表、登录与权限三态测试。