# Next_Edu Architecture RFC **Status**: PROPOSED **Date**: 2025-12-22 **Author**: Principal Software Architect **Version**: 1.0.0 --- ## 1. 核心原则 (Core Principles) 本架构设计遵循以下核心原则,旨在构建一个高性能、可扩展、易维护的企业级在线教育平台。 1. **Vertical Slice Architecture (垂直切片)**: 拒绝传统的按技术分层(Layered Architecture),采用按业务功能分层。代码应根据“它属于哪个功能”而不是“它是什么文件”来组织。 2. **Type Safety First (类型安全优先)**: 全链路 TypeScript (Strict Mode)。从数据库 Schema 到 API 再到 UI 组件,必须保持类型一致性。 3. **Server-First (服务端优先)**: 充分利用 Next.js 15 App Router 的 RSC (React Server Components) 能力,减少客户端 Bundle 体积。 4. **Performance by Default (默认高性能)**: 严禁引入重型动画库,动效优先使用 CSS Native 实现。Web Vitals 指标作为 CI 阻断标准。 5. **Strict Engineering (严格工程化)**: CI/CD 流程标准化,代码风格统一,自动化测试覆盖。 --- ## 2. 技术栈全景图 (Technology Panorama) ### 核心框架 * **Framework**: Next.js 15 (App Router) * **Language**: TypeScript 5.x (Strict Mode enabled) * *Correction*: 鉴于 Next.js App Router 的特性,`.tsx` 仅用于包含 JSX 的组件文件。所有的业务逻辑、Hooks、API 路由、Lib 工具函数必须使用 `.ts` 后缀,以明确区分“渲染层”与“逻辑层”。 * **Runtime**: Node.js 20.x (LTS) ### 数据层 * **Database**: MySQL 8.0+ * **ORM**: Drizzle ORM (轻量、无运行时开销、类型安全) * **Driver**: `mysql2` (配合连接池) 或 `serverless-mysql` (针对特定 Serverless 环境) * **Validation**: Zod (Schema 定义与运行时验证) ### UI/UX 层 * **Styling**: Tailwind CSS v3.4+ * **Components**: Shadcn/UI (基于 Radix UI 的 Headless 组件拷贝) * **Icons**: Lucide React * **Animations**: CSS Transitions / Tailwind `animate-*` / `tailwindcss-animate` * *Complex Interactions*: Framer Motion (仅限按需加载 `LazyMotion`) ### 身份验证与授权 * **Auth**: Auth.js v5 (NextAuth) * *Decision Driver*: 相比 Clerk,Auth.js 提供了完全的**数据所有权**和**无 Vendor Lock-in**。 * *Enterprise Needs*: 允许自定义 Session 结构(如注入 `Role` 字段)并直接对接现有 MySQL 数据库,满足复杂的企业级权限管理需求。 ### 状态管理 * **Server State**: TanStack Query v5 (仅用于复杂客户端轮询/无限加载) * **URL State (Primary)**: Nuqs (Type-safe search params state manager) * *Principle*: 绝大多数状态(筛选、分页、Tab)应存在 URL 中,以支持分享和书签。 * **Global Client State (Secondary)**: Zustand * *Usage*: 仅限极少数全局交互状态(如播放器悬浮窗、全局 Modal)。 * *Anti-pattern*: **严禁使用 Redux**。避免不必要的样板代码和 Bundle 体积。 ### 基础设施 & DevOps * **CI/CD**: GitHub Actions (Strictly v3) * **Linting**: ESLint (Next.js config), Prettier * **Package Manager**: pnpm (推荐) 或 npm --- ## 3. 项目目录结构规范 (Project Structure) 采用 **Feature-based / Vertical Slice** 架构。所有业务逻辑应封装在 `src/modules` 中。 文档存放位置: * 架构设计文档: `docs/architecture/` * API 规范文档: `docs/api/` ### 目录树 (Directory Tree) ``` Next_Edu/ ├── .github/ │ └── workflows/ │ └── ci.yml # GitHub Actions (v3 strict) ├── docs/ │ └── architecture/ # 架构决策记录 (ADR) ├── drizzle/ # 数据库迁移文件 (Generated) ├── public/ # 静态资源 ├── src/ │ ├── app/ # [路由层] 极薄,仅负责路由分发和布局 │ │ ├── (auth)/ # 路由组 │ │ ├── (dashboard)/ │ │ ├── api/ # Webhooks / External APIs │ │ ├── layout.tsx │ │ └── page.tsx │ │ │ ├── modules/ # [核心业务层] 垂直切片 │ │ ├── courses/ # 课程模块 │ │ │ ├── components/ # 模块私有组件 (CourseCard, Player) │ │ │ ├── actions.ts # Server Actions (业务逻辑入口) │ │ │ ├── service.ts # 领域服务 (可选,复杂逻辑拆分) │ │ │ ├── data-access.ts # 数据库查询 (DTOs) │ │ │ └── types.ts # 模块私有类型 │ │ │ │ │ ├── users/ # 用户模块 │ │ ├── payments/ # 支付模块 │ │ └── community/ # 社区模块 │ │ │ ├── shared/ # [共享层] 仅存放真正通用的代码 │ │ ├── components/ # 通用 UI (Button, Dialog - Shadcn) │ │ ├── lib/ # 通用工具 (utils, date formatting) │ │ ├── db/ # Drizzle Client & Schema │ │ │ ├── index.ts # DB 连接实例 │ │ │ └── schema.ts # 全局 Schema 定义 (或按模块拆分导出) │ │ └── hooks/ # 通用 Hooks │ │ │ ├── env.mjs # 环境变量类型检查 │ └── middleware.ts # 边缘中间件 (Auth check) ├── drizzle.config.ts # Drizzle 配置文件 ├── next.config.mjs └── package.json ``` --- ## 4. 数据库层设计 (Database Strategy) ### 连接配置 (Connection Pooling) 在 Next.js 的 Serverless/Edge 环境中,直接连接 MySQL 可能导致连接数耗尽。我们采取以下策略: 1. **开发环境**: 使用 Global Singleton 模式防止 Hot Reload 导致连接泄露。 2. **生产环境**: * 推荐使用支持 HTTP 连接或内置连接池的 Serverless MySQL 方案 (如 PlanetScale)。 * 若使用标准 MySQL,必须配置连接池 (`connectionLimit`) 并合理设置空闲超时。 **代码示例 (`src/shared/db/index.ts`)**: ```typescript import { drizzle } from "drizzle-orm/mysql2"; import mysql from "mysql2/promise"; import * as schema from "./schema"; // Global cache to prevent connection exhaustion in development const globalForDb = globalThis as unknown as { conn: mysql.Pool | undefined; }; const poolConnection = globalForDb.conn ?? mysql.createPool({ uri: process.env.DATABASE_URL, waitForConnections: true, connectionLimit: 10, // 根据数据库规格调整 queueLimit: 0 }); if (process.env.NODE_ENV !== "production") globalForDb.conn = poolConnection; export const db = drizzle(poolConnection, { schema, mode: "default" }); ``` ### Migration 策略 * 使用 `drizzle-kit` 进行迁移管理。 * 严禁在生产环境运行时自动执行 Migration。 * **流程**: 1. 修改 Schema (`schema.ts`). 2. 运行 `pnpm drizzle-kit generate` 生成 SQL 文件。 3. Review SQL 文件。 4. 在 CI/CD 部署前置步骤或手动运行 `pnpm drizzle-kit migrate`。 ### Server Components 中的数据查询 * **Colocation**: 查询逻辑应尽量靠近使用它的组件,或者封装在 `data-access.ts` 中。 * **Request Memoization**: 即使在一个请求中多次调用相同的查询函数,Next.js 的 `cache` (或 React `cache`) 也会自动去重。 ```typescript // src/modules/courses/data-access.ts import { cache } from 'react'; import { db } from '@/shared/db'; import { eq } from 'drizzle-orm'; import { courses } from '@/shared/db/schema'; // 使用 React cache 确保单次请求内的去重 export const getCourseById = cache(async (id: string) => { return await db.query.courses.findFirst({ where: eq(courses.id, id), }); }); ``` --- ## 5. UI/UX 动效规范 (Animation Guidelines) ### 核心策略 * **CSS Native First**: 90% 的交互通过 CSS `transition` 和 `animation` 实现。 * **Hardware Acceleration**: 确保动画属性触发 GPU 加速 (`transform`, `opacity`)。 * **Micro-interactions**: 关注 `:hover`, `:active`, `:focus-visible` 状态。 ### 高性能通用组件示例 (Interactive Card) 这是一个符合规范的卡片组件,使用了 Tailwind 的 `group` 和 `transform` 属性实现丝滑的微交互,且没有 JS 运行时开销。 ```tsx // src/shared/components/ui/interactive-card.tsx import { cn } from "@/shared/lib/utils"; interface CardProps extends React.HTMLAttributes { children: React.ReactNode; } export function InteractiveCard({ className, children, ...props }: CardProps) { return (
{/* 光泽效果 (Shimmer Effect) - 仅 CSS */} ); } ``` --- ## 6. CI/CD 配置文件模板 (GitHub Actions) **警告**: 必须严格遵守 `v3` 版本限制。严禁使用 `v4`。 文件路径: `.github/workflows/ci.yml` ```yaml name: CI/CD Pipeline on: push: branches: [ "main", "develop" ] pull_request: branches: [ "main", "develop" ] env: NODE_VERSION: '20.x' jobs: quality-check: name: Quality & Type Check runs-on: ubuntu-latest steps: # 强制使用 v3 - name: Checkout Code uses: actions/checkout@v3 with: fetch-depth: 0 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} cache: 'npm' # 或 'pnpm' - name: Install Dependencies run: npm ci - name: Linting (ESLint) run: npm run lint - name: Type Checking (TSC) # 确保没有 TS 错误 run: npx tsc --noEmit test: name: Unit Tests needs: quality-check runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} cache: 'npm' - name: Install Dependencies run: npm ci - name: Run Tests run: npm run test build-check: name: Production Build Check needs: test runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} cache: 'npm' - name: Install Dependencies run: npm ci - name: Cache Next.js build uses: actions/cache@v3 with: path: | ~/.npm ${{ github.workspace }}/.next/cache # Generate a new cache whenever packages or source files change. key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }} restore-keys: | ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}- - name: Build Application run: npm run build env: # 构建时跳过 ESLint/TS 检查 (因为已经在 quality-check job 做过了,加速构建) NEXT_TELEMETRY_DISABLED: 1 ```