# 后端模块重构实施指南

## 概述

本指南提供了完整的后端模块重构步骤和代码示例。重构涉及：
- 创建 50+ 个新文件
- 修改所有 Controller 的路由前缀
- 更新前端 API 调用路径
- 创建新的模块组织结构

## 一、快速开始

### 方案选择

**方案A：手动逐步执行**（推荐，风险低）
- 按照本文档逐个模块迁移
- 每完成一个端就测试验证
- 适合希望完全掌控过程的团队

**方案B：使用自动化脚本**（快速，需要验证）
- 使用提供的 Node.js 脚本批量迁移
- 完成后统一测试和修复
- 适合有经验的团队

**方案C：AI辅助完成**（平衡）
- AI 创建关键示例和模板
- 人工复制粘贴并调整其他模块
- 本文档提供所有必要的模板

## 二、目录结构

```
apps/server/src/modules/
├── user/                    # 用户端（C端）
│   ├── auth/
│   │   ├── auth.controller.ts
│   │   ├── auth.service.ts
│   │   ├── auth.module.ts
│   │   └── dto/
│   ├── profile/
│   ├── guest/
│   ├── order/
│   ├── review/
│   ├── coupon/
│   ├── finance/
│   ├── activity/
│   └── user.module.ts       # 用户端总模块
│
├── merchant/                # 商家端（B端）
│   ├── auth/
│   ├── profile/
│   ├── room/
│   ├── room-calendar/
│   ├── order/
│   ├── review/
│   ├── finance/
│   ├── statistics/
│   └── merchant.module.ts   # 商家端总模块
│
├── admin/                   # 平台管理端
│   ├── auth/
│   ├── user/
│   ├── merchant/
│   ├── room/
│   ├── order/
│   ├── review/
│   ├── coupon/
│   ├── activity/
│   ├── config/
│   ├── finance/
│   ├── website/
│   └── admin.module.ts      # 管理端总模块
│
├── website/                 # 官网
│   ├── info/
│   └── website.module.ts
│
└── shared/                  # 公共模块
    ├── room/
    ├── merchant/
    ├── activity/
    ├── upload/
    └── shared.module.ts
```

## 三、路由前缀映射表

### 用户端
| 旧路由 | 新路由 | 说明 |
|--------|--------|------|
| `/auth/*` | `/api/user/auth/*` | 用户认证 |
| `/user/*` | `/api/user/profile/*` | 个人信息 |
| `/user/guests` | `/api/user/guests` | 入住人管理 |
| `/orders` | `/api/user/orders` | 用户订单 |
| `/reviews` | `/api/user/reviews` | 用户评价 |
| `/user/coupons` | `/api/user/coupons` | 用户优惠券 |
| `/user/finance` | `/api/user/finance` | 用户财务 |
| `/user/activity/invite` | `/api/user/activity/invite` | 邀请活动 |

### 商家端
| 旧路由 | 新路由 | 说明 |
|--------|--------|------|
| `/seller/auth/*` | `/api/merchant/auth/*` | 商家认证 |
| `/seller/merchant` | `/api/merchant/profile` | 商家信息 |
| `/seller/statistics` | `/api/merchant/statistics` | 数据统计 |
| `/seller/rooms` | `/api/merchant/rooms` | 房源管理 |
| `/seller/room-calendar` | `/api/merchant/room-calendar` | 房量房价 |
| `/seller/orders` | `/api/merchant/orders` | 商家订单 |
| `/seller/reviews` | `/api/merchant/reviews` | 商家评价 |
| `/merchant/finance/*` | `/api/merchant/finance/*` | 商家财务 |

### 平台管理端
| 旧路由 | 新路由 | 说明 |
|--------|--------|------|
| `/admin/auth/*` | `/api/admin/auth/*` | 管理员认证 |
| `/admin/users` | `/api/admin/users` | 用户管理 |
| `/admin/merchants` | `/api/admin/merchants` | 商家管理 |
| `/admin/rooms` | `/api/admin/rooms` | 房源审核 |
| `/admin/orders` | `/api/admin/orders` | 订单管理 |
| `/admin/reviews` | `/api/admin/reviews` | 评价审核 |
| `/admin/coupons` | `/api/admin/coupons` | 优惠券管理 |
| `/admin/activity` | `/api/admin/activity` | 活动管理 |
| `/admin/config` | `/api/admin/config` | 系统配置 |
| `/admin/finance/*` | `/api/admin/finance/*` | 财务管理 |

### 公共接口
| 旧路由 | 新路由 | 说明 |
|--------|--------|------|
| `/rooms` | `/api/public/rooms` | 房源公开查询 |
| `/merchants` | `/api/public/merchants` | 商家公开信息 |
| `/activity` | `/api/public/activity` | 活动公开信息 |
| `/upload` | `/api/user/upload` | 用户上传 |
| `/seller/upload` | `/api/merchant/upload` | 商家上传 |
| `/admin/upload` | `/api/admin/upload` | 管理员上传 |

## 四、代码模板

### 1. Controller 模板（用户端认证示例）

**文件位置**: `apps/server/src/modules/user/auth/auth.controller.ts`

```typescript
import { Controller, Post, Body, UseGuards, Get, Req } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { AuthService } from './auth.service';
import {
  LoginByPhoneDto,
  LoginByPasswordDto,
  RegisterDto,
  SendCodeDto,
  WechatLoginDto,
} from './dto/auth.dto';
import { JwtAuthGuard } from '@/common/guards/jwt-auth.guard';

@ApiTags('用户认证')
@Controller('api/user/auth')  // ⚠️ 关键：新的路由前缀
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @Post('send-code')
  @ApiOperation({ summary: '发送验证码' })
  async sendCode(@Body() dto: SendCodeDto) {
    return this.authService.sendCode(dto.phone);
  }

  @Post('login/phone')
  @ApiOperation({ summary: '手机号验证码登录' })
  async loginByPhone(@Body() dto: LoginByPhoneDto) {
    return this.authService.loginByPhone(dto);
  }

  @Post('login/password')
  @ApiOperation({ summary: '账号密码登录' })
  async loginByPassword(@Body() dto: LoginByPasswordDto) {
    return this.authService.loginByPassword(dto);
  }

  @Post('login/wechat')
  @ApiOperation({ summary: '微信授权登录' })
  async loginByWechat(@Body() dto: WechatLoginDto) {
    return this.authService.loginByWechat(dto);
  }

  @Post('register')
  @ApiOperation({ summary: '用户注册' })
  async register(@Body() dto: RegisterDto) {
    return this.authService.register(dto);
  }

  @Post('refresh')
  @ApiOperation({ summary: '刷新令牌' })
  async refresh(@Body('refreshToken') refreshToken: string) {
    return this.authService.refresh(refreshToken);
  }

  @Get('profile')
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth()
  @ApiOperation({ summary: '获取当前用户信息' })
  async getProfile(@Req() req) {
    return req.user;
  }
}
```

### 2. Module 模板（子模块）

**文件位置**: `apps/server/src/modules/user/auth/auth.module.ts`

```typescript
import { Module, Global } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { User } from '@/entities/user.entity';
import { UserAccount } from '@/entities/user-account.entity';

@Global()
@Module({
  imports: [
    TypeOrmModule.forFeature([User, UserAccount]),
    JwtModule.registerAsync({
      imports: [ConfigModule],
      useFactory: (configService: ConfigService) => ({
        secret: configService.get<string>('jwt.secret') || 'dev_secret_key',
        signOptions: {
          expiresIn: configService.get<string>('jwt.expiresIn') || '7d',
        },
      }),
      inject: [ConfigService],
    }),
  ],
  controllers: [AuthController],
  providers: [AuthService],
  exports: [AuthService, JwtModule],
})
export class UserAuthModule {}  // ⚠️ 重命名避免冲突
```

### 3. 端总模块模板

**文件位置**: `apps/server/src/modules/user/user.module.ts`

```typescript
import { Module } from '@nestjs/common';
import { UserAuthModule } from './auth/auth.module';
import { UserProfileModule } from './profile/profile.module';
import { UserGuestModule } from './guest/guest.module';
import { UserOrderModule } from './order/order.module';
import { UserReviewModule } from './review/review.module';
import { UserCouponModule } from './coupon/coupon.module';
import { UserFinanceModule } from './finance/finance.module';
import { UserActivityModule } from './activity/activity.module';

@Module({
  imports: [
    UserAuthModule,
    UserProfileModule,
    UserGuestModule,
    UserOrderModule,
    UserReviewModule,
    UserCouponModule,
    UserFinanceModule,
    UserActivityModule,
  ],
})
export class UserModule {}
```

### 4. 根模块更新

**文件位置**: `apps/server/src/app.module.ts`

```typescript
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserModule } from './modules/user/user.module';
import { MerchantModule } from './modules/merchant/merchant.module';
import { AdminModule } from './modules/admin/admin.module';
import { WebsiteModule } from './modules/website/website.module';
import { SharedModule } from './modules/shared/shared.module';
// ... 其他导入

@Module({
  imports: [
    ConfigModule.forRoot(/* ... */),
    TypeOrmModule.forRoot(/* ... */),
    UserModule,        // 用户端
    MerchantModule,    // 商家端
    AdminModule,       // 管理端
    WebsiteModule,     // 官网
    SharedModule,      // 公共模块
    // 删除旧的模块导入
  ],
})
export class AppModule {}
```

## 五、前端 API 路径更新

### 小程序 (miniapp)

**文件**: `apps/miniapp/src/api/auth.ts`

```typescript
// 旧代码
export function login(data: any) {
  return request.post('/auth/login/phone', data);
}

// 新代码
export function login(data: any) {
  return request.post('/api/user/auth/login/phone', data);
}
```

### 批量替换规则（使用 VS Code 全局搜索替换）

**用户端接口**:
- 搜索: `'/auth/`
- 替换: `'/api/user/auth/`

- 搜索: `'/user/`
- 替换: `'/api/user/profile/`

- 搜索: `'/orders`
- 替换: `'/api/user/orders`

**商家端接口**:
- 搜索: `'/seller/auth/`
- 替换: `'/api/merchant/auth/`

- 搜索: `'/seller/`
- 替换: `'/api/merchant/`

- 搜索: `'/merchant/finance/`
- 替换: `'/api/merchant/finance/`

**管理端接口**:
- 搜索: `'/admin/`
- 替换: `'/api/admin/`

**公共接口**:
- 搜索: `'/rooms`
- 替换: `'/api/public/rooms`

- 搜索: `'/merchants`
- 替换: `'/api/public/merchants`

## 六、官网模块实现

### 1. 创建 WebsiteInfo 实体

**文件**: `apps/server/src/entities/website-info.entity.ts`

```typescript
import {
  Entity,
  PrimaryGeneratedColumn,
  Column,
  CreateDateColumn,
  UpdateDateColumn,
} from 'typeorm';

@Entity('website_info')
export class WebsiteInfo {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ name: 'site_name', length: 100 })
  siteName: string;

  @Column({ name: 'site_title', length: 200 })
  siteTitle: string;

  @Column({ name: 'site_description', type: 'text' })
  siteDescription: string;

  @Column({ name: 'site_keywords', length: 500 })
  siteKeywords: string;

  @Column({ length: 500 })
  logo: string;

  @Column({ length: 500 })
  favicon: string;

  @Column({ name: 'contact_phone', length: 50 })
  contactPhone: string;

  @Column({ name: 'contact_email', length: 100 })
  contactEmail: string;

  @Column({ name: 'contact_address', length: 500 })
  contactAddress: string;

  @Column({ length: 100 })
  icp: string;

  @Column({ type: 'text' })
  copyright: string;

  @Column({ name: 'about_us', type: 'text' })
  aboutUs: string;

  @Column({ name: 'service_agreement', type: 'text' })
  serviceAgreement: string;

  @Column({ name: 'privacy_policy', type: 'text' })
  privacyPolicy: string;

  @Column({ name: 'social_links', type: 'json', nullable: true })
  socialLinks: Record<string, string>;

  @Column({
    type: 'enum',
    enum: ['active', 'inactive'],
    default: 'active',
  })
  status: 'active' | 'inactive';

  @CreateDateColumn({ name: 'created_at' })
  createdAt: Date;

  @UpdateDateColumn({ name: 'updated_at' })
  updatedAt: Date;
}
```

### 2. 数据库迁移脚本

**文件**: `database/migrations/002_create_website_info.sql`

```sql
CREATE TABLE IF NOT EXISTS `website_info` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `site_name` VARCHAR(100) NOT NULL COMMENT '网站名称',
  `site_title` VARCHAR(200) NOT NULL COMMENT '网站标题',
  `site_description` TEXT NOT NULL COMMENT '网站描述',
  `site_keywords` VARCHAR(500) NOT NULL COMMENT 'SEO关键词',
  `logo` VARCHAR(500) NOT NULL COMMENT 'Logo URL',
  `favicon` VARCHAR(500) NOT NULL COMMENT '网站图标',
  `contact_phone` VARCHAR(50) NOT NULL COMMENT '联系电话',
  `contact_email` VARCHAR(100) NOT NULL COMMENT '联系邮箱',
  `contact_address` VARCHAR(500) NOT NULL COMMENT '联系地址',
  `icp` VARCHAR(100) NOT NULL COMMENT 'ICP备案号',
  `copyright` TEXT NOT NULL COMMENT '版权信息',
  `about_us` TEXT COMMENT '关于我们',
  `service_agreement` TEXT COMMENT '服务协议',
  `privacy_policy` TEXT COMMENT '隐私政策',
  `social_links` JSON COMMENT '社交媒体链接',
  `status` ENUM('active', 'inactive') DEFAULT 'active' COMMENT '状态',
  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  INDEX `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='网站信息表';

-- 插入默认数据
INSERT INTO `website_info` (
  `site_name`, `site_title`, `site_description`, `site_keywords`,
  `logo`, `favicon`, `contact_phone`, `contact_email`, `contact_address`,
  `icp`, `copyright`, `about_us`, `service_agreement`, `privacy_policy`
) VALUES (
  '租赁平台', '租赁平台 - 您的租赁服务专家', '提供优质的租赁服务', '租赁,房屋租赁,短租',
  '', '', '400-000-0000', 'contact@example.com', '北京市朝阳区',
  '京ICP备00000000号', '© 2024 租赁平台 版权所有', '关于我们的内容...', '服务协议内容...', '隐私政策内容...'
);
```

### 3. WebsiteInfo Service

**文件**: `apps/server/src/modules/website/info/info.service.ts`

```typescript
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { WebsiteInfo } from '@/entities/website-info.entity';

@Injectable()
export class WebsiteInfoService {
  constructor(
    @InjectRepository(WebsiteInfo)
    private websiteInfoRepo: Repository<WebsiteInfo>,
  ) {}

  async getInfo(): Promise<WebsiteInfo> {
    // 获取第一条记录（通常只有一条）
    const info = await this.websiteInfoRepo.findOne({
      where: { status: 'active' },
      order: { id: 'ASC' },
    });

    if (!info) {
      throw new Error('网站信息未配置');
    }

    return info;
  }

  async updateInfo(data: Partial<WebsiteInfo>): Promise<WebsiteInfo> {
    const info = await this.getInfo();
    Object.assign(info, data);
    return this.websiteInfoRepo.save(info);
  }
}
```

### 4. WebsiteInfo Controller（公开接口）

**文件**: `apps/server/src/modules/website/info/info.controller.ts`

```typescript
import { Controller, Get } from '@nestjs/common';
import { ApiTags, ApiOperation } from '@nestjs/swagger';
import { WebsiteInfoService } from './info.service';

@ApiTags('网站信息')
@Controller('api/website/info')
export class WebsiteInfoController {
  constructor(private readonly websiteInfoService: WebsiteInfoService) {}

  @Get()
  @ApiOperation({ summary: '获取网站信息' })
  async getInfo() {
    return this.websiteInfoService.getInfo();
  }
}
```

### 5. WebsiteInfo 管理接口

**文件**: `apps/server/src/modules/admin/website/website.controller.ts`

```typescript
import { Controller, Put, Body, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { JwtAuthGuard } from '@/common/guards/jwt-auth.guard';
import { RolesGuard } from '@/common/guards/roles.guard';
import { Roles } from '@/common/decorators/roles.decorator';
import { WebsiteInfoService } from '@/modules/website/info/info.service';

@ApiTags('网站管理')
@Controller('api/admin/website/info')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@ApiBearerAuth()
export class AdminWebsiteController {
  constructor(private readonly websiteInfoService: WebsiteInfoService) {}

  @Put()
  @ApiOperation({ summary: '更新网站信息' })
  async updateInfo(@Body() data: any) {
    return this.websiteInfoService.updateInfo(data);
  }
}
```

## 七、执行步骤

### 步骤1：创建目录结构
```bash
cd d:/project/company/rent/apps/server/src/modules
mkdir -p user/{auth,profile,guest,order,review,coupon,finance,activity}
mkdir -p merchant/{auth,profile,room,room-calendar,order,review,finance,statistics}
mkdir -p admin/{auth,user,merchant,room,order,review,coupon,activity,config,finance,website}
mkdir -p website/info
mkdir -p shared/{room,merchant,activity,upload}
```

### 步骤2：复制并修改文件
对于每个模块：
1. 复制原文件到新位置
2. 修改 Controller 的 `@Controller()` 装饰器路由前缀
3. 如果是 Module 文件，重命名类名避免冲突（如 `AuthModule` → `UserAuthModule`）
4. 复制 Service 和 DTO 文件（通常不需要修改）

### 步骤3：创建端总模块
为每个端创建总模块文件（user.module.ts, merchant.module.ts, admin.module.ts等）

### 步骤4：更新 app.module.ts
导入新的四个端模块，删除旧模块导入

### 步骤5：创建官网模块
1. 创建 WebsiteInfo 实体
2. 运行数据库迁移
3. 创建 Service、Controller
4. 创建管理接口

### 步骤6：更新前端 API 路径
使用 VS Code 全局搜索替换，按照第五节的规则批量替换

### 步骤7：测试验证
1. 启动后端服务
2. 检查 Swagger 文档
3. 测试各端的核心接口
4. 启动三个前端应用测试

### 步骤8：清理旧模块
确认新模块工作正常后，删除旧的模块文件

## 八、常见问题

### Q1: 模块导入路径错误
**问题**: Service 或 Entity 导入路径找不到
**解决**: 使用绝对路径 `@/entities/...` 或 `@/modules/...`

### Q2: 模块名称冲突
**问题**: 多个模块都叫 `AuthModule`
**解决**: 重命名为 `UserAuthModule`, `MerchantAuthModule`, `AdminAuthModule`

### Q3: 前端接口404
**问题**: 前端调用新接口返回404
**解决**: 检查是否遗漏了某些路径的替换，特别注意动态路径

### Q4: Guards 不生效
**问题**: 认证守卫没有正确应用
**解决**: 确保 JwtModule 在对应的 Auth Module 中正确导出

## 九、验证清单

- [ ] 后端服务启动无错误
- [ ] Swagger 文档显示所有新接口
- [ ] 用户端接口测试通过（登录、下单、支付等）
- [ ] 商家端接口测试通过（登录、房源管理、订单处理等）
- [ ] 管理端接口测试通过（登录、审核、财务管理等）
- [ ] 公共接口测试通过（房源列表、商家列表等）
- [ ] 官网接口测试通过（获取网站信息）
- [ ] 小程序正常运行
- [ ] 商家后台正常运行
- [ ] 平台后台正常运行
- [ ] 旧模块已删除
- [ ] 代码已提交到版本控制

## 十、回滚方案

如果重构出现问题需要回滚：
1. 使用 git 恢复到重构前的提交
2. 或者保留旧模块，在 app.module.ts 中切换回旧模块
3. 前端恢复旧的 API 路径

建议：在开始重构前创建一个 git 分支，确保可以随时回滚。
