Files
ftb-project-management/docs/superpowers/plans/2026-06-08-project-init.md
Script Generator 8de1f93fd3 feat: 初始化 FTB 智能项目管理系统 monorepo 项目结构
包含 Turborepo 配置、Next.js 前端骨架、NestJS 后端骨架、Prisma Schema、
共享类型包、Docker Compose 和环境变量模板。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-08 10:31:35 +08:00

899 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# FTB 智能项目管理系统 — 初始化实现计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 初始化 monorepo 项目代码结构,包含前后端骨架、数据库 Schema、共享类型包使项目可以运行并进入功能开发阶段。
**Architecture:** Turborepo monorepoapps/web (Next.js 14 App Router) + apps/server (NestJS)packages/shared 共享类型。PostgreSQL + Prisma ORMpnpm workspace 管理依赖。
**Tech Stack:** Next.js 14, Shadcn/ui, Tailwind CSS, Zustand, NestJS, Prisma, PostgreSQL, TypeScript
---
## Task 1: 初始化 Monorepo 根目录
**Files:**
- Create: `package.json`
- Create: `pnpm-workspace.yaml`
- Create: `turbo.json`
- Create: `.gitignore`
- Create: `.nvmrc`
- [ ] **Step 1: 初始化 git 仓库**
```bash
git init
```
- [ ] **Step 2: 创建根 package.json**
```json
{
"name": "ftb-project-management",
"private": true,
"scripts": {
"dev": "turbo dev",
"build": "turbo build",
"lint": "turbo lint",
"type-check": "turbo type-check",
"test": "turbo test",
"db:migrate": "pnpm --filter=server db:migrate",
"db:seed": "pnpm --filter=server db:seed",
"db:studio": "pnpm --filter=server db:studio"
},
"devDependencies": {
"turbo": "^2.0.0",
"typescript": "^5.5.0"
},
"packageManager": "pnpm@9.4.0"
}
```
- [ ] **Step 3: 创建 pnpm-workspace.yaml**
```yaml
packages:
- "apps/*"
- "packages/*"
```
- [ ] **Step 4: 创建 turbo.json**
```json
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"dev": {
"cache": false,
"persistent": true
},
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"]
},
"lint": {
"dependsOn": ["^build"]
},
"type-check": {
"dependsOn": ["^build"]
},
"test": {
"dependsOn": ["^build"]
}
}
}
```
- [ ] **Step 5: 创建 .gitignore**
```
node_modules/
dist/
.next/
.env
.env.local
.env.production
*.log
.turbo/
coverage/
.DS_Store
```
- [ ] **Step 6: 创建 .nvmrc**
```
20
```
- [ ] **Step 7: 安装根依赖并验证**
```bash
pnpm install
```
- [ ] **Step 8: Commit**
```bash
git add package.json pnpm-workspace.yaml turbo.json .gitignore .nvmrc
git commit -m "chore: 初始化 monorepo 根目录配置"
```
---
## Task 2: 初始化 packages/shared 共享类型包
**Files:**
- Create: `packages/shared/package.json`
- Create: `packages/shared/tsconfig.json`
- Create: `packages/shared/src/index.ts`
- Create: `packages/shared/src/enums.ts`
- Create: `packages/shared/src/types.ts`
- [ ] **Step 1: 创建 packages/shared/package.json**
```json
{
"name": "@ftb/shared",
"version": "0.0.1",
"private": true,
"main": "./src/index.ts",
"types": "./src/index.ts",
"scripts": {
"type-check": "tsc --noEmit",
"lint": "eslint src/"
},
"devDependencies": {
"typescript": "^5.5.0"
}
}
```
- [ ] **Step 2: 创建 packages/shared/tsconfig.json**
```json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"declaration": true,
"outDir": "./dist"
},
"include": ["src"]
}
```
- [ ] **Step 3: 创建 packages/shared/src/enums.ts**
```typescript
export enum TaskStatus {
TODO = 'todo',
IN_PROGRESS = 'in_progress',
IN_REVIEW = 'in_review',
DONE = 'done',
CLOSED = 'closed',
}
export enum ProjectRole {
OWNER = 'owner',
ADMIN = 'admin',
MEMBER = 'member',
VIEWER = 'viewer',
}
export enum RequirementStatus {
DRAFT = 'draft',
REVIEWING = 'reviewing',
APPROVED = 'approved',
REJECTED = 'rejected',
DELIVERED = 'delivered',
}
```
- [ ] **Step 4: 创建 packages/shared/src/types.ts**
```typescript
import { TaskStatus, ProjectRole, RequirementStatus } from './enums';
export interface Product {
id: string;
name: string;
description: string;
createdAt: Date;
updatedAt: Date;
}
export interface Project {
id: string;
productId: string;
name: string;
description: string;
createdAt: Date;
updatedAt: Date;
}
export interface Task {
id: string;
projectId: string;
sprintId: string | null;
versionId: string | null;
parentId: string | null;
title: string;
description: string;
status: TaskStatus;
assigneeId: string | null;
creatorId: string;
priority: number;
startDate: Date | null;
dueDate: Date | null;
createdAt: Date;
updatedAt: Date;
}
export interface Requirement {
id: string;
productId: string;
title: string;
description: string;
status: RequirementStatus;
priority: number;
creatorId: string;
createdAt: Date;
updatedAt: Date;
}
export interface Version {
id: string;
productId: string;
name: string;
description: string;
releaseDate: Date | null;
createdAt: Date;
updatedAt: Date;
}
export interface Sprint {
id: string;
projectId: string;
name: string;
startDate: Date;
endDate: Date;
createdAt: Date;
updatedAt: Date;
}
```
- [ ] **Step 5: 创建 packages/shared/src/index.ts**
```typescript
export * from './enums';
export * from './types';
```
- [ ] **Step 6: Commit**
```bash
git add packages/shared/
git commit -m "feat(shared): 初始化共享类型包,定义核心枚举和实体类型"
```
---
## Task 3: 初始化 NestJS 后端 (apps/server)
**Files:**
- Create: `apps/server/package.json`
- Create: `apps/server/tsconfig.json`
- Create: `apps/server/nest-cli.json`
- Create: `apps/server/src/main.ts`
- Create: `apps/server/src/app.module.ts`
- [ ] **Step 1: 创建 apps/server/package.json**
```json
{
"name": "server",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "nest start --watch",
"build": "nest build",
"start": "nest start",
"start:prod": "node dist/main",
"lint": "eslint \"src/**/*.ts\"",
"type-check": "tsc --noEmit",
"test": "jest",
"test:watch": "jest --watch",
"db:migrate": "prisma migrate dev",
"db:seed": "ts-node prisma/seed.ts",
"db:studio": "prisma studio"
},
"dependencies": {
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/platform-express": "^10.0.0",
"@prisma/client": "^5.15.0",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.0",
"@ftb/shared": "workspace:*"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
"@nestjs/testing": "^10.0.0",
"@types/express": "^4.17.0",
"@types/jest": "^29.5.0",
"@types/node": "^20.0.0",
"jest": "^29.7.0",
"prisma": "^5.15.0",
"ts-jest": "^29.1.0",
"ts-node": "^10.9.0",
"typescript": "^5.5.0"
}
}
```
- [ ] **Step 2: 创建 apps/server/tsconfig.json**
```json
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "ES2021",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"strict": true,
"skipLibCheck": true,
"paths": { "@/*": ["src/*"] }
},
"include": ["src"]
}
```
- [ ] **Step 3: 创建 apps/server/nest-cli.json**
```json
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": { "deleteOutDir": true }
}
```
- [ ] **Step 4: 创建 apps/server/src/app.module.ts**
```typescript
import { Module } from '@nestjs/common';
@Module({
imports: [],
controllers: [],
providers: [],
})
export class AppModule {}
```
- [ ] **Step 5: 创建 apps/server/src/main.ts**
```typescript
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.setGlobalPrefix('api/v1');
app.useGlobalPipes(new ValidationPipe({ whitelist: true }));
app.enableCors();
await app.listen(3001);
}
bootstrap();
```
- [ ] **Step 6: Commit**
```bash
git add apps/server/
git commit -m "feat(server): 初始化 NestJS 后端骨架"
```
---
## Task 4: 配置 Prisma Schema
**Files:**
- Create: `apps/server/prisma/schema.prisma`
- [ ] **Step 1: 创建 Prisma Schema 文件**
```prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
email String @unique
name String
avatar String?
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
createdTasks Task[] @relation("TaskCreator")
assignedTasks Task[] @relation("TaskAssignee")
projectMembers ProjectMember[]
requirements Requirement[]
watchedTasks TaskWatcher[]
@@map("users")
}
model Product {
id String @id @default(cuid())
name String
description String @default("")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
projects Project[]
requirements Requirement[]
versions Version[]
@@map("products")
}
model Project {
id String @id @default(cuid())
productId String @map("product_id")
name String
description String @default("")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
product Product @relation(fields: [productId], references: [id])
sprints Sprint[]
tasks Task[]
members ProjectMember[]
@@map("projects")
}
```
- [ ] **Step 2: 继续添加剩余模型到 schema.prisma**
在上面的文件末尾追加:
```prisma
model Sprint {
id String @id @default(cuid())
projectId String @map("project_id")
name String
startDate DateTime @map("start_date")
endDate DateTime @map("end_date")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
project Project @relation(fields: [projectId], references: [id])
tasks Task[]
@@map("sprints")
}
model Version {
id String @id @default(cuid())
productId String @map("product_id")
name String
description String @default("")
releaseDate DateTime? @map("release_date")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
product Product @relation(fields: [productId], references: [id])
tasks Task[]
@@map("versions")
}
model Requirement {
id String @id @default(cuid())
productId String @map("product_id")
title String
description String @default("")
status String @default("draft")
priority Int @default(0)
creatorId String @map("creator_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
product Product @relation(fields: [productId], references: [id])
creator User @relation(fields: [creatorId], references: [id])
@@map("requirements")
}
model Task {
id String @id @default(cuid())
projectId String @map("project_id")
sprintId String? @map("sprint_id")
versionId String? @map("version_id")
parentId String? @map("parent_id")
title String
description String @default("")
status String @default("todo")
priority Int @default(0)
assigneeId String? @map("assignee_id")
creatorId String @map("creator_id")
startDate DateTime? @map("start_date")
dueDate DateTime? @map("due_date")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
project Project @relation(fields: [projectId], references: [id])
sprint Sprint? @relation(fields: [sprintId], references: [id])
version Version? @relation(fields: [versionId], references: [id])
parent Task? @relation("TaskChildren", fields: [parentId], references: [id])
children Task[] @relation("TaskChildren")
assignee User? @relation("TaskAssignee", fields: [assigneeId], references: [id])
creator User @relation("TaskCreator", fields: [creatorId], references: [id])
watchers TaskWatcher[]
comments Comment[]
@@map("tasks")
}
model TaskWatcher {
id String @id @default(cuid())
taskId String @map("task_id")
userId String @map("user_id")
task Task @relation(fields: [taskId], references: [id])
user User @relation(fields: [userId], references: [id])
@@unique([taskId, userId])
@@map("task_watchers")
}
model Comment {
id String @id @default(cuid())
taskId String @map("task_id")
authorId String @map("author_id")
content String
createdAt DateTime @default(now()) @map("created_at")
task Task @relation(fields: [taskId], references: [id])
@@map("comments")
}
model ProjectMember {
id String @id @default(cuid())
projectId String @map("project_id")
userId String @map("user_id")
role String @default("member")
project Project @relation(fields: [projectId], references: [id])
user User @relation(fields: [userId], references: [id])
@@unique([projectId, userId])
@@map("project_members")
}
```
- [ ] **Step 3: Commit**
```bash
git add apps/server/prisma/
git commit -m "feat(server): 添加 Prisma Schema定义全部核心数据模型"
```
---
## Task 5: 初始化 Next.js 前端 (apps/web)
**Files:**
- Create: `apps/web/package.json`
- Create: `apps/web/tsconfig.json`
- Create: `apps/web/next.config.js`
- Create: `apps/web/tailwind.config.ts`
- Create: `apps/web/postcss.config.js`
- Create: `apps/web/app/layout.tsx`
- Create: `apps/web/app/page.tsx`
- Create: `apps/web/app/globals.css`
- [ ] **Step 1: 创建 apps/web/package.json**
```json
{
"name": "web",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "next dev --port 3000",
"build": "next build",
"start": "next start",
"lint": "next lint",
"type-check": "tsc --noEmit"
},
"dependencies": {
"next": "^14.2.0",
"react": "^18.3.0",
"react-dom": "^18.3.0",
"zustand": "^4.5.0",
"@ftb/shared": "workspace:*"
},
"devDependencies": {
"@types/node": "^20.0.0",
"@types/react": "^18.3.0",
"@types/react-dom": "^18.3.0",
"autoprefixer": "^10.4.0",
"postcss": "^8.4.0",
"tailwindcss": "^3.4.0",
"typescript": "^5.5.0"
}
}
```
- [ ] **Step 2: 创建 apps/web/tsconfig.json**
```json
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [{ "name": "next" }],
"paths": { "@/*": ["./*"] }
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}
```
- [ ] **Step 3: 创建 apps/web/next.config.js**
```javascript
/** @type {import('next').NextConfig} */
const nextConfig = {
transpilePackages: ['@ftb/shared'],
};
module.exports = nextConfig;
```
- [ ] **Step 4: 创建 apps/web/tailwind.config.ts**
```typescript
import type { Config } from 'tailwindcss';
const config: Config = {
content: ['./app/**/*.{ts,tsx}', './components/**/*.{ts,tsx}'],
theme: { extend: {} },
plugins: [],
};
export default config;
```
- [ ] **Step 5: 创建 apps/web/postcss.config.js**
```javascript
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
```
- [ ] **Step 6: 创建 apps/web/app/globals.css**
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```
- [ ] **Step 7: 创建 apps/web/app/layout.tsx**
```tsx
import './globals.css';
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'FTB 项目管理',
description: '智能项目管理系统',
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="zh-CN">
<body>{children}</body>
</html>
);
}
```
- [ ] **Step 8: 创建 apps/web/app/page.tsx**
```tsx
export default function HomePage() {
return (
<main className="flex min-h-screen items-center justify-center">
<h1 className="text-3xl font-bold">FTB 项目管理系统</h1>
</main>
);
}
```
- [ ] **Step 9: 创建前端页面目录占位**
```bash
mkdir -p apps/web/app/workspace
mkdir -p apps/web/app/products/[id]/requirements
mkdir -p apps/web/app/products/[id]/versions
mkdir -p apps/web/app/projects/[id]/board
mkdir -p apps/web/app/projects/[id]/gantt
mkdir -p apps/web/app/projects/[id]/sprints
mkdir -p apps/web/app/projects/[id]/settings
mkdir -p apps/web/app/admin/members
mkdir -p apps/web/components/ui
mkdir -p apps/web/components/board
mkdir -p apps/web/components/gantt
mkdir -p apps/web/components/shared
mkdir -p apps/web/hooks
mkdir -p apps/web/stores
mkdir -p apps/web/lib
```
- [ ] **Step 10: Commit**
```bash
git add apps/web/
git commit -m "feat(web): 初始化 Next.js 前端骨架,配置 Tailwind CSS"
```
---
## Task 6: Docker + 环境配置
**Files:**
- Create: `docker-compose.yml`
- Create: `.env.example`
- Create: `apps/server/.env.example`
- [ ] **Step 1: 创建 docker-compose.yml**
```yaml
version: '3.8'
services:
postgres:
image: postgres:16-alpine
ports:
- '5432:5432'
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: ftb_pm
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
ports:
- '6379:6379'
volumes:
postgres_data:
```
- [ ] **Step 2: 创建 .env.example**
```bash
# 数据库
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/ftb_pm
# 认证
NEXTAUTH_SECRET=change-me-to-random-secret
NEXTAUTH_URL=http://localhost:3000
# AI
ANTHROPIC_API_KEY=sk-ant-xxx
# Redis
REDIS_URL=redis://localhost:6379
# 邮件通知(可选)
SMTP_HOST=smtp.example.com
SMTP_PORT=465
SMTP_USER=noreply@example.com
SMTP_PASS=your-smtp-password
```
- [ ] **Step 3: 创建 apps/server/.env.example**
```bash
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/ftb_pm
ANTHROPIC_API_KEY=sk-ant-xxx
REDIS_URL=redis://localhost:6379
```
- [ ] **Step 4: Commit**
```bash
git add docker-compose.yml .env.example apps/server/.env.example
git commit -m "chore: 添加 Docker Compose 和环境变量示例配置"
```
---
## Task 7: 验证整体项目结构
- [ ] **Step 1: 安装全部依赖**
```bash
pnpm install
```
- [ ] **Step 2: 启动数据库**
```bash
docker-compose up -d
```
- [ ] **Step 3: 运行 Prisma 迁移**
```bash
cd apps/server && pnpm db:migrate
```
- [ ] **Step 4: 验证后端启动**
```bash
pnpm dev --filter=server
```
预期:控制台输出 `Nest application successfully started`,监听 3001 端口。
- [ ] **Step 5: 验证前端启动**
```bash
pnpm dev --filter=web
```
预期:控制台输出 `ready started server on 0.0.0.0:3000`,浏览器打开看到 "FTB 项目管理系统"。
- [ ] **Step 6: 类型检查通过**
```bash
pnpm type-check
```
预期:无错误输出。