chore: commit oxfmt formatting changes and verify artifacts

This commit is contained in:
2026-07-02 15:55:09 +08:00
parent 34726cc46d
commit 4f4cee157a
77 changed files with 5576 additions and 1400 deletions

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-07-02

View File

@@ -0,0 +1,112 @@
## Context
当前项目为双应用平面结构:`backend/`NestJS + TypeORM`frontend/`React 19 + Vite通过 `docker-compose.yml` 编排部署。根 `package.json` 仅包含两个 `cd` 子目录的脚本,无统一构建编排能力。
随着业务扩展规划(学生端 `apps/student/` 等新应用),当前结构面临以下问题:
- 无共享配置机制,前后端各自维护 ESLint/TypeScript 配置
- 无构建缓存和并行能力CI 时间随应用增加线性增长
- 新增应用无标准目录约定,结构逐渐混乱
## Goals / Non-Goals
**Goals:**
- 建立标准 Turborepo monorepo 目录结构apps/ + packages/
- 引入 Turborepo 构建流水线与缓存,支持并行构建
- npm workspaces 统一依赖管理
- 抽取共享 TypeScript 配置到独立 package
- 代码格式化迁移到 oxfmt统一
- 前端 Linting 迁移到 oxlint更快后端保留 ESLint保障 NestJS 覆盖)
- Docker Compose 构建上下文适配新目录结构
**Non-Goals:**
- 不拆分后端微服务
- 不引入 pnpm/yarn 包管理器
- 不重构业务代码逻辑src/ 零变更)
- 不修改 Docker Compose 服务编排逻辑
- 暂不抽取 shared-types 包
## Decisions
### 1. 选择 Turborepo 而非 Nx/Lerna
| 维度 | Turborepo | Nx | Lerna |
|------|-----------|-----|-------|
| 构建缓存 | ✅ 内置(内容哈希) | ✅ 内置 | ⚠️ 需插件 |
| 并行执行 | ✅ 自动拓扑排序 | ✅ 自动 | ⚠️ 手动配置 |
| 配置复杂度 | 低(单一 turbo.json | 中nx.json + project.json | 低 |
| 生态 | Vercel 维护,与 Vite 天然契合 | 功能最强但重 | 社区为主 |
**选择 Turborepo**:项目前端使用 Vite同属 Vercel 生态),配置简洁,满足当前规模需求且不过度设计。
### 2. 选择 npm workspaces用户指定
用户要求沿用 npm。npm workspaces 自 v8+ 已成熟,支持 `--workspace` 标志,与 Turborepo 完全兼容。
### 3. 目录结构选择apps/ + packages/
采用 Turborepo 官方推荐结构:
```
gongxue-base/
├── apps/
│ ├── server/ # ← 当前 backend/ 移入API 服务)
│ ├── admin/ # ← 当前 frontend/ 移入(管理后台)
│ └── student/ # 未来:学生端
├── packages/
│ └── typescript-config/ # 共享 TS 配置
├── package.json # workspaces 声明 + 根脚本
├── turbo.json # Turborepo 流水线
├── .oxfmtrc.json # oxfmt 全局配置
├── oxlint.config.ts # oxlint 全局配置
└── docker-compose.yml # 调整构建 context
```
### 4. oxlint / oxfmt 工具链策略
**oxfmt**:统一替换 Prettier。oxfmt 与 Prettier 格式输出高度兼容,配置项映射简单。`.oxfmtrc.json` 放在根目录。
**oxlint**:采用混合策略:
- **前端apps/admin**:全面切换 oxlint。现有规则映射
- `typescript-eslint` → oxlint 内置 TypeScript 规则 ✅
- `react-hooks/rules-of-hooks` → oxlint 内置 ✅
- `react-hooks/exhaustive-deps` → ⚠️ oxlint 不支持,在 oxlint.config.ts 中禁用对应检查,接受 IDE 级补充
- `react-refresh` → ❌ 无等效规则,损失较小(仅 HMR 时的 export 检查)
- **后端apps/server**:保留 ESLint。NestJS 特有的装饰器类型检查和依赖注入规则(`@typescript-eslint/no-unsafe-*` 系列)在 oxlint 中无等效覆盖,贸然切换风险较高。
### 5. 共享 TypeScript 配置设计
`packages/typescript-config/` 提供三个预设:
- `base.json` — 通用 compilerOptions`strictNullChecks``skipLibCheck``forceConsistentCasingInFileNames``esModuleInterop` 等)
- `nestjs.json` — 继承 base + NestJS 特有(`experimentalDecorators``emitDecoratorMetadata``declaration`
- `react-vite.json` — 继承 base + 前端特有(`jsx: react-jsx``moduleResolution: bundler`
### 6. Turbo 流水线设计
```json
{
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"dev": {
"cache": false,
"persistent": true
},
"lint": { "dependsOn": ["^build"] },
"test": { "dependsOn": ["build"] },
"format": { "cache": false },
"typecheck": { "dependsOn": ["^build"] }
}
}
```
## Risks / Trade-offs
| 风险 | 影响 | 缓解措施 |
|------|------|----------|
| 目录迁移导致所有路径引用失效 | import 路径、Dockerfile、CI 脚本全部需更新 | tasks 中拆分独立的"目录迁移"步骤,逐项验证 |
| oxlint 覆盖不足导致部分规则缺失 | `exhaustive-deps``react-refresh` 规则丢失 | 明确记录缺失规则,依赖 TypeScript compiler 和 code review 兜底 |
| npm workspaces hoisting 行为变化 | 子项目可能访问到 hoisted 的不兼容版本 | Turborepo 严格模式下按 workspace 隔离;迁移后全量测试 |
| Docker 构建 context 路径变更 | `docker-compose.yml``build: ./backend` 需改为 `build: ./apps/server` | 迁移后 `docker compose build` 验证 |
| 根 node_modules 现有依赖冲突 | `@fission-ai/openspec` 与子项目依赖可能 hoisting 冲突 | openspec 保留在根,子项目依赖在各自 workspace 中声明 |

View File

@@ -0,0 +1,31 @@
## Why
当前项目采用平面目录结构(`backend/` + `frontend/`),根 `package.json` 仅用 `cd` 脚本串联两个子项目。规划中将新增学生端(`student`)等应用,现有结构无法支持统一构建编排、共享配置和依赖管理,项目工程化能力成为扩张瓶颈。需要建立标准 monorepo 体系,为多应用并行开发奠定基础。
## What Changes
- **BREAKING**:目录重组 — `backend/``apps/server/`API 服务),`frontend/``apps/admin/`(管理后台),预留 `apps/student/`(学生端)
- 引入 Turborepo 构建编排,定义 `turbo.json` 流水线
-`package.json` 改造为 npm workspaces 声明
- 抽取共享 TypeScript 配置到 `packages/typescript-config/`
- 代码格式化从 Prettier 迁移到 oxfmt
- 前端 Linting 从 ESLint 迁移到 oxlint后端保留 ESLint保障 NestJS 规则覆盖)
- Docker Compose 构建上下文路径调整
- 新增统一的根级脚本:`dev``build``lint``format`
## Capabilities
### New Capabilities
- `monorepo-structure`: npm workspaces 驱动的 monorepo 目录结构apps/ + packages/
- `turborepo-pipeline`: Turborepo 构建流水线与缓存
- `oxlint-oxfmt-toolchain`: 基于 oxlint + oxfmt 的代码质量工具链(前端 oxlint后端保留 ESLint
### Modified Capabilities
<!-- 本次无现有 spec 需要修改 -->
## Impact
- **目录结构**:所有顶层 `backend/``frontend/` 路径引用需更新
- **配置文件**:根 `package.json``tsconfig`(新增共享包)、`.gitignore`、Dockerfiles、`docker-compose.yml`
- **开发流程**开发、构建、lint、format 命令从子目录变更到根目录执行
- **无业务代码变更**`src/` 下所有业务逻辑保持不变

View File

@@ -0,0 +1,45 @@
## ADDED Requirements
### Requirement: Monorepo directory structure
The project SHALL adopt the Turborepo-recommended directory structure with `apps/` for applications and `packages/` for shared libraries.
#### Scenario: Directory layout exists
- **WHEN** a developer clones the repository
- **THEN** the root directory contains `apps/server/`, `apps/admin/`, and `packages/typescript-config/` as npm workspace packages
#### Scenario: Legacy paths removed
- **WHEN** the migration is complete
- **THEN** top-level `backend/` (moved to `apps/server/`) and `frontend/` (moved to `apps/admin/`) directories no longer exist
### Requirement: npm workspaces configuration
The root `package.json` SHALL declare `workspaces` field listing all app and package directories, enabling unified dependency management via npm.
#### Scenario: Install from root
- **WHEN** `npm install` is run at the project root
- **THEN** dependencies for all workspaces are installed and hoisted to root `node_modules/`
#### Scenario: Workspace-scoped scripts
- **WHEN** `npm run test --workspace=apps/server` is executed
- **THEN** only the backend test suite runs
### Requirement: Shared TypeScript configuration
The project SHALL provide shared TypeScript configuration presets via `packages/typescript-config/`, including `base.json`, `nestjs.json`, and `react-vite.json`.
#### Scenario: Server inherits NestJS preset
- **WHEN** `apps/server/tsconfig.json` is read
- **THEN** it extends `@gongxue/typescript-config/nestjs.json`
#### Scenario: Admin inherits React preset
- **WHEN** `apps/admin/tsconfig.json` is read
- **THEN** it extends `@gongxue/typescript-config/react-vite.json`
### Requirement: Docker Compose path compatibility
The `docker-compose.yml` SHALL reference build contexts using the new `apps/` paths, and all services MUST build and start successfully.
#### Scenario: Docker compose build succeeds
- **WHEN** `docker compose build` is executed
- **THEN** server and admin images build without errors
#### Scenario: Docker compose up succeeds
- **WHEN** `docker compose up` is executed
- **THEN** all services (MySQL, server, admin) start and respond to requests

View File

@@ -0,0 +1,45 @@
## ADDED Requirements
### Requirement: oxfmt replaces Prettier
The project SHALL use oxfmt for all code formatting, with a root `.oxfmtrc.json` configuration that replicates the existing Prettier conventions.
#### Scenario: Format check passes
- **WHEN** `npm run format` is executed at root
- **THEN** all TypeScript/JavaScript/JSON source files are formatted according to `.oxfmtrc.json` rules
#### Scenario: CI format gate
- **WHEN** `npm run format -- --check` is executed in CI
- **THEN** it exits with non-zero code if any file is not formatted correctly
### Requirement: Frontend oxlint replaces ESLint
The admin application (`apps/admin/`) SHALL use oxlint for linting, with a configuration that covers TypeScript and React rules equivalent to the existing ESLint setup.
#### Scenario: Admin lint passes
- **WHEN** `npm run lint` is executed at root
- **THEN** admin source files are linted with oxlint and pass without errors
#### Scenario: Rules-of-hooks violations detected
- **WHEN** a React hook is called conditionally in admin source
- **THEN** oxlint reports a rules-of-hooks violation
### Requirement: Backend retains ESLint
The server application (`apps/server/`) SHALL retain its existing ESLint configuration due to NestJS-specific rules that oxlint does not support.
#### Scenario: Server lint passes
- **WHEN** `npm run lint` is executed at root
- **THEN** server source files are linted with ESLint and pass without errors
#### Scenario: NestJS decorator checks work
- **WHEN** ESLint runs on server source
- **THEN** `@typescript-eslint/no-unsafe-*` rules and NestJS-specific patterns are enforced
### Requirement: Pre-existing Prettier/ESLint cleanup
All Prettier configuration files (`.prettierrc`, `eslint-plugin-prettier` references) SHALL be removed, and ESLint configurations SHALL be updated to remove Prettier integration.
#### Scenario: No Prettier remnants
- **WHEN** the migration is complete
- **THEN** `grep -r "prettier"` across config files returns no results (excluding oxfmt config which is separate)
#### Scenario: No Prettier dependencies
- **WHEN** `npm ls prettier eslint-plugin-prettier eslint-config-prettier` is run
- **THEN** no Prettier-related packages are installed in any workspace

View File

@@ -0,0 +1,38 @@
## ADDED Requirements
### Requirement: Turbo pipeline configuration
The project SHALL define a `turbo.json` at the repository root that configures build, dev, lint, test, format, and typecheck pipelines with appropriate caching and dependency ordering.
#### Scenario: Build pipeline with caching
- **WHEN** `turbo run build` is executed twice without source changes
- **THEN** the second run uses cached outputs and completes with "FULL TURBO" status
#### Scenario: Topological build ordering
- **WHEN** `turbo run build` is executed
- **THEN** packages (shared configs, types) build before apps that depend on them
#### Scenario: Parallel execution
- **WHEN** `turbo run lint` is executed
- **THEN** server and admin linting run in parallel where dependency graph allows
### Requirement: Unified root scripts
The root `package.json` SHALL provide top-level scripts (`dev`, `build`, `lint`, `format`, `test`, `typecheck`) that delegate to Turborepo or workspace-level commands.
#### Scenario: Dev mode starts all apps
- **WHEN** `npm run dev` is executed at root
- **THEN** both server (NestJS on port 3003) and admin (Vite on port 3002) start in dev mode
#### Scenario: Build produces all outputs
- **WHEN** `npm run build` is executed at root
- **THEN** server `dist/` and admin `dist/` are produced
### Requirement: Independent workspace scripts
Each workspace SHALL retain the ability to run its own scripts independently (e.g., `npm run test` inside `apps/server/`).
#### Scenario: Server tests run independently
- **WHEN** `npm run test` is executed inside `apps/server/`
- **THEN** the NestJS Jest test suite runs and reports results
#### Scenario: Admin dev runs independently
- **WHEN** `npm run dev` is executed inside `apps/admin/`
- **THEN** the Vite dev server starts on port 3002 with API proxy configured