commit 8de1f93fd34926c35d284d4e76258746809c2fb1 Author: Script Generator Date: Mon Jun 8 10:31:35 2026 +0800 feat: 初始化 FTB 智能项目管理系统 monorepo 项目结构 包含 Turborepo 配置、Next.js 前端骨架、NestJS 后端骨架、Prisma Schema、 共享类型包、Docker Compose 和环境变量模板。 Co-Authored-By: Claude Opus 4.7 (1M context) diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..7f97812 --- /dev/null +++ b/.env.example @@ -0,0 +1,18 @@ +# 数据库 +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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..58fe590 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +node_modules/ +dist/ +.next/ +.env +.env.local +.env.production +*.log +.turbo/ +coverage/ +.DS_Store diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..209e3ef --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +20 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..48bccbf --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,188 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +FTB 智能项目管理系统 — 一个集成 AI 能力的项目管理平台,核心目标是通过智能化手段提升项目管理效率。 + +### 核心功能模块 + +- **任务管理**:任务创建、分配、状态流转、优先级管理 +- **看板视图**:可视化任务拖拽、自定义工作流列 +- **甘特图**:项目时间线规划与依赖关系管理 +- **AI 辅助**:任务智能分解、工期预估、风险预警 +- **资源调度**:团队成员工作负载可视化、智能排期建议 +- **数据看板**:项目进度、燃尽图、团队效率指标 + +## Tech Stack + +| 层级 | 技术 | 说明 | +|------|------|------| +| 前端框架 | Next.js 14+ (App Router) | SSR + 文件路由 | +| UI 组件 | Shadcn/ui + Tailwind CSS | 现代风格,完全可定制 | +| 状态管理 | Zustand | 轻量级,替代 Redux | +| 拖拽 | dnd-kit | 看板拖拽交互 | +| 图表 | Recharts | 燃尽图、数据看板 | +| 后端框架 | NestJS | 模块化架构,TypeScript | +| ORM | Prisma | 类型安全的数据库访问 | +| 数据库 | PostgreSQL | 关系型数据,适合任务依赖建模 | +| AI 集成 | Anthropic SDK | 任务分解、风险分析、智能建议 | +| 认证 | NextAuth.js | OAuth + JWT | +| 实时通信 | Socket.io | 看板实时同步、通知推送 | + +## Architecture + +``` +ftb-project-management/ +├── apps/ +│ ├── web/ # Next.js 前端 +│ │ ├── app/ # App Router 页面 +│ │ ├── components/ # UI 组件 +│ │ │ ├── ui/ # Shadcn 基础组件 +│ │ │ ├── board/ # 看板相关组件 +│ │ │ ├── gantt/ # 甘特图组件 +│ │ │ └── dashboard/ # 数据看板组件 +│ │ ├── hooks/ # 自定义 Hooks +│ │ ├── stores/ # Zustand stores +│ │ └── lib/ # 工具函数 +│ └── server/ # NestJS 后端 +│ ├── src/ +│ │ ├── modules/ +│ │ │ ├── project/ # 项目 CRUD +│ │ │ ├── task/ # 任务管理 + 状态机 +│ │ │ ├── board/ # 看板逻辑 +│ │ │ ├── gantt/ # 甘特图数据 +│ │ │ ├── ai/ # AI 能力封装 +│ │ │ ├── user/ # 用户与权限 +│ │ │ └── notify/ # 通知系统 +│ │ ├── common/ # 拦截器、守卫、管道 +│ │ └── prisma/ # Schema + Migrations +│ └── test/ +├── packages/ +│ └── shared/ # 前后端共享类型定义 +├── docker-compose.yml +└── turbo.json # Turborepo monorepo 管理 +``` + +## Build & Dev Commands + +```bash +# 安装依赖(monorepo 根目录) +pnpm install + +# 启动全部服务(前端 + 后端 + 数据库) +pnpm dev + +# 单独启动 +pnpm dev --filter=web # 前端 localhost:3000 +pnpm dev --filter=server # 后端 localhost:3001 + +# 数据库 +pnpm db:migrate # 执行 Prisma 迁移 +pnpm db:seed # 填充测试数据 +pnpm db:studio # 打开 Prisma Studio + +# 测试 +pnpm test # 全部测试 +pnpm test --filter=server # 仅后端测试 +pnpm test -- --watch # 监听模式 +pnpm test -- -t "任务创建" # 运行单个测试 + +# 构建 & 检查 +pnpm build # 生产构建 +pnpm lint # ESLint 检查 +pnpm type-check # TypeScript 类型检查 + +# Docker +docker-compose up -d # 启动 PostgreSQL + Redis +docker-compose down # 停止容器 +``` + +## Data Model (核心实体关系) + +``` +User ──┬── owns ──── Project + │ │ + │ contains many + │ │ + └── assigned ── Task ──── depends on ──── Task + │ + has many + │ + Comment / Activity / Attachment +``` + +关键设计决策: +- 任务状态机:`todo → in_progress → in_review → done`,支持自定义列 +- 任务支持无限层级子任务(parent_id 自引用) +- 权限模型:Owner > Admin > Member > Viewer(项目级 RBAC) +- AI 操作记录独立表存储,便于审计和回溯 + +## AI Module 设计 + +AI 模块作为独立 NestJS Module,对外暴露服务接口: + +- `AiTaskService.decompose(description)` — 将需求描述拆解为子任务 +- `AiRiskService.analyze(projectId)` — 分析项目风险并生成预警 +- `AiScheduleService.suggest(projectId)` — 基于成员负载给出排期建议 + +所有 AI 调用走统一的 `AiGateway`,负责 prompt 管理、token 计量、降级处理。 + +## Conventions + +- 包管理器:pnpm(monorepo workspace) +- 分支命名:`feature/模块-描述`、`fix/模块-描述`、`hotfix/描述` +- Commit 格式:`类型(模块): 描述`(中文) + - 类型:feat / fix / refactor / docs / test / chore +- API 路径:`/api/v1/projects/:projectId/tasks/:taskId`(RESTful 嵌套资源) +- 前端路由:`/projects/[id]/board`、`/projects/[id]/gantt`、`/projects/[id]/dashboard` +- 数据库表名 snake_case,TypeScript 字段 camelCase(Prisma 自动映射) +- 组件文件 PascalCase,工具函数文件 camelCase +- Zustand store 按功能域拆分:`useProjectStore`、`useTaskStore`、`useBoardStore` + +## Environment Variables + +项目根目录提供 `.env.example`,开发者复制为 `.env.local` 使用。 + +```bash +# 数据库 +DATABASE_URL=postgresql://postgres:postgres@localhost:5432/ftb_pm + +# 认证 +NEXTAUTH_SECRET=your-random-secret-key +NEXTAUTH_URL=http://localhost:3000 + +# AI +ANTHROPIC_API_KEY=sk-ant-xxx + +# Redis(Socket.io 适配器 + 缓存) +REDIS_URL=redis://localhost:6379 + +# 邮件通知(可选) +SMTP_HOST=smtp.example.com +SMTP_PORT=465 +SMTP_USER=noreply@example.com +SMTP_PASS=your-smtp-password +``` + +## Deployment + +采用 Docker Compose 部署到云服务器(推荐 2核4G),一套配置本地和线上通用。 + +```yaml +# docker-compose.prod.yml 核心服务 +services: + web: # Next.js 前端,端口 3000 + server: # NestJS 后端,端口 3001 + postgres: # PostgreSQL 数据库,端口 5432 + redis: # Redis 缓存 + Socket.io,端口 6379 + nginx: # 反向代理 + SSL 终止,端口 80/443 +``` + +部署流程: +1. 服务器安装 Docker + Docker Compose +2. 配置 `.env.production` 环境变量 +3. `docker-compose -f docker-compose.prod.yml up -d` +4. Nginx 配置域名 + Let's Encrypt SSL 证书 +5. 数据库迁移:`docker exec server pnpm db:migrate` diff --git a/apps/server/.env.example b/apps/server/.env.example new file mode 100644 index 0000000..79c391b --- /dev/null +++ b/apps/server/.env.example @@ -0,0 +1,3 @@ +DATABASE_URL=postgresql://postgres:postgres@localhost:5432/ftb_pm +ANTHROPIC_API_KEY=sk-ant-xxx +REDIS_URL=redis://localhost:6379 diff --git a/apps/server/nest-cli.json b/apps/server/nest-cli.json new file mode 100644 index 0000000..d50e6ab --- /dev/null +++ b/apps/server/nest-cli.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/nest-cli", + "collection": "@nestjs/schematics", + "sourceRoot": "src", + "compilerOptions": { "deleteOutDir": true } +} diff --git a/apps/server/package.json b/apps/server/package.json new file mode 100644 index 0000000..0cea8df --- /dev/null +++ b/apps/server/package.json @@ -0,0 +1,39 @@ +{ + "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" + } +} diff --git a/apps/server/prisma/schema.prisma b/apps/server/prisma/schema.prisma new file mode 100644 index 0000000..60b1e32 --- /dev/null +++ b/apps/server/prisma/schema.prisma @@ -0,0 +1,169 @@ +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") +} + +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") +} diff --git a/apps/server/src/app.module.ts b/apps/server/src/app.module.ts new file mode 100644 index 0000000..ee5f2c9 --- /dev/null +++ b/apps/server/src/app.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; + +@Module({ + imports: [], + controllers: [], + providers: [], +}) +export class AppModule {} diff --git a/apps/server/src/main.ts b/apps/server/src/main.ts new file mode 100644 index 0000000..65896d0 --- /dev/null +++ b/apps/server/src/main.ts @@ -0,0 +1,12 @@ +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(); diff --git a/apps/server/tsconfig.json b/apps/server/tsconfig.json new file mode 100644 index 0000000..93651bd --- /dev/null +++ b/apps/server/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "module": "commonjs", + "declaration": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "target": "ES2021", + "sourceMap": true, + "outDir": "./dist", + "baseUrl": "./", + "strict": true, + "skipLibCheck": true, + "paths": { "@/*": ["src/*"] } + }, + "include": ["src"] +} diff --git a/apps/web/app/globals.css b/apps/web/app/globals.css new file mode 100644 index 0000000..b5c61c9 --- /dev/null +++ b/apps/web/app/globals.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx new file mode 100644 index 0000000..5c8fcb4 --- /dev/null +++ b/apps/web/app/layout.tsx @@ -0,0 +1,19 @@ +import './globals.css'; +import type { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'FTB 项目管理', + description: '智能项目管理系统', +}; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx new file mode 100644 index 0000000..377c67d --- /dev/null +++ b/apps/web/app/page.tsx @@ -0,0 +1,7 @@ +export default function HomePage() { + return ( +
+

FTB 项目管理系统

+
+ ); +} diff --git a/apps/web/next.config.js b/apps/web/next.config.js new file mode 100644 index 0000000..6a74afd --- /dev/null +++ b/apps/web/next.config.js @@ -0,0 +1,6 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + transpilePackages: ['@ftb/shared'], +}; + +module.exports = nextConfig; diff --git a/apps/web/package.json b/apps/web/package.json new file mode 100644 index 0000000..652a895 --- /dev/null +++ b/apps/web/package.json @@ -0,0 +1,28 @@ +{ + "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" + } +} diff --git a/apps/web/postcss.config.js b/apps/web/postcss.config.js new file mode 100644 index 0000000..12a703d --- /dev/null +++ b/apps/web/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/apps/web/tailwind.config.ts b/apps/web/tailwind.config.ts new file mode 100644 index 0000000..e5335b0 --- /dev/null +++ b/apps/web/tailwind.config.ts @@ -0,0 +1,9 @@ +import type { Config } from 'tailwindcss'; + +const config: Config = { + content: ['./app/**/*.{ts,tsx}', './components/**/*.{ts,tsx}'], + theme: { extend: {} }, + plugins: [], +}; + +export default config; diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json new file mode 100644 index 0000000..e4effab --- /dev/null +++ b/apps/web/tsconfig.json @@ -0,0 +1,21 @@ +{ + "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"] +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a5671ff --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,21 @@ +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: diff --git a/docs/superpowers/plans/2026-06-08-project-init.md b/docs/superpowers/plans/2026-06-08-project-init.md new file mode 100644 index 0000000..6784cbe --- /dev/null +++ b/docs/superpowers/plans/2026-06-08-project-init.md @@ -0,0 +1,898 @@ +# 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 monorepo,apps/web (Next.js 14 App Router) + apps/server (NestJS),packages/shared 共享类型。PostgreSQL + Prisma ORM,pnpm 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 ( + + {children} + + ); +} +``` + +- [ ] **Step 8: 创建 apps/web/app/page.tsx** + +```tsx +export default function HomePage() { + return ( +
+

FTB 项目管理系统

+
+ ); +} +``` + +- [ ] **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 +``` + +预期:无错误输出。 diff --git a/docs/superpowers/specs/2026-06-08-project-structure-design.md b/docs/superpowers/specs/2026-06-08-project-structure-design.md new file mode 100644 index 0000000..3206dd2 --- /dev/null +++ b/docs/superpowers/specs/2026-06-08-project-structure-design.md @@ -0,0 +1,134 @@ +# FTB 智能项目管理系统 — 项目结构设计 + +## 概述 + +基于 AI 能力的项目管理平台,核心层级:产品 → 项目 → 迭代 → 任务。采用 Turborepo monorepo + Next.js + NestJS + PostgreSQL 技术栈。 + +## 数据层级 + +``` +产品 (Product) — 顶层容器 +├── 需求池 (Requirement) — 需求管理、评审流转 +├── 发布版本 (Version) — v1.0/v2.0,关联多个任务追踪发布范围 +└── 项目 (Project) — 归属于产品 + ├── 迭代 (Sprint) — 时间盒开发周期 + └── 任务 (Task) — 归属迭代,可关联版本 +``` + +## 后端模块划分 + +| 模块 | 职责 | 关键实体 | +|------|------|---------| +| product | 产品 CRUD、需求池管理、需求评审状态流转 | Product, Requirement | +| version | 产品发布版本、版本规划、关联任务范围 | Version | +| project | 项目 CRUD、项目设置 | Project | +| sprint | 迭代管理、迭代规划、燃尽图数据源 | Sprint | +| task | 任务 CRUD、状态机、看板、甘特图、子任务 | Task, Comment, Attachment | +| member | 用户管理、角色分配(RBAC)、项目成员 | User, Role, ProjectMember | +| dashboard | "与我相关"聚合视图 | 无独立实体,聚合查询 | +| ai | 任务智能分解、风险预警、排期建议 | AiLog | +| common | 守卫、拦截器、管道、装饰器 | — | + +## 目录结构 + +``` +ftb-project-management/ +├── apps/ +│ ├── web/ # Next.js 14+ (App Router) +│ │ ├── app/ +│ │ │ ├── (auth)/ # 登录、注册 +│ │ │ ├── workspace/ # "与我相关" +│ │ │ ├── products/ # 产品列表 + 详情 +│ │ │ │ └── [id]/ +│ │ │ │ ├── requirements/ # 需求池 +│ │ │ │ └── versions/ # 版本管理 +│ │ │ ├── projects/ +│ │ │ │ └── [id]/ +│ │ │ │ ├── board/ # 看板 +│ │ │ │ ├── gantt/ # 甘特图 +│ │ │ │ ├── sprints/ # 迭代 +│ │ │ │ └── settings/ # 项目设置+成员 +│ │ │ └── admin/ # 全局管理 +│ │ ├── components/ +│ │ │ ├── ui/ # Shadcn 基础组件 +│ │ │ ├── board/ # 看板组件 +│ │ │ ├── gantt/ # 甘特图组件 +│ │ │ └── shared/ # 通用业务组件 +│ │ ├── hooks/ +│ │ ├── stores/ # Zustand stores +│ │ └── lib/ # 工具函数、API client +│ └── server/ # NestJS 后端 +│ ├── src/ +│ │ ├── modules/ +│ │ │ ├── product/ +│ │ │ ├── version/ +│ │ │ ├── project/ +│ │ │ ├── sprint/ +│ │ │ ├── task/ +│ │ │ ├── member/ +│ │ │ ├── dashboard/ +│ │ │ └── ai/ +│ │ ├── common/ # 守卫、拦截器、管道 +│ │ └── prisma/ # Schema + Migrations +│ └── test/ +├── packages/ +│ └── shared/ # 前后端共享类型、枚举、常量 +├── docker-compose.yml +├── docker-compose.prod.yml +└── turbo.json +``` + +## 前端路由 + +| 路由 | 页面 | +|------|------| +| `/login` | 登录 | +| `/workspace` | "与我相关"(我的任务、我创建的、我关注的) | +| `/products` | 产品列表 | +| `/products/[id]` | 产品详情 | +| `/products/[id]/requirements` | 需求池 | +| `/products/[id]/versions` | 版本管理 | +| `/projects/[id]/board` | 看板 | +| `/projects/[id]/gantt` | 甘特图 | +| `/projects/[id]/sprints` | 迭代管理 | +| `/projects/[id]/settings` | 项目设置 + 成员管理 | +| `/admin/members` | 全局人员管理 | + +## 任务状态机 + +``` +todo → in_progress → in_review → done → closed +``` + +看板列对应状态,支持自定义列名但不改变底层状态枚举。 + +## 关键数据关系 + +- Product 1:N Project(产品下有多个项目) +- Product 1:N Requirement(产品有需求池) +- Product 1:N Version(产品有发布版本) +- Project 1:N Sprint(项目有多个迭代) +- Sprint 1:N Task(迭代包含多个任务) +- Task N:1 Version(任务可关联到某个发布版本) +- Task 自引用(parent_id,无限层级子任务) +- Requirement → Task(需求可一键转为任务) +- Task 有 assignee、creator、watchers + +## 权限模型 + +项目级 RBAC,四个角色: +- **Owner** — 项目所有者,全部权限 +- **Admin** — 管理成员、修改项目设置 +- **Member** — 创建/编辑任务、评论 +- **Viewer** — 只读访问 + +全局管理员可管理所有产品和人员。 + +## AI 模块 + +独立 NestJS Module,统一通过 AiGateway 调用: +- 任务智能分解:输入需求描述,输出结构化子任务列表 +- 风险预警:分析项目延期风险,基于历史数据和当前进度 +- 排期建议:基于成员负载和任务依赖给出时间安排 + +所有 AI 调用记录到 AiLog 表,支持审计和 token 用量追踪。 diff --git a/package.json b/package.json new file mode 100644 index 0000000..8c0c444 --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "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" +} diff --git a/packages/shared/package.json b/packages/shared/package.json new file mode 100644 index 0000000..eda3a0d --- /dev/null +++ b/packages/shared/package.json @@ -0,0 +1,14 @@ +{ + "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" + } +} diff --git a/packages/shared/src/enums.ts b/packages/shared/src/enums.ts new file mode 100644 index 0000000..a13c269 --- /dev/null +++ b/packages/shared/src/enums.ts @@ -0,0 +1,22 @@ +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', +} diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts new file mode 100644 index 0000000..968a286 --- /dev/null +++ b/packages/shared/src/index.ts @@ -0,0 +1,2 @@ +export * from './enums'; +export * from './types'; diff --git a/packages/shared/src/types.ts b/packages/shared/src/types.ts new file mode 100644 index 0000000..8e1e4f9 --- /dev/null +++ b/packages/shared/src/types.ts @@ -0,0 +1,68 @@ +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; +} diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json new file mode 100644 index 0000000..ceabbe9 --- /dev/null +++ b/packages/shared/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "declaration": true, + "outDir": "./dist" + }, + "include": ["src"] +} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..3ff5faa --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +packages: + - "apps/*" + - "packages/*" diff --git a/turbo.json b/turbo.json new file mode 100644 index 0000000..16b3652 --- /dev/null +++ b/turbo.json @@ -0,0 +1,22 @@ +{ + "$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"] + } + } +}