feat(a0): 完成工程骨架与契约基线
ci / 质量门禁 (push) Canceled after 0s

- 建立 pnpm workspace + Turborepo 单仓、ESLint 9/Prettier/commitlint/husky 门禁
- NestJS + Fastify API:统一错误体、trace_id、Zod 管道、/health 真实依赖探活、OpenAPI 3.1 契约
- Prisma 基线:outbox_events/idempotency_keys/system_configs 与首版迁移、幂等种子
- shared 契约包:错误码、权限点、ULID、游标分页、命名/时间工具
- ui 包与 Web 壳层:Semi + Remix 图标统一出口、Cloud Blue 视觉、登录/工作台/错误页
- worker 骨架、Playwright 冒烟、Gitea CI、OpenAPI 快照与 oasdiff 回退脚本
- 补充 A0 实施报告与本地开发说明
This commit is contained in:
Stev_Wang committed 2026-11-02 17:01:50 +08:00
1 parent 9c3ab9768a
commit 04f49690f4
155 files changed
+18402 -28

No files matched your search

+54
View File
@@ -0,0 +1,54 @@
import { describe, expect, it } from 'vitest';
import {
ERROR_HTTP_STATUS,
ERROR_MESSAGES,
ErrorCode,
httpStatusOf,
isErrorCode,
} from './codes.js';
describe('ErrorCode', () => {
it('错误码段与工程规范 04 一致', () => {
expect(ErrorCode.PARAM_INVALID).toBe(40001);
expect(ErrorCode.UNAUTHENTICATED).toBe(40101);
expect(ErrorCode.TOKEN_EXPIRED).toBe(40102);
expect(ErrorCode.PERMISSION_DENIED).toBe(40301);
expect(ErrorCode.OUT_OF_SCOPE).toBe(40302);
expect(ErrorCode.NOT_FOUND).toBe(40401);
expect(ErrorCode.VERSION_CONFLICT).toBe(40901);
expect(ErrorCode.STATE_NOT_ALLOWED).toBe(40903);
expect(ErrorCode.COMPLIANCE_BLOCKED).toBe(42202);
expect(ErrorCode.COST_OVER_BUDGET).toBe(42203);
expect(ErrorCode.RATE_LIMITED).toBe(42901);
expect(ErrorCode.INTERNAL_ERROR).toBe(50001);
expect(ErrorCode.DEPENDENCY_UNAVAILABLE).toBe(50002);
expect(ErrorCode.TIMEOUT).toBe(50003);
});
it('每个错误码都有 HTTP 状态与默认提示', () => {
for (const code of Object.values(ErrorCode)) {
expect(ERROR_HTTP_STATUS[code]).toBeGreaterThanOrEqual(400);
expect(ERROR_HTTP_STATUS[code]).toBeLessThan(600);
expect(ERROR_MESSAGES[code].length).toBeGreaterThan(0);
}
});
it('依赖不可用映射 503、超时映射 504', () => {
expect(ERROR_HTTP_STATUS[ErrorCode.DEPENDENCY_UNAVAILABLE]).toBe(503);
expect(ERROR_HTTP_STATUS[ErrorCode.TIMEOUT]).toBe(504);
});
it('isErrorCode 只认可登记的错误码', () => {
expect(isErrorCode(40001)).toBe(true);
expect(isErrorCode(40099)).toBe(false);
expect(isErrorCode(200)).toBe(false);
});
it('httpStatusOf 从百位推导,非法码回退 500', () => {
expect(httpStatusOf(42203)).toBe(422);
expect(httpStatusOf(40101)).toBe(401);
expect(httpStatusOf(123)).toBe(500);
expect(httpStatusOf(70001)).toBe(500);
});
});