Files
NextEdu/docs/superpowers/plans/2026-07-07-enterprise-architecture-normalization.md

27 KiB

企业级架构规范化实施计划

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 消除所有架构违规 + 补齐大仓工程基建 + 升级 TypeScript/CI 配置,使项目达到企业级规范标准

Architecture: 严格分阶段(P0→P1→P2),每阶段独立 git 提交,失败可回滚。P0 修复 32 个无权限 Action + 5 个超长文件;P1 补齐文档 + 提交钩子 + tech-debt;P2 开启 noUncheckedIndexedAccess + CI 加 unit test + 可观测性补充

Tech Stack: TypeScript 5 / Next.js 16 / Drizzle / ESLint 9 / husky / commitlint / vitest / @next/bundle-analyzer

Spec: docs/superpowers/specs/2026-07-07-enterprise-architecture-normalization-design.md


阶段 1: P0 安全合规

Task 1: arch:scan 添加 @public 豁免标记机制

Files:

  • Modify: scripts/arch-scan/schema.ts (symbols 表加 is_public 列)

  • Modify: scripts/arch-scan/scanner.ts (识别 JSDoc @public)

  • Modify: scripts/arch-scan/query.ts (violations 过滤 is_public)

  • Test: scripts/arch-scan/scanner.test.ts

  • Step 1: 给 symbols 表加 is_public 列

修改 scripts/arch-scan/schema.ts,在 symbols 表定义中加:

is_public: integer("is_public", { mode: "boolean" }).notNull().default(false),

删除 scripts/arch-scan/arch.db 让 schema 重建。

  • Step 2: scanner.ts 识别 JSDoc @public 标记

修改 scripts/arch-scan/scanner.ts 的符号扫描逻辑。对每个 async function 导出,检查其上方的 JSDoc 注释是否包含 @public 标记。若是,设 is_public: true

参考实现(ts-morph API):

const jsDocs = symbolNode.getJsDocs();
const isPublic = jsDocs.some(doc => doc.getTags().some(tag => tag.getTagName() === "public"));
  • Step 3: query.ts violations 过滤 is_public

修改 scripts/arch-scan/query.tsprintViolations 函数,Server Actions without requirePermission 查询加 AND is_public = 0

  • Step 4: 运行测试验证
npm run test:arch-scan

Expected: 所有测试 PASS(25/25)。若 schema 变更导致测试失败,更新测试 fixture。

  • Step 5: 重新扫描验证
npm run arch:scan
npm run arch:query -- violations

Expected: violations 输出仍是 32 个(因为还没给 Action 加 @public)。

  • Step 6: Commit
git add scripts/arch-scan/
git commit -m "feat(arch-scan): add @public tag exemption mechanism for server actions"

Task 2: 给 12 个豁免 Action 加 @public 标记

Files:

  • Modify: src/modules/auth/actions.ts

  • Modify: src/modules/invitation-codes/actions.ts

  • Modify: src/modules/onboarding/actions.ts

  • Modify: src/modules/settings/actions-security.ts

  • Modify: src/modules/rbac/actions.ts

  • Modify: src/shared/lib/audit-logger.ts

  • Modify: src/shared/lib/change-logger.ts

  • Modify: src/shared/lib/login-logger.ts

  • Step 1: auth/actions.ts 加 @public

registerActioncheckEmailAvailabilityActionpreflightTwoFactorAction 三个函数,在 JSDoc 中加 @public 标记。示例:

/**
 * 注册新用户(登录前,无需权限校验)
 * @public
 */
export async function registerAction(...): Promise<ActionState<...>> { ... }
  • Step 2: invitation-codes/actions.ts 加 @public

validateInvitationCodeAction@public(注册时校验邀请码)。

  • Step 3: onboarding/actions.ts 加 @public

getOnboardingStatusActioncompleteOnboardingAction@public(引导阶段,已登录但未完成引导)。

  • Step 4: settings/actions-security.ts 加 @public

preflightTwoFactorActionverifyTwoFactorForLogin@public(登录中 2FA 流程)。

  • Step 5: rbac/actions.ts 加 @public

isAdminRole@public(内部辅助函数,非对外 Action)。

  • Step 6: shared/lib 三个 logger 加 @public

audit-logger.tslogAuditchange-logger.tslogDataChangelogin-logger.tslogLoginEvent@public(基础设施,被 Action 内部调用,非对外 Action)。

  • Step 7: 重新扫描验证豁免生效
npm run arch:scan
npm run arch:query -- violations

Expected: Server Actions without requirePermission 从 32 降至 20(豁免 12 个)。

  • Step 8: 验证 tsc + lint
npx tsc --noEmit
npm run lint

Expected: 0 errors。

  • Step 9: Commit
git add src/modules/ src/shared/lib/
git commit -m "fix(permissions): mark 12 public/infrastructure actions with @public tag"

Task 3: 修复 ai 模块 6 个 Action 权限

Files:

  • Modify: src/modules/ai/actions.ts

  • Possibly modify: src/shared/types/permissions.ts (若需新增权限点)

  • Step 1: 读取 ai/actions.ts 理解 6 个 Action 签名

# 用 Read 工具读取 src/modules/ai/actions.ts

确认每个 Action 的参数和现有权限校验方式。

  • Step 2: 确认所需权限点存在

检查 src/shared/types/permissions.ts 是否有:QUESTION_READ、HOMEWORK_GRADE、LESSON_PLAN_CREATE、QUESTION_CREATE、DIAGNOSTIC_READ、ERROR_BOOK_READ。若缺失,新增并注册到 5 处(permissions.ts → ROLE_PERMISSIONS_SEED → permission-bitmap.ts → permission-catalog.ts → i18n/rbac.json)。

  • Step 3: 给 6 个 Action 加 requirePermission
import { requirePermission } from "@/shared/lib/auth-guard";
import { Permissions } from "@/shared/types/permissions";

export async function suggestSimilarQuestionsAction(...) {
  const ctx = await requirePermission(Permissions.QUESTION_READ);
  // ... 原 logic 使用 ctx.userId
}

6 个映射:suggestSimilarQuestionsAction→QUESTION_READ、suggestGradingAction→HOMEWORK_GRADE、generateLessonContentAction→LESSON_PLAN_CREATE、generateQuestionVariantAction→QUESTION_CREATE、analyzeWeaknessAction→DIAGNOSTIC_READ、explainErrorAction→ERROR_BOOK_READ。

  • Step 4: 验证 tsc + lint
npx tsc --noEmit
npm run lint

Expected: 0 errors。

  • Step 5: Commit
git add src/modules/ai/ src/shared/types/
git commit -m "fix(ai): add requirePermission to 6 ai server actions"

Task 4: 修复 parent 模块 6 个 Action 权限

Files:

  • Modify: src/modules/parent/actions.ts

  • Possibly modify: src/shared/types/permissions.ts

  • Step 1: 读取 parent/actions.ts

确认 6 个 Action 的现有实现。parent 模块的特殊性:需要同时校验 parentId + studentId 防跨家庭信息泄露。

  • Step 2: 确认 PARENT_DASHBOARD_VIEW 权限点存在

若不存在,新增 PARENT_DASHBOARD_VIEW 到 permissions.ts + 5 处注册。

  • Step 3: 给 6 个 Action 加 requirePermission + parentId/studentId 校验
export async function getChildrenAction() {
  const ctx = await requirePermission(Permissions.PARENT_DASHBOARD_VIEW);
  // ctx.userId 即 parentId
  return getChildren(ctx.userId);
}

export async function getChildDashboardDataAction(studentId: string) {
  const ctx = await requirePermission(Permissions.PARENT_DASHBOARD_VIEW);
  await verifyParentChildRelationAction(ctx.userId, studentId); // 防越权
  return getChildDashboardData(studentId);
}

6 个:getChildrenAction、getChildBasicInfoAction、getChildDashboardDataAction、getParentDashboardDataAction、getChildNameListAction、verifyParentChildRelationAction。

  • Step 4: 验证 tsc + lint + arch:scan
npx tsc --noEmit
npm run lint
npm run arch:scan
npm run arch:query -- violations

Expected: tsc/lint 0 errors;violations 中 parent 模块的 6 个消失。

  • Step 5: Commit
git add src/modules/parent/ src/shared/types/
git commit -m "fix(parent): add requirePermission + parent-child relation check to 6 actions"

Task 5: 修复 settings 模块 5 个 Action 权限

Files:

  • Modify: src/modules/settings/actions.ts (4 个)

  • Modify: src/modules/settings/actions-service.ts (1 个: updateProfileAction)

  • Step 1: 确认权限点

确认 SYSTEM_SETTINGS_READ、SYSTEM_SETTINGS_MANAGE、USER_PROFILE_UPDATE 存在。USER_PROFILE_UPDATE 若不存在,用 getAuthContext() 替代(自身资料更新,任何登录用户均可)。

  • Step 2: 给 5 个 Action 加权限校验

actions.ts 中 4 个:getAiProviderSummaries→SYSTEM_SETTINGS_READ、upsertAiProviderAction→SYSTEM_SETTINGS_MANAGE、testAiProviderAction→SYSTEM_SETTINGS_MANAGE、deleteAiProviderAction→SYSTEM_SETTINGS_MANAGE、canConfigurePublicAiProvider→SYSTEM_SETTINGS_READ。

actions-service.ts 中 updateProfileAction:用 getAuthContext()(任何登录用户可改自己资料)。

  • Step 3: 验证
npx tsc --noEmit && npm run lint
  • Step 4: Commit
git add src/modules/settings/
git commit -m "fix(settings): add requirePermission to 5 settings server actions"

Task 6: 修复剩余 3 个 Action 权限

Files:

  • Modify: src/modules/leave-requests/actions.ts (listMyLeaveRequests)

  • Modify: src/modules/lesson-preparation/actions.ts (duplicateLessonPlanFormAction)

  • Step 1: leave-requests listMyLeaveRequests

getAuthContext()(查自己的请假记录,任何登录用户可查自己)。

  • Step 2: lesson-preparation duplicateLessonPlanFormAction

requirePermission(Permissions.LESSON_PLAN_CREATE)

  • Step 3: 验证全部 P0 权限修复完成
npm run arch:scan
npm run arch:query -- violations

Expected: Server Actions without requirePermission = 0。

  • Step 4: tsc + lint
npx tsc --noEmit && npm run lint
  • Step 5: Commit P0 权限修复完成
git add src/modules/
git commit -m "fix(permissions): complete requirePermission for remaining 3 actions"

Task 7: 拆分 shared/db/schema.ts (2245 行 → 按域拆分)

Files:

  • Create: src/shared/db/schema/users.ts

  • Create: src/shared/db/schema/academic.ts

  • Create: src/shared/db/schema/exams.ts

  • Create: src/shared/db/schema/grades.ts

  • Create: src/shared/db/schema/attendance.ts

  • Create: src/shared/db/schema/messaging.ts

  • Create: src/shared/db/schema/notifications.ts

  • Create: src/shared/db/schema/audit.ts

  • Create: src/shared/db/schema/rbac.ts

  • Create: src/shared/db/schema/files.ts

  • Create: src/shared/db/schema/scheduling.ts

  • Create: src/shared/db/schema/misc.ts

  • Modify: src/shared/db/schema.ts (改为 barrel re-export)

  • Step 1: 读取 schema.ts 按表分组

读取 src/shared/db/schema.ts,按域将 54 张表分组到上述 12 个文件。

  • Step 2: 创建 schema/ 目录,按域拆分

每个 schema/<domain>.ts 文件:

import { mysqlTable, varchar, ... } from "drizzle-orm/mysql-core";
// 该域的表定义
export const users = mysqlTable("users", { ... });
  • Step 3: schema.ts 改为 barrel
// src/shared/db/schema.ts
export * from "./schema/users";
export * from "./schema/academic";
export * from "./schema/exams";
// ... 12 个 re-export
  • Step 4: 验证所有 import 仍正常
npx tsc --noEmit

Expected: 0 errors(因为 barrel re-export 保持 import 路径不变)。

  • Step 5: 验证文件行数
Get-Content src/shared/db/schema.ts | Measure-Object -Line
# Expected: < 50 行(barrel)
Get-ChildItem src/shared/db/schema/*.ts | ForEach-Object { "$($_.Name): $((Get-Content $_.FullName | Measure-Object -Line).Lines)" }
# Expected: 每个文件 < 500 行
  • Step 6: Commit
git add src/shared/db/
git commit -m "refactor(db): split schema.ts (2245 lines) into 12 domain files"

Task 8: 拆分 shared/lib/cache/invalidation-map.ts (1195 行)

Files:

  • Create: src/shared/lib/cache/invalidation/<module>.ts (按模块拆分)

  • Modify: src/shared/lib/cache/invalidation-map.ts (改为 barrel + registerInvalidationMaps)

  • Step 1: 读取 invalidation-map.ts 按模块分组

  • Step 2: 按模块拆分到 invalidation/ 目录

每个模块的 invalidation map 移到独立文件,导出该模块的 invalidation 配置对象。

  • Step 3: invalidation-map.ts 改为 barrel + 聚合注册
import { examsInvalidation } from "./invalidation/exams";
// ...
export function registerInvalidationMaps() {
  register(examsInvalidation);
  // ...
}
  • Step 4: 验证
npx tsc --noEmit && npm run lint
  • Step 5: Commit
git add src/shared/lib/cache/
git commit -m "refactor(cache): split invalidation-map.ts (1195 lines) by module"

Task 9: 拆分 messaging/actions.ts (973 行)

Files:

  • Create: src/modules/messaging/actions-conversations.ts

  • Create: src/modules/messaging/actions-messages.ts

  • Create: src/modules/messaging/actions-starred.ts

  • Create: src/modules/messaging/actions-read.ts

  • Modify: src/modules/messaging/actions.ts (改为 barrel)

  • Step 1: 读取 actions.ts 按职责分组

  • Step 2: 按职责拆分到 4 个文件

每个文件顶部 "use server",按职责归类 Action。

  • Step 3: actions.ts 改为 barrel
export * from "./actions-conversations";
export * from "./actions-messages";
export * from "./actions-starred";
export * from "./actions-read";
  • Step 4: 验证
npx tsc --noEmit && npm run lint && npm run arch:scan
npm run arch:query -- violations

Expected: messaging/actions.ts 不再在超长文件列表。

  • Step 5: Commit
git add src/modules/messaging/
git commit -m "refactor(messaging): split actions.ts (973 lines) by responsibility"

Task 10: 拆分 textbooks/data-access.ts (907 行)

Files:

  • Create: src/modules/textbooks/data-access-chapters.ts

  • Create: src/modules/textbooks/data-access-knowledge-points.ts

  • Modify: src/modules/textbooks/data-access.ts (改为 barrel + 核心)

  • Step 1: 拆分章节 CRUD 到 data-access-chapters.ts

  • Step 2: 拆分知识点 CRUD 到 data-access-knowledge-points.ts

  • Step 3: data-access.ts 保留核心 + barrel re-export

  • Step 4: 验证

npx tsc --noEmit && npm run lint && npm run arch:scan
npm run arch:query -- violations

Expected: textbooks/data-access.ts 不再在超长文件列表。

  • Step 5: Commit
git add src/modules/textbooks/
git commit -m "refactor(textbooks): split data-access.ts (907 lines) by entity"

Task 11: 拆分 questions/data-access.ts (828 行)

Files:

  • Create: src/modules/questions/data-access-search.ts

  • Modify: src/modules/questions/data-access.ts (保留核心 CRUD + barrel)

  • Step 1: 拆分 FULLTEXT 检索到 data-access-search.ts

  • Step 2: data-access.ts 保留核心 CRUD + re-export

  • Step 3: 验证 P0 全部完成

npm run arch:scan
npm run arch:query -- violations

Expected: Long files = 0;Server Actions without requirePermission = 0。

npx tsc --noEmit && npm run lint

Expected: 0 errors。

  • Step 4: 更新 known-issues.md 工作经验日志

docs/troubleshooting/known-issues.md 工作经验日志区追加 P0 完成记录。

  • Step 5: Commit P0 阶段完成
git add src/modules/questions/ docs/troubleshooting/
git commit -m "refactor(questions): split data-access.ts and complete P0 security phase"
git push

阶段 2: P1 大仓工程基建

Task 12: 创建大仓文档

Files:

  • Create: LICENSE

  • Create: CHANGELOG.md

  • Create: CONTRIBUTING.md

  • Create: SECURITY.md

  • Create: .env.example

  • Step 1: 创建 LICENSE(专有协议)

Copyright (c) 2026 EazyGame. 保留所有权利。

未经版权所有者书面许可,不得以任何形式复制、修改、合并、发布、分发、再许可或销售本软件的任何部分。
  • Step 2: 创建 CHANGELOG.md(Keep-a-changelog 格式)
# 更新日志

本项目遵循 [Keep a Changelog](https://keepachangelog.com/) 格式,版本号遵循 [Semantic Versioning](https://semver.org/)。

## [1.0.0] - 2026-07-07

### Added
- arch.db 架构元数据库 + 扫描器(ts-morph + SQLite)
- 35 个模块 README.md(含 mermaid 架构图与流程图)
- 004 架构设计文档 V3(14 章节 + 13 mermaid 图)
- known-issues.md 索引式速查手册

### Changed
- 004 从"影响地图"重构为"架构设计文档"(458→912 行)
- project_rules.md 引入 arch.db + AI 工作强制流程
- coding-standards.md 更新令牌分层 + cacheFn + 5 层状态模型
  • Step 3: 创建 CONTRIBUTING.md

包含:分支策略(main 保护)、Conventional Commits 规范、提交前检查(lint+tsc+arch:scan)、模块 README 维护规则、代码审查清单。

  • Step 4: 创建 SECURITY.md

包含:漏洞报告流程、安全联系人、响应 SLA、不公开披露策略。

  • Step 5: 创建 .env.example

读取 src/env.mjs 提取所有环境变量键,加注释:

# 数据库
DATABASE_URL="mysql://user:pass@localhost:3306/next_edu"

# NextAuth
NEXTAUTH_SECRET="your-secret-here"
NEXTAUTH_URL="http://localhost:3000"

# AI Provider(可选)
OPENAI_API_KEY=""
ANTHROPIC_API_KEY=""

# Redis(可选)
REDIS_URL=""

# 文件存储
UPLOAD_DIR="./uploads"

# ... 其余从 env.mjs 提取
  • Step 6: Commit
git add LICENSE CHANGELOG.md CONTRIBUTING.md SECURITY.md .env.example
git commit -m "docs: add enterprise baseline docs (LICENSE/CHANGELOG/CONTRIBUTING/SECURITY/env.example)"

Task 13: 安装 husky + lint-staged + commitlint

Files:

  • Modify: package.json (dependencies + scripts)

  • Create: .husky/pre-commit

  • Create: .husky/commit-msg

  • Create: commitlint.config.js

  • Create: lint-staged.config.js

  • Step 1: 安装依赖

npm install -D husky lint-staged @commitlint/cli @commitlint/config-conventional
  • Step 2: 初始化 husky
npx husky init

这会创建 .husky/ 目录并生成 .husky/pre-commit 示例。

  • Step 3: 配置 pre-commit 钩子

.husky/pre-commit:

npx lint-staged
  • Step 4: 配置 commit-msg 钩子

.husky/commit-msg:

npx commitlint --edit "$1"
  • Step 5: 创建 commitlint.config.js
module.exports = {
  extends: ["@commitlint/config-conventional"],
  rules: {
    "scope-enum": [2, "always", [
      // 35 模块名
      "exams", "homework", "questions", "textbooks", "grades",
      "lesson-preparation", "classes", "school", "scheduling",
      "attendance", "course-plans", "users", "messaging",
      "notifications", "parent", "audit", "rbac", "auth",
      "onboarding", "ai", "dashboard", "diagnostic",
      "adaptive-practice", "error-book", "elective",
      "proctoring", "leave-requests", "invitation-codes",
      "files", "settings", "layout", "student", "search",
      "announcements", "standards",
      // 架构层
      "arch-scan", "db", "cache", "ui", "deps", "config",
      // 文档
      "docs", "architecture", "troubleshooting",
    ]],
  },
};
  • Step 6: 创建 lint-staged.config.js
module.exports = {
  "*.{ts,tsx}": ["eslint --fix", "prettier --write"],
  "*.{js,mjs,cjs}": ["prettier --write"],
  "*.md": ["prettier --write"],
  "*.{json,yml,yaml}": ["prettier --write"],
};
  • Step 7: package.json 加 prepare 脚本
"scripts": {
  "prepare": "husky"
}
  • Step 8: 验证钩子工作
# 测试 commitlint 拒绝非规范提交
git commit -m "bad commit message" --allow-empty
# Expected: FAIL (commitlint 拒绝)

# 测试规范提交
git commit -m "test(husky): verify commitlint works" --allow-empty
# Expected: PASS
  • Step 9: Commit
git add .husky/ commitlint.config.js lint-staged.config.js package.json package-lock.json
git commit -m "chore(deps): add husky + lint-staged + commitlint for commit convention enforcement"

Task 14: 填充 tech-debt.md

Files:

  • Modify: docs/architecture/roadmap/tech-debt.md

  • Step 1: 整理待解决技术债

从 known-issues 工作经验日志 + 本次诊断补充,整理至少 6 条待解决技术债:

  1. scripts 目录混放治理(.sh/.ps1/.js/.mjs/.ts 统一)
  2. API 文档自动化(OpenAPI 生成)
  3. proctoring 模块的 exams 依赖未被 arch.db 捕获(scanner 改进)
  4. FULLTEXT 索引迁移工具化
  5. client-error 上报机制完善(Task 12-14)
  6. React Flow 移除后的历史包袱清理
  7. noUncheckedIndexedAccess 历史债务(本次 P2 解决)
  8. coverage 阈值渐进提升(本次设 60% 起步)
  • Step 2: 写入 tech-debt.md

每条含:描述、影响、建议方案、优先级(P0/P1/P2)。

  • Step 3: Commit P1 阶段完成
git add docs/architecture/roadmap/tech-debt.md
git commit -m "docs(roadmap): populate tech-debt.md with 8 pending items"
git push

阶段 3: P2 配置升级

Task 15: 开启 noUncheckedIndexedAccess + 全量修复

Files:

  • Modify: tsconfig.json

  • Modify: 多个源文件(修复类型错误)

  • Step 1: tsconfig.json 开启 noUncheckedIndexedAccess

"noUncheckedIndexedAccess": true,
  • Step 2: 运行 tsc 收集所有错误
npx tsc --noEmit 2>&1 | Select-String "error TS"

记录所有错误位置。

  • Step 3: 批量修复类型错误

按模块批量修复:

  • 数组索引 arr[0]arr[0]!(确认存在)或 arr.at(0) ?? defaultValue(可能不存在)

  • 对象索引 obj[key] → 显式判空 if (key in obj) { ... }

  • split/match 结果 → ?? [] 兜底

  • Record<string, T> 访问 → T | undefined 处理

  • Step 4: 验证 tsc 0 错误

npx tsc --noEmit

Expected: 0 errors。

  • Step 5: 验证 lint + arch:scan
npm run lint && npm run arch:scan
  • Step 6: Commit
git add tsconfig.json src/
git commit -m "refactor(ts): enable noUncheckedIndexedAccess and fix all type errors"

Task 16: CI 加 unit test + coverage

Files:

  • Modify: .gitea/workflows/ci.yml

  • Modify: vitest.unit.config.ts

  • Modify: package.json (加 engines + packageManager)

  • Step 1: ci.yml 在 Lint 后、Typecheck 前加 Unit test

      - name: Lint
        run: npm run lint

      - name: Unit tests
        run: npm run test:unit

      - name: Typecheck
        run: npm run typecheck
  • Step 2: vitest.unit.config.ts 加 coverage 配置
test: {
  name: "unit",
  environment: "jsdom",
  include: ["src/**/*.test.{ts,tsx}"],
  clearMocks: true,
  restoreMocks: true,
  mockReset: true,
  coverage: {
    provider: "v8",
    reporter: ["text", "json-summary"],
    lines: 60,
    functions: 60,
    branches: 60,
    statements: 60,
  },
},
  • Step 3: package.json 加 engines + packageManager
"engines": {
  "node": ">=22"
},
"packageManager": "npm@10.9.0",
  • Step 4: 验证 unit test 通过
npm run test:unit

Expected: 全部 PASS。

  • Step 5: Commit
git add .gitea/workflows/ci.yml vitest.unit.config.ts package.json
git commit -m "ci: add unit test step and coverage threshold to CI"

Task 17: /api/health 端点 + Dockerfile HEALTHCHECK

Files:

  • Create: src/app/api/health/route.ts

  • Modify: Dockerfile(在 .next/standalone/Dockerfile)

  • Step 1: 创建 /api/health 路由

// src/app/api/health/route.ts
import { NextResponse } from "next/server";

export async function GET(): Promise<NextResponse> {
  return NextResponse.json({
    status: "ok",
    uptime: process.uptime(),
    timestamp: new Date().toISOString(),
    version: process.env.npm_package_version ?? "unknown",
  });
}
  • Step 2: 读取并修改 Dockerfile

读取 .next/standalone/Dockerfile(若不存在,读取项目根 Dockerfile)。加:

HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD wget -qO- http://localhost:3000/api/health || exit 1
  • Step 3: 验证
npx tsc --noEmit && npm run lint
  • Step 4: Commit
git add src/app/api/health/ Dockerfile
git commit -m "feat(observability): add /api/health endpoint and Docker HEALTHCHECK"

Task 18: bundle-analyzer

Files:

  • Modify: package.json (devDeps + scripts)

  • Modify: next.config.ts(若存在)或 next.config.mjs

  • Step 1: 安装 @next/bundle-analyzer

npm install -D @next/bundle-analyzer
  • Step 2: 配置 next.config

读取现有 next.config 文件,用 @next/bundle-analyzer 包装:

import bundleAnalyzer from "@next/bundle-analyzer";

const withBundleAnalyzer = bundleAnalyzer({
  enabled: process.env.ANALYZE === "true",
});

export default withBundleAnalyzer(nextConfig);
  • Step 3: package.json 加 analyze 脚本
"analyze": "ANALYZE=true next build"
  • Step 4: 验证
npm run lint
  • Step 5: Commit
git add next.config.* package.json package-lock.json
git commit -m "feat(perf): add @next/bundle-analyzer for bundle visualization"

Task 19: API 文档

Files:

  • Create: docs/api/README.md

  • Step 1: 创建 docs/api/README.md

列出 17 个 API 路由,每个含:方法、路径、用途、请求 schema、响应 schema、权限要求。从 withApiErrorHandlerActionState 推导统一格式。

  • Step 2: Commit P2 阶段完成
git add docs/api/
git commit -m "docs(api): add API documentation for 17 routes"
git push

Task 20: 最终验收 + 经验沉淀

  • Step 1: 全量验证
npm run arch:scan
npm run arch:query -- violations
npx tsc --noEmit
npm run lint
npm run test:unit

Expected:

  • violations: Long files = 0, Server Actions without requirePermission = 0

  • tsc: 0 errors

  • lint: 0 errors

  • test:unit: 全部 PASS

  • Step 2: 更新 known-issues.md 工作经验日志

追加本次规范化治理的经验记录。

  • Step 3: 更新 004(若架构意图变化)

若 P0 阶段的文件拆分改变了架构描述,更新 docs/architecture/004_architecture_impact_map.md

  • Step 4: 最终 commit + push
git add docs/
git commit -m "docs: final validation and experience logging for architecture normalization"
git push

验收标准

阶段 验收项 验证命令
P0 0 个超长文件 + 0 个无权限 Action npm run arch:query -- violations
P0 tsc + lint 0 错误 npx tsc --noEmit && npm run lint
P1 5 个文档存在 ls LICENSE CHANGELOG.md CONTRIBUTING.md SECURITY.md .env.example
P1 husky 钩子工作 git commit -m "bad" 被拒绝
P1 tech-debt.md 含 6+ 条 Get-Content docs/architecture/roadmap/tech-debt.md | Measure-Object -Line
P2 noUncheckedIndexedAccess=true cat tsconfig.json | Select-String noUncheckedIndexedAccess
P2 CI 跑 unit test Select-String "Unit tests" .gitea/workflows/ci.yml
P2 /api/health 可用 curl http://localhost:3000/api/health
P2 bundle-analyzer 可用 npm run analyze