# 第一周开发指南（Day 1-7）

> **目标：** 搭建完整的开发环境，实现第一个功能（用户认证）  
> **时间：** 7天  
> **状态：** 🚀 准备就绪！

---

## ✅ 已完成准备工作

- [x] Docker Desktop 安装完毕
- [x] DeepSeek API Key 已申请
- [x] Qwen API Key 已申请

---

## 📅 本周计划

| 天数 | 任务 | 预计时间 |
|------|------|---------|
| Day 1 | 验证环境 + 创建项目结构 | 2小时 |
| Day 2 | 启动基础服务（Docker） | 1小时 |
| Day 3 | 搭建后端框架 | 3小时 |
| Day 4 | 搭建前端框架 | 3小时 |
| Day 5 | 实现用户认证（后端） | 4小时 |
| Day 6 | 实现登录界面（前端） | 4小时 |
| Day 7 | 测试联调 | 2小时 |

---

## 🎯 Day 1: 验证环境 + 创建项目结构

### 步骤1：验证 Docker 安装

打开终端（Windows用PowerShell或CMD，macOS用Terminal），执行：

```bash
# 检查 Docker 版本
docker --version
# 应输出类似：Docker version 24.0.x

# 检查 Docker Compose 版本
docker-compose --version
# 应输出类似：Docker Compose version v2.x.x

# 检查 Docker 是否运行
docker ps
# 应输出表头（即使没有容器运行）
```

**如果遇到错误：**
- Windows: 确保 Docker Desktop 已启动（系统托盘有Docker图标）
- macOS: 确保 Docker Desktop 已启动

---

### 步骤2：创建项目目录结构

```bash
# 选择一个工作目录（比如 D:\Projects 或 ~/Projects）
cd D:\Projects  # Windows
# 或
cd ~/Projects   # macOS/Linux

# 创建项目根目录
mkdir ai-clinical-research
cd ai-clinical-research

# 创建子目录
mkdir backend frontend config docs

# 验证目录结构
tree -L 1
# 或 Windows: dir
```

**预期结构：**
```
ai-clinical-research/
├── backend/          # 后端代码
├── frontend/         # 前端代码
├── config/           # 配置文件
└── docs/             # 文档
```

---

### 步骤3：创建 docker-compose.yml

在项目根目录创建 `docker-compose.yml`：

```yaml
version: '3.8'

services:
  # PostgreSQL 数据库
  postgres:
    image: postgres:15-alpine
    container_name: acr-postgres
    environment:
      POSTGRES_DB: ai_clinical_research
      POSTGRES_USER: dev_user
      POSTGRES_PASSWORD: dev_pass_2024
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U dev_user -d ai_clinical_research"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Redis 缓存
  redis:
    image: redis:7-alpine
    container_name: acr-redis
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5

  # Dify Sandbox（沙箱环境，Dify依赖）
  dify-sandbox:
    image: langgenius/dify-sandbox:latest
    container_name: acr-dify-sandbox
    restart: unless-stopped

  # Dify API
  dify-api:
    image: langgenius/dify-api:latest
    container_name: acr-dify-api
    environment:
      # 数据库配置
      DB_USERNAME: dify
      DB_PASSWORD: dify_pass_2024
      DB_HOST: dify-postgres
      DB_PORT: 5432
      DB_DATABASE: dify
      
      # Redis配置
      REDIS_HOST: dify-redis
      REDIS_PORT: 6379
      REDIS_DB: 0
      
      # 应用配置
      MODE: api
      SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
      CONSOLE_WEB_URL: http://localhost
      CONSOLE_API_URL: http://localhost:5001
      SERVICE_API_URL: http://localhost:5001
      APP_WEB_URL: http://localhost
      
      # 文件存储（本地）
      STORAGE_TYPE: local
      STORAGE_LOCAL_PATH: /app/storage
      
      # Vector Store（向量数据库）
      VECTOR_STORE: qdrant
      QDRANT_URL: http://dify-qdrant:6333
      QDRANT_API_KEY: dify-qdrant-key
      
      # Celery（异步任务）
      CELERY_BROKER_URL: redis://dify-redis:6379/1
      
      # 模型配置（可选，可在Web界面配置）
      # OPENAI_API_KEY: your-key-here
    ports:
      - "5001:5001"
    volumes:
      - dify_app_storage:/app/storage
    depends_on:
      - dify-postgres
      - dify-redis
      - dify-qdrant
      - dify-sandbox
    restart: unless-stopped

  # Dify Worker（后台任务处理）
  dify-worker:
    image: langgenius/dify-api:latest
    container_name: acr-dify-worker
    environment:
      MODE: worker
      DB_USERNAME: dify
      DB_PASSWORD: dify_pass_2024
      DB_HOST: dify-postgres
      DB_PORT: 5432
      DB_DATABASE: dify
      REDIS_HOST: dify-redis
      REDIS_PORT: 6379
      REDIS_DB: 0
      CELERY_BROKER_URL: redis://dify-redis:6379/1
      SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
      STORAGE_TYPE: local
      STORAGE_LOCAL_PATH: /app/storage
      VECTOR_STORE: qdrant
      QDRANT_URL: http://dify-qdrant:6333
      QDRANT_API_KEY: dify-qdrant-key
    volumes:
      - dify_app_storage:/app/storage
    depends_on:
      - dify-postgres
      - dify-redis
      - dify-qdrant
    restart: unless-stopped

  # Dify PostgreSQL
  dify-postgres:
    image: postgres:15-alpine
    container_name: acr-dify-postgres
    environment:
      POSTGRES_DB: dify
      POSTGRES_USER: dify
      POSTGRES_PASSWORD: dify_pass_2024
      PGDATA: /var/lib/postgresql/data/pgdata
    volumes:
      - dify_postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U dify -d dify"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  # Dify Redis
  dify-redis:
    image: redis:7-alpine
    container_name: acr-dify-redis
    volumes:
      - dify_redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5
    restart: unless-stopped

  # Qdrant 向量数据库
  dify-qdrant:
    image: qdrant/qdrant:latest
    container_name: acr-dify-qdrant
    environment:
      QDRANT__SERVICE__API_KEY: dify-qdrant-key
    ports:
      - "6333:6333"
    volumes:
      - dify_qdrant_data:/qdrant/storage
    restart: unless-stopped

  # Dify Web界面
  dify-web:
    image: langgenius/dify-web:latest
    container_name: acr-dify-web
    environment:
      CONSOLE_API_URL: http://localhost:5001
      APP_API_URL: http://localhost:5001
    ports:
      - "3000:3000"
    depends_on:
      - dify-api
    restart: unless-stopped

volumes:
  postgres_data:
  redis_data:
  dify_postgres_data:
  dify_redis_data:
  dify_qdrant_data:
  dify_app_storage:

networks:
  default:
    name: acr-network
```

**保存文件：** `ai-clinical-research/docker-compose.yml`

---

### 步骤4：创建 .gitignore

在项目根目录创建 `.gitignore`：

```gitignore
# Node modules
node_modules/
*/node_modules/

# Environment variables
.env
.env.local
.env.*.local
*.env

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
Thumbs.db

# Build outputs
dist/
build/
*.log

# Database
*.sqlite
*.db

# API Keys（重要！）
**/config/api-keys.json
backend/config/api-keys.json
```

---

### 步骤5：创建 README.md

在项目根目录创建 `README.md`：

```markdown
# AI科研助手

## 快速启动

### 启动所有服务
\`\`\`bash
docker-compose up -d
\`\`\`

### 查看服务状态
\`\`\`bash
docker-compose ps
\`\`\`

### 查看日志
\`\`\`bash
docker-compose logs -f
\`\`\`

### 停止所有服务
\`\`\`bash
docker-compose down
\`\`\`

## 访问地址

- 前端开发服务器: http://localhost:5173
- 后端API: http://localhost:3001
- Dify Web管理界面: http://localhost:3000
- Dify API: http://localhost:5001
- PostgreSQL: localhost:5432
- Redis: localhost:6379

## 开发文档

详见 `docs/` 目录
```

---

**✅ Day 1 完成检查清单：**
- [ ] Docker 命令验证通过
- [ ] 项目目录创建完成
- [ ] docker-compose.yml 创建完成
- [ ] .gitignore 创建完成
- [ ] README.md 创建完成

---

## 🎯 Day 2: 启动基础服务

### 步骤1：启动 Docker 服务

```bash
# 确保在项目根目录
cd ai-clinical-research

# 启动所有服务（首次启动会下载镜像，需要5-10分钟）
docker-compose up -d

# 查看启动日志
docker-compose logs -f

# 等待所有服务启动完成（约2-3分钟）
# 看到类似信息表示成功：
# acr-dify-api       | INFO: Application startup complete.
# acr-dify-web       | ready - started server on 0.0.0.0:3000
```

**注意：** 首次启动会下载Docker镜像（约2GB），请耐心等待。

---

### 步骤2：验证服务状态

```bash
# 查看所有容器状态
docker-compose ps

# 应该看到所有服务都是 "Up" 状态
# NAME                    STATUS
# acr-postgres            Up (healthy)
# acr-redis               Up (healthy)
# acr-dify-postgres       Up (healthy)
# acr-dify-redis          Up (healthy)
# acr-dify-qdrant         Up
# acr-dify-api            Up
# acr-dify-worker         Up
# acr-dify-web            Up
```

---

### 步骤3：访问 Dify Web 界面

1. 打开浏览器访问：http://localhost:3000
2. 首次访问会要求创建管理员账号
3. 填写信息：
   - 邮箱：admin@example.com
   - 密码：Admin123!（自己设置一个）
   - 确认密码：Admin123!
4. 点击"创建账号"

**成功标志：** 进入Dify管理后台

---

### 步骤4：获取 Dify API Key

1. 在Dify管理后台，点击左侧 "设置" → "API密钥"
2. 点击 "创建密钥"
3. 复制生成的API Key（类似：`app-xxx...`）
4. 保存到安全的地方（后面会用到）

---

### 步骤5：测试数据库连接

```bash
# 测试 PostgreSQL（业务数据库）
docker exec -it acr-postgres psql -U dev_user -d ai_clinical_research -c "SELECT version();"

# 应输出 PostgreSQL 版本信息

# 测试 Redis
docker exec -it acr-redis redis-cli ping
# 应输出: PONG

# 测试 Dify API
curl http://localhost:5001/health
# 应输出: {"status":"ok"}
```

---

**✅ Day 2 完成检查清单：**
- [ ] 所有Docker容器启动成功
- [ ] Dify Web界面可访问
- [ ] Dify管理员账号创建完成
- [ ] Dify API Key获取完成
- [ ] 数据库连接测试通过

---

## 🎯 Day 3: 搭建后端框架

### 步骤1：初始化后端项目

```bash
# 进入后端目录
cd backend

# 初始化 Node.js 项目
npm init -y

# 安装依赖
npm install fastify@4.26.0 \
  @fastify/cors@9.0.0 \
  @fastify/jwt@7.2.0 \
  @prisma/client@5.10.0 \
  bcryptjs@2.4.3 \
  dotenv@16.4.0 \
  ioredis@5.3.0 \
  axios@1.6.0

# 安装开发依赖
npm install -D \
  prisma@5.10.0 \
  typescript@5.3.0 \
  @types/node@20.11.0 \
  @types/bcryptjs@2.4.6 \
  tsx@4.7.0 \
  nodemon@3.0.0
```

---

### 步骤2：配置 TypeScript

创建 `backend/tsconfig.json`：

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "commonjs",
    "lib": ["ES2022"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "moduleResolution": "node"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}
```

---

### 步骤3：配置环境变量

创建 `backend/.env`：

```bash
# 数据库配置
DATABASE_URL="postgresql://dev_user:dev_pass_2024@localhost:5432/ai_clinical_research"

# Redis配置
REDIS_URL="redis://localhost:6379"

# JWT配置
JWT_SECRET="your-super-secret-jwt-key-change-this-in-production-2024"
JWT_EXPIRES_IN="7d"

# LLM API Keys
DEEPSEEK_API_KEY="你的DeepSeek API Key"
DASHSCOPE_API_KEY="你的Qwen API Key"

# Dify配置
DIFY_API_URL="http://localhost:5001"
DIFY_API_KEY="你在Day2获取的Dify API Key"

# 应用配置
NODE_ENV="development"
PORT=3001
```

**注意：** 把"你的XXX API Key"替换成你实际申请的Key

---

### 步骤4：初始化 Prisma

```bash
# 初始化 Prisma
npx prisma init

# 这会创建 prisma/schema.prisma 文件
```

编辑 `backend/prisma/schema.prisma`：

```prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

// 用户表
model User {
  id        String   @id @default(uuid())
  email     String   @unique
  password  String
  name      String?
  role      String   @default("user") // user, admin
  status    String   @default("active") // active, inactive
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  // 关联
  projects  Project[]
  knowledgeBases KnowledgeBase[]

  @@map("users")
}

// 项目/课题表
model Project {
  id          String   @id @default(uuid())
  userId      String
  name        String
  description String   @db.Text
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  // 关联
  user        User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  conversations Conversation[]

  @@map("projects")
}

// 对话表
model Conversation {
  id        String   @id @default(uuid())
  projectId String?
  userId    String
  agentId   String
  title     String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  // 关联
  project   Project? @relation(fields: [projectId], references: [id], onDelete: Cascade)
  messages  Message[]

  @@map("conversations")
}

// 消息表
model Message {
  id             String   @id @default(uuid())
  conversationId String
  role           String   // user, assistant
  content        String   @db.Text
  createdAt      DateTime @default(now())

  // 关联
  conversation   Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)

  @@map("messages")
}

// 知识库表
model KnowledgeBase {
  id             String   @id @default(uuid())
  userId         String
  name           String
  description    String?
  difyDatasetId  String   // Dify中的知识库ID
  fileCount      Int      @default(0)
  totalSizeBytes BigInt   @default(0)
  createdAt      DateTime @default(now())
  updatedAt      DateTime @updatedAt

  // 关联
  user           User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  documents      Document[]

  @@map("knowledge_bases")
}

// 文档表
model Document {
  id              String   @id @default(uuid())
  kbId            String
  userId          String
  filename        String
  fileType        String
  fileSizeBytes   BigInt
  fileUrl         String
  difyDocumentId  String
  status          String   @default("uploading") // uploading, processing, completed, failed
  progress        Int      @default(0)
  errorMessage    String?
  segmentsCount   Int?
  tokensCount     Int?
  uploadedAt      DateTime @default(now())
  processedAt     DateTime?

  // 关联
  knowledgeBase   KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)

  @@map("documents")
}
```

---

### 步骤5：创建数据库表

```bash
# 生成 Prisma Client
npx prisma generate

# 创建数据库迁移
npx prisma migrate dev --name init

# 看到类似输出表示成功：
# ✔ Generated Prisma Client
# ✔ Your database is now in sync with your schema.
```

---

### 步骤6：创建基础目录结构

```bash
# 在 backend 目录下创建
mkdir -p src/routes src/services src/config src/utils src/types
```

---

### 步骤7：创建服务器入口文件

创建 `backend/src/server.ts`：

```typescript
import Fastify from 'fastify';
import cors from '@fastify/cors';
import dotenv from 'dotenv';

// 加载环境变量
dotenv.config();

const server = Fastify({
  logger: true
});

// 注册CORS
server.register(cors, {
  origin: true // 开发环境允许所有来源
});

// 健康检查端点
server.get('/health', async (request, reply) => {
  return { status: 'ok', timestamp: new Date().toISOString() };
});

// 测试端点
server.get('/api/test', async (request, reply) => {
  return { 
    message: 'AI科研助手后端服务运行正常！',
    env: process.env.NODE_ENV,
    timestamp: new Date().toISOString()
  };
});

// 启动服务器
const start = async () => {
  try {
    const port = parseInt(process.env.PORT || '3001');
    await server.listen({ port, host: '0.0.0.0' });
    console.log(`🚀 服务器启动成功！`);
    console.log(`📝 API地址: http://localhost:${port}`);
    console.log(`🏥 健康检查: http://localhost:${port}/health`);
  } catch (err) {
    server.log.error(err);
    process.exit(1);
  }
};

start();
```

---

### 步骤8：配置 package.json scripts

编辑 `backend/package.json`，添加 scripts：

```json
{
  "scripts": {
    "dev": "tsx watch src/server.ts",
    "build": "tsc",
    "start": "node dist/server.js",
    "prisma:generate": "prisma generate",
    "prisma:migrate": "prisma migrate dev",
    "prisma:studio": "prisma studio"
  }
}
```

---

### 步骤9：启动后端服务

```bash
# 启动开发服务器
npm run dev

# 看到类似输出表示成功：
# 🚀 服务器启动成功！
# 📝 API地址: http://localhost:3001
# 🏥 健康检查: http://localhost:3001/health
```

---

### 步骤10：测试后端API

打开新的终端窗口：

```bash
# 测试健康检查
curl http://localhost:3001/health

# 测试API
curl http://localhost:3001/api/test
```

---

**✅ Day 3 完成检查清单：**
- [ ] 后端项目初始化完成
- [ ] 依赖安装完成
- [ ] TypeScript配置完成
- [ ] 环境变量配置完成
- [ ] Prisma数据库模型创建完成
- [ ] 数据库迁移成功
- [ ] 后端服务启动成功
- [ ] API测试通过

---

## 🎯 Day 4-7: 继续开发...

（后续天数的详细步骤将在您完成Day 1-3后提供）

---

## 📊 当前进度

```
✅ 环境准备: 100%
⏳ Day 1: 待开始
⏳ Day 2: 待开始
⏳ Day 3: 待开始
```

---

## 🆘 常见问题

### Q1: Docker 容器启动失败
```bash
# 查看日志
docker-compose logs [服务名]

# 重启服务
docker-compose restart [服务名]

# 完全重置
docker-compose down -v
docker-compose up -d
```

### Q2: 端口被占用
```bash
# Windows 查找占用端口的进程
netstat -ano | findstr :3001

# macOS/Linux
lsof -i :3001

# 修改端口（在 .env 中）
PORT=3002
```

### Q3: npm install 太慢
```bash
# 使用国内镜像
npm config set registry https://registry.npmmirror.com
```

---

## 🎉 准备开始！

**现在就开始 Day 1 吧！**

执行第一个命令：
```bash
docker --version
```

有任何问题随时告诉我！🚀




