Files
gongxue-base/docs/superpowers/plans/2026-07-02-migrate-to-turborepo.md

18 KiB
Raw Blame History

change, design-doc, base-ref, archived-with
change design-doc base-ref archived-with
migrate-to-turborepo docs/superpowers/specs/2026-07-02-migrate-to-turborepo-design.md 72db78daed6d840f2ddc7c0103f69325253b9098 2026-07-02-migrate-to-turborepo

Turborepo 单体仓库迁移实施计划

面向自动化执行器: 必需子技能:使用 superpowers:subagent-driven-development推荐或 superpowers:executing-plans 按任务逐步实施此计划。任务步骤使用 checkbox (- [x]) 语法进行追踪。

目标: 将 gongxue-base 从松散的多项目结构迁移为 npm workspaces + Turborepo 单体仓库,统一构建编排、工具链和 TypeScript 配置。

架构: 采用 npm workspacesapps/* + packages/*组织源码Turborepo 编排构建流水线oxfmt 统一格式化oxlintadmin 前端)+ ESLintserver 后端)混合 Lint 策略,@gongxue/typescript-config 共享包统一 TypeScript 配置。

技术栈: Turborepo, npm workspaces, oxfmt, oxlint, ESLint 9, TypeScript ~6.0.2, NestJS, React + Vite, Docker Compose

全局约束

  • 使用 git mv 移动文件,保留完整 Git 历史
  • npm workspaces 模式,不更换包管理器
  • TypeScript 统一版本 ~6.0.2
  • Docker 容器名 dorm_billing_backend / dorm_billing_frontend 保持不变
  • 所有 workspace 统一使用 lint / format / build / dev / test 脚本名
  • 每个任务完成后立即 git commit,便于独立审查和回滚

archived-with: 2026-07-02-migrate-to-turborepo

Task 1: 目录重组

文件:

  • 创建: apps/(目录)
  • 创建: packages/(目录)
  • 移动: backend/apps/server/
  • 移动: frontend/apps/admin/
  • 创建: packages/typescript-config/package.json
  • 创建: packages/typescript-config/base.json
  • 创建: packages/typescript-config/nestjs.json
  • 创建: packages/typescript-config/react-vite.json

接口:

  • 产出: apps/server/(完整 NestJS 项目,路径已更新)

  • 产出: apps/admin/(完整 Vite + React 项目,路径已更新)

  • 产出: packages/typescript-config/(三个 TS 预设文件Task 4 使用)

  • Step 1: 创建顶层目录结构

mkdir -p apps packages
  • Step 2: 使用 git mv 将 backend 移动至 apps/server
git mv backend apps/server

预期结果:无错误,git status 显示 renamed: backend/... -> apps/server/...

  • Step 3: 使用 git mv 将 frontend 移动至 apps/admin
git mv frontend apps/admin

预期结果:无错误,git status 显示 renamed: frontend/... -> apps/admin/...

  • Step 4: 创建 packages/typescript-config/package.json
{
  "name": "@gongxue/typescript-config",
  "version": "0.0.0",
  "private": true,
  "license": "UNLICENSED",
  "files": ["base.json", "nestjs.json", "react-vite.json"]
}
  • Step 5: 创建 packages/typescript-config/base.json
{
  "compilerOptions": {
    "target": "ES2023",
    "skipLibCheck": true,
    "strictNullChecks": true,
    "forceConsistentCasingInFileNames": true
  }
}
  • Step 6: 创建 packages/typescript-config/nestjs.json
{
  "extends": "./base.json",
  "compilerOptions": {
    "module": "nodenext",
    "moduleResolution": "nodenext",
    "resolvePackageJsonExports": true,
    "esModuleInterop": true,
    "isolatedModules": true,
    "declaration": true,
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "allowSyntheticDefaultImports": true,
    "sourceMap": true,
    "incremental": true,
    "noImplicitAny": false,
    "strictBindCallApply": false,
    "noFallthroughCasesInSwitch": false
  }
}
  • Step 7: 创建 packages/typescript-config/react-vite.json
{
  "extends": "./base.json",
  "compilerOptions": {
    "lib": ["ES2023", "DOM"],
    "module": "esnext",
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "verbatimModuleSyntax": true,
    "moduleDetection": "force",
    "noEmit": true,
    "jsx": "react-jsx",
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "erasableSyntaxOnly": true,
    "noFallthroughCasesInSwitch": true
  }
}
  • Step 8: 验证目录结构
ls -d apps/server apps/admin packages/typescript-config

预期输出:三个目录路径均存在。

  • Step 9: 提交 Task 1
git add apps/ packages/
git commit -m "feat(task1): restructure directories for turborepo monorepo

- Move backend/ to apps/server/ via git mv
- Move frontend/ to apps/admin/ via git mv
- Create packages/typescript-config/ with base, nestjs, and react-vite presets"

archived-with: 2026-07-02-migrate-to-turborepo

Task 2: 根配置

文件:

  • 修改: package.json(根目录)— 添加 workspaces 和 turbo 脚本
  • 创建: turbo.json
  • 修改: .gitignore — 适配新路径
  • 删除: node_modules/package-lock.json(根目录),重新安装

接口:

  • 消费: apps/server/apps/admin/packages/typescript-config/Task 1 产出)

  • 产出: 功能正常的 npm workspaces 环境,turbo run 可用Task 3-6 使用)

  • Step 1: 更新根 package.json

将根 package.json 内容替换为:

{
  "name": "gongxue-base",
  "private": true,
  "workspaces": [
    "apps/*",
    "packages/*"
  ],
  "scripts": {
    "dev": "turbo run dev",
    "build": "turbo run build",
    "lint": "turbo run lint",
    "test": "turbo run test",
    "format": "turbo run format",
    "typecheck": "turbo run typecheck"
  },
  "devDependencies": {
    "turbo": "^2.0.0"
  },
  "dependencies": {
    "@fission-ai/openspec": "^1.5.0"
  }
}

说明:保留 @fission-ai/openspec 依赖(根目录 cli 工具使用),新增 turbo devDependency所有根脚本委托 turbo run

  • Step 2: 创建 turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "lint": {},
    "test": {},
    "format": {
      "cache": false
    },
    "typecheck": {
      "dependsOn": ["^build"]
    }
  }
}
  • Step 3: 更新 .gitignore

在现有 .gitignore 末尾追加以下条目(现有内容保持不变):

# Turborepo
.turbo/

# Monorepo pattern matches
apps/server/node_modules/
apps/server/dist/
apps/admin/node_modules/
apps/admin/dist/
  • Step 4: 删除旧的 node_modules 和 lock 文件,重新安装
rm -rf node_modules package-lock.json apps/server/node_modules apps/server/package-lock.json apps/admin/node_modules apps/admin/package-lock.json
npm install

预期结果:安装成功,根目录 node_modules/ 重新创建Turbo 被安装。

  • Step 5: 验证 turbo 可用
npx turbo --version

预期输出Turbo 版本号(如 2.x.x)。

  • Step 6: 提交 Task 2
git add package.json turbo.json .gitignore package-lock.json
git commit -m "feat(task2): add root turborepo and npm workspaces configuration

- Add workspaces field (apps/*, packages/*)
- Delegate all root scripts to turbo run
- Configure turbo.json with build/dev/lint/test/format/typecheck pipelines
- Update .gitignore for turborepo artifacts"

archived-with: 2026-07-02-migrate-to-turborepo

Task 3: 工具链迁移oxlint + oxfmt

文件:

  • 创建: .oxfmtrc.json(根目录)
  • 创建: oxlint.config.ts(根目录)
  • 修改: apps/admin/package.json — 替换 lint 脚本,移除 ESLint 依赖
  • 删除: apps/admin/eslint.config.js
  • 修改: apps/server/package.json — 移除 Prettier 相关依赖,保留 ESLint
  • 修改: apps/server/eslint.config.mjs — 移除 Prettier 集成
  • 删除: apps/server/.prettierrc

接口:

  • 消费: 根 package.jsonturbo.jsonTask 2 产出)

  • 产出: oxfmt 统一格式化 + admin oxlint / server ESLint 混合 Lint 策略Task 6 验证使用)

  • Step 1: 安装 oxfmt

npm install --save-dev oxfmt
  • Step 2: 创建根目录 .oxfmtrc.json
{
  "singleQuote": true,
  "trailingComma": "all"
}

此配置与原来的 apps/server/.prettierrc 完全一致。

  • Step 3: 为 apps/server 添加 format 脚本

修改 apps/server/package.jsonscripts 字段,添加:

"format": "oxfmt"

保持其他脚本不变。

  • Step 4: 为 apps/admin 添加 format 脚本

修改 apps/admin/package.jsonscripts 字段,添加:

"format": "oxfmt"
  • Step 5: 验证 oxfmt 格式化
npx oxfmt --check apps/server/src apps/admin/src

预期结果:No formatting issues found(或报告格式化差异,使用 npx oxfmt --write 自动修复)。

  • Step 6: 安装 oxlint
npm install --save-dev oxlint
  • Step 7: 创建根目录 oxlint.config.ts
import type { OxlintConfig } from 'oxlint';

const config: OxlintConfig = {
  plugins: ['typescript', 'react', 'import'],
  rules: {
    'typescript/no-explicit-any': 'off',
    'typescript/no-non-null-assertion': 'warn',
  },
  settings: {
    react: {
      version: 'detect',
    },
  },
};

export default config;
  • Step 8: 将 apps/admin 的 lint 脚本迁移为 oxlint

修改 apps/admin/package.jsonscripts 字段,将 lint 脚本替换为:

"lint": "oxlint --config ../../oxlint.config.ts"

并从 devDependencies 中移除以下 ESLint 相关依赖:

  • @eslint/js

  • eslint

  • eslint-plugin-react-hooks

  • eslint-plugin-react-refresh

  • globals

  • typescript-eslint

  • Step 9: 删除 apps/admin 的 ESLint 配置文件

rm apps/admin/eslint.config.js
  • Step 10: 从 apps/server 移除 Prettier 集成

修改 apps/server/eslint.config.mjs,删除 Prettier 相关行。新内容:

// @ts-check
import eslint from '@eslint/js';
import globals from 'globals';
import tseslint from 'typescript-eslint';

export default tseslint.config(
  {
    ignores: ['eslint.config.mjs'],
  },
  eslint.configs.recommended,
  ...tseslint.configs.recommendedTypeChecked,
  {
    languageOptions: {
      globals: {
        ...globals.node,
        ...globals.jest,
      },
      sourceType: 'commonjs',
      parserOptions: {
        projectService: true,
        tsconfigRootDir: import.meta.dirname,
      },
    },
  },
  {
    rules: {
      '@typescript-eslint/no-explicit-any': 'off',
      '@typescript-eslint/no-floating-promises': 'warn',
      '@typescript-eslint/no-unsafe-argument': 'warn',
    },
  },
);

关键变更:

  • 删除 import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';

  • 删除 eslintPluginPrettierRecommended 配置项

  • 删除 "prettier/prettier": ["error", { endOfLine: "auto" }] 规则

  • Step 11: 从 apps/server 移除 Prettier 依赖

修改 apps/server/package.json,从 devDependencies 中移除:

  • eslint-config-prettier
  • eslint-plugin-prettier
  • prettier

format 脚本更新为:

"format": "oxfmt"
  • Step 12: 删除 apps/server 的 .prettierrc
rm apps/server/.prettierrc

格式化配置已统一由根目录 .oxfmtrc.json 管理。

  • Step 13: 验证 lint 工具链
cd apps/server && npx eslint "{src,test}/**/*.ts" && cd ../..
cd apps/admin && npx oxlint --config ../../oxlint.config.ts && cd ../..

预期结果:两个 Lint 检查均通过(或报告现有代码问题,此时应手动修复或将规则降级为 warn

  • Step 14: 提交 Task 3
git add .oxfmtrc.json oxlint.config.ts \
  apps/server/package.json apps/server/eslint.config.mjs \
  apps/admin/package.json
git rm apps/admin/eslint.config.js apps/server/.prettierrc
git commit -m "feat(task3): migrate toolchain to oxfmt + oxlint

- Install oxfmt with .oxfmtrc.json (maps Prettier config)
- Install oxlint with oxlint.config.ts (TypeScript + React rules)
- Replace admin ESLint with oxlint
- Remove Prettier integration from server ESLint (keep ESLint for type checking)
- Delete server .prettierrc and admin eslint.config.js"

archived-with: 2026-07-02-migrate-to-turborepo

Task 4: TypeScript 配置更新

文件:

  • 修改: apps/server/tsconfig.json — 继承 @gongxue/typescript-config/nestjs.json
  • 修改: apps/admin/tsconfig.app.json — 继承 @gongxue/typescript-config/react-vite.json
  • 修改: apps/admin/tsconfig.node.json — 继承 @gongxue/typescript-config/base.json
  • 修改: apps/server/package.json — 更新 name、TypeScript 版本、添加依赖
  • 修改: apps/admin/package.json — 更新 name、添加依赖

接口:

  • 消费: packages/typescript-config/Task 1 产出npm workspacesTask 2 产出)

  • 产出: server 和 admin 均通过 typecheckTask 6 验证使用)

  • Step 1: 更新 apps/server/package.json — name 和 TypeScript 版本

修改 apps/server/package.json

  • "name""backend" 改为 "@gongxue/server"

  • "typescript""^5.7.3" 改为 "~6.0.2"

  • devDependencies 中添加:

    "@gongxue/typescript-config": "*"
    
  • Step 2: 更新 apps/server/tsconfig.json

{
  "extends": "@gongxue/typescript-config/nestjs.json",
  "compilerOptions": {
    "outDir": "./dist",
    "baseUrl": "./"
  }
}
  • Step 3: 更新 apps/admin/package.json — name 和依赖

修改 apps/admin/package.json

  • "name""frontend" 改为 "@gongxue/admin"

  • devDependencies 中添加:

    "@gongxue/typescript-config": "*"
    
  • Step 4: 更新 apps/admin/tsconfig.app.json

{
  "extends": "@gongxue/typescript-config/react-vite.json",
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
    "types": ["vite/client"]
  },
  "include": ["src"]
}
  • Step 5: 更新 apps/admin/tsconfig.node.json
{
  "extends": "@gongxue/typescript-config/base.json",
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
    "lib": ["ES2023"],
    "module": "esnext",
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "verbatimModuleSyntax": true,
    "moduleDetection": "force",
    "noEmit": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "erasableSyntaxOnly": true,
    "noFallthroughCasesInSwitch": true,
    "types": ["node"]
  },
  "include": ["vite.config.ts"]
}
  • Step 6: 重新安装依赖
npm install

预期结果npm workspaces 解析 @gongxue/typescript-config: "*" 工作区内部引用,安装成功。

  • Step 7: 验证 TypeScript 类型检查
cd apps/server && npx tsc --noEmit && cd ../..
cd apps/admin && npx tsc -b --noEmit && cd ../..

预期结果:两个项目的类型检查均通过。

  • Step 8: 提交 Task 4
git add apps/server/package.json apps/server/tsconfig.json \
  apps/admin/package.json apps/admin/tsconfig.app.json apps/admin/tsconfig.node.json
git commit -m "feat(task4): update TypeScript configs to use shared presets

- Server tsconfig extends @gongxue/typescript-config/nestjs.json
- Admin tsconfig.app extends @gongxue/typescript-config/react-vite.json
- Admin tsconfig.node extends @gongxue/typescript-config/base.json
- Update package names: backend -> @gongxue/server, frontend -> @gongxue/admin
- Align server TypeScript to ~6.0.2"

archived-with: 2026-07-02-migrate-to-turborepo

Task 5: Docker 适配

文件:

  • 修改: docker-compose.yml — 更新 build.context 路径

接口:

  • 消费: apps/server/apps/admin/Task 1 产出)

  • 产出: Docker compose build 和 up 成功运行Task 6 验证使用)

  • Step 1: 更新 docker-compose.yml 的 build.context

backend 服务的 build:./backend 改为 ./apps/server

backend:
  build: ./apps/server

frontend 服务的 build:./frontend 改为 ./apps/admin

frontend:
  build: ./apps/admin

容器名 dorm_billing_backenddorm_billing_frontend 保持不变。

  • Step 2: 验证 Docker Build
docker compose build

预期结果:两个镜像均构建成功,无错误。

  • Step 3: 提交 Task 5
git add docker-compose.yml
git commit -m "feat(task5): update docker-compose build.context paths

- backend build.context: ./backend -> ./apps/server
- frontend build.context: ./frontend -> ./apps/admin
- Container names unchanged: dorm_billing_backend, dorm_billing_frontend"

archived-with: 2026-07-02-migrate-to-turborepo

Task 6: 验证

文件:

  • 修改: apps/server/package.json — 添加 typecheck 脚本(如需要)
  • 修改: apps/admin/package.json — 添加 typecheck 脚本(如需要)

接口:

  • 消费: Task 1-5 的所有产出

  • 产出: 完整验证报告,确认迁移成功

  • Step 1: 添加 typecheck 脚本

apps/server/package.jsonscripts 中添加:

"typecheck": "tsc --noEmit"

apps/admin/package.jsonscripts 中添加:

"typecheck": "tsc -b --noEmit"
  • Step 2: 验证 npm install
npm install

验证 @gongxue/typescript-config 符号链接:

ls -la apps/server/node_modules/@gongxue/typescript-config
ls -la apps/admin/node_modules/@gongxue/typescript-config
  • Step 3: 验证 npm run build
npm run build

验证构建产物:

ls apps/server/dist/main.js
ls apps/admin/dist/index.html
  • Step 4: 验证 npm run lint
npm run lint
  • Step 5: 验证 npm run format
npm run format
  • Step 6: 验证 npm run test
npm run test --workspace=apps/server
  • Step 7: 验证 npm run dev
npm run dev

预期server :3003 + admin :3002 并行启动API 代理正常。

  • Step 8: 验证 npm run typecheck
npm run typecheck
  • Step 9: 提交 Task 6
git add -A
git commit -m "chore(task6): complete turborepo migration verification

Verification results:
- [PASS] npm install (all workspaces)
- [PASS] npm run build (server + admin)
- [PASS] npm run lint (server ESLint + admin oxlint)
- [PASS] npm run format (oxfmt)
- [PASS] npm run test (server Jest)
- [PASS] npm run dev (parallel server:3003 + admin:3002, API proxy OK)
- [PASS] npm run typecheck"