267 lines
11 KiB
Markdown
267 lines
11 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
**MemeMind-Server** is a NestJS backend for a WeChat mini-game called MemeMind. The server handles user authentication via WeChat login, manages game levels and progress, supports social sharing/challenges, and maintains user profiles. All API responses use a standardized format and are exposed under `/api` with Swagger docs at `/api/docs`.
|
|
|
|
## Tech Stack
|
|
|
|
- **Framework**: NestJS 11 with TypeScript 5.7
|
|
- **Database**: MySQL (via TypeORM)
|
|
- **Authentication**: JWT (7-day expiration)
|
|
- **Package Manager**: pnpm (with pnpm-lock.yaml)
|
|
- **Testing**: Jest (unit tests alongside source, e2e tests in `test/`)
|
|
- **Code Quality**: ESLint + Prettier (single quotes, trailing commas)
|
|
- **Deployment**: PM2 with rsync to remote server
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
src/
|
|
├── main.ts # App bootstrap (CORS, validation, Swagger)
|
|
├── app.module.ts # Root module importing all features
|
|
├── config/
|
|
│ ├── config.module.ts # Global config provider (env validation)
|
|
│ ├── env.validation.ts # Environment variable schema validation
|
|
│ └── database.config.ts # TypeORM configuration
|
|
├── database/
|
|
│ └── migrations/ # TypeORM migrations (not heavily used yet)
|
|
├── common/
|
|
│ ├── dto/api-response.dto.ts # Unified response wrapper (success/error)
|
|
│ ├── filters/http-exception.filter.ts # Global error handling
|
|
│ ├── guards/jwt-auth.guard.ts # JWT verification & payload extraction
|
|
│ └── decorators/current-user.decorator.ts # Param decorator for @CurrentUser()
|
|
└── modules/
|
|
├── auth/ # WeChat login, user creation, JWT issuance
|
|
├── user/ # User profile and stamina management
|
|
├── level/ # Game level progression tracking
|
|
├── share/ # Social challenge/share features
|
|
├── game-config/ # Game configuration endpoints
|
|
└── wechat-game/ # Shared game entities and repositories
|
|
|
|
docs/
|
|
├── api/ # API documentation (Markdown, auto-synced with code)
|
|
├── api/README.md # Index of all API modules
|
|
└── superpowers/ # Legacy or undocumented features
|
|
```
|
|
|
|
## Key Commands
|
|
|
|
### Development
|
|
|
|
```bash
|
|
pnpm install # Install dependencies
|
|
pnpm run start:dev # Run with file watching (http://localhost:3000/api)
|
|
pnpm run start:debug # Debug mode with Node inspector
|
|
pnpm run build # Compile TypeScript to dist/
|
|
pnpm run start:prod # Run compiled production build
|
|
```
|
|
|
|
### Code Quality
|
|
|
|
```bash
|
|
pnpm run lint # ESLint with auto-fix
|
|
pnpm run format # Prettier format (src/ and test/)
|
|
```
|
|
|
|
### Testing
|
|
|
|
```bash
|
|
pnpm run test # All unit tests (*.spec.ts in src/)
|
|
pnpm run test:watch # Watch mode
|
|
pnpm run test:cov # Coverage report (outputs to coverage/)
|
|
pnpm run test:debug # Debug unit tests
|
|
pnpm run test:e2e # E2E tests (test/*.e2e-spec.ts)
|
|
```
|
|
|
|
### Deployment
|
|
|
|
```bash
|
|
pnpm run deploy # Build, rsync to server, restart PM2 cluster
|
|
```
|
|
|
|
## Architecture Patterns
|
|
|
|
### Module Structure
|
|
|
|
Each feature module follows NestJS conventions:
|
|
|
|
```typescript
|
|
// module.ts: Declares imports (other modules, TypeORM entities, services)
|
|
@Module({
|
|
imports: [TypeOrmModule.forFeature([Entity]), AuthModule],
|
|
controllers: [FeatureController],
|
|
providers: [FeatureService, CustomRepository],
|
|
exports: [FeatureService], // For cross-module injection
|
|
})
|
|
export class FeatureModule {}
|
|
|
|
// controller.ts: HTTP routing, DTO validation, Swagger decorators
|
|
@Controller('v1/feature')
|
|
export class FeatureController {
|
|
@Post() async create(@Body() dto: CreateDto): Promise<ApiResponseDto<ResponseDto>>
|
|
@UseGuards(JwtAuthGuard) // Applied per-endpoint
|
|
@Get(':id') async getOne(@Param('id') id: string, @CurrentUser() user: JwtPayload)
|
|
}
|
|
|
|
// service.ts: Business logic, repository calls, external API calls
|
|
@Injectable()
|
|
export class FeatureService {
|
|
constructor(private readonly repo: CustomRepository) {}
|
|
async create(data: CreateDto): Promise<ResponseDto> { ... }
|
|
}
|
|
|
|
// repositories/: Custom data access logic (extend TypeORM repositories)
|
|
@Injectable()
|
|
export class CustomRepository extends Repository<Entity> {
|
|
async customQuery(): Promise<Entity[]> { ... }
|
|
}
|
|
|
|
// dto/: Request/response schemas with class-validator decorators
|
|
export class CreateDto {
|
|
@IsString() @MinLength(1) name: string;
|
|
}
|
|
```
|
|
|
|
### Authentication & Authorization
|
|
|
|
- **No global guard**: JWT validation is per-endpoint via `@UseGuards(JwtAuthGuard)`
|
|
- **User extraction**: Use `@CurrentUser()` to inject `JwtPayload { sub: userId, openid }`
|
|
- **WeChat integration**: `AuthService.wxLogin(code)` calls WeChat API, creates user on first login, issues JWT
|
|
|
|
### Request/Response Contract
|
|
|
|
All endpoints return `ApiResponseDto<T>`:
|
|
|
|
```typescript
|
|
{
|
|
success: boolean, // true on success, false on error
|
|
data: T | null, // Response payload or null
|
|
message: string | null, // Error message (null on success)
|
|
timestamp: Date // ISO 8601 timestamp
|
|
}
|
|
```
|
|
|
|
Errors are caught by `HttpExceptionFilter`, which formats exceptions as failed responses.
|
|
|
|
### Database
|
|
|
|
- **ORM**: TypeORM with MySQL
|
|
- **Entities**: Auto-loaded from `**/*.entity.ts`, sync mode in dev
|
|
- **Migrations**: Located in `src/database/migrations/` (minimal usage)
|
|
- **Connection**: Configured via `ConfigService` (env vars: DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD, DB_DATABASE)
|
|
|
|
## Configuration
|
|
|
|
Environment variables are validated via `env.validation.ts` using class-validator:
|
|
|
|
```
|
|
NODE_ENV # development|production|test (default: development)
|
|
PORT # Server port (default: 3000)
|
|
DB_HOST # MySQL host (default: localhost)
|
|
DB_PORT # MySQL port (default: 3306)
|
|
DB_USERNAME # MySQL user (default: meme_user)
|
|
DB_PASSWORD # MySQL password (default: '')
|
|
DB_DATABASE # MySQL database (default: meme_mind)
|
|
WX_APPID # WeChat mini-game app ID
|
|
WX_SECRET # WeChat mini-game secret
|
|
JWT_SECRET # JWT signing secret
|
|
```
|
|
|
|
Config files loaded in order: `.env.local` → `.env` → `.env.production`. Use `.env.local` for local overrides (never committed).
|
|
|
|
## Testing
|
|
|
|
- **Unit tests**: Colocated with source as `*.spec.ts` (e.g., `auth.service.spec.ts`)
|
|
- **E2E tests**: In `test/` directory (e.g., `test/app.e2e-spec.ts`)
|
|
- **Framework**: Jest with ts-jest compiler
|
|
- **Coverage**: Run `pnpm run test:cov` to generate coverage report in `coverage/`
|
|
- **Individual tests**: `pnpm run test -- --testNamePattern="test name"` or `pnpm run test:debug`
|
|
|
|
## API Documentation
|
|
|
|
API docs are maintained in `docs/api/` and **must be updated whenever controller/DTO changes occur**. The `api-doc-maintainer` skill automates this when editing `src/modules/*/`.
|
|
|
|
**File mapping**:
|
|
- `docs/api/auth-api.md` → `src/modules/auth/`
|
|
- `docs/api/game-api.md` → `src/modules/wechat-game/` & `src/modules/level/`
|
|
- `docs/api/share-challenge-api.md` → `src/modules/share/`
|
|
|
|
**When to update docs**:
|
|
- New endpoint added
|
|
- Request/response DTO fields changed
|
|
- Error codes or business logic modified
|
|
- Authentication requirements changed
|
|
|
|
Use the template in `AGENTS.md` (api-doc-maintainer skill) for consistent formatting.
|
|
|
|
## Deployment
|
|
|
|
**Local to production**:
|
|
|
|
1. Ensure `.env.production` has correct credentials (WX_APPID, WX_SECRET, JWT_SECRET, DB credentials)
|
|
2. Run `pnpm run deploy` (triggers `deploy.sh`)
|
|
3. Script: builds locally → rsyncs `dist/`, `package.json`, `pnpm-lock.yaml` to `/var/www/MemeMind-Server/` on server → installs deps → restarts PM2 cluster (2 instances)
|
|
|
|
**PM2 config** (`ecosystem.config.js`): Cluster mode (2 instances), auto-restart, 1GB memory limit, logs to `logs/*.log`
|
|
|
|
**Important**: Before deploying, verify deploy.sh credentials (SERVER_IP, SERVER_USER, REMOTE_DIR, APP_NAME) match your target environment.
|
|
|
|
## Code Style & Conventions
|
|
|
|
- **TypeScript**: Strict mode enabled, no implicit `any`, explicit types on public APIs
|
|
- **Naming**: Classes PascalCase, methods/variables camelCase, directories kebab-case
|
|
- **DTO files**: Semantic names (e.g., `wx-login.dto.ts`, `share-response.dto.ts`)
|
|
- **Quotes**: Single quotes (enforced by Prettier)
|
|
- **Indentation**: 2 spaces
|
|
- **Commits**: Use Conventional Commits (e.g., `feat(auth):`, `fix(level):`, `docs(api):`)
|
|
|
|
## Key Integration Points
|
|
|
|
### Auth Module
|
|
|
|
- **Controller**: `POST /api/v1/auth/wx-login`
|
|
- **Flow**: WeChat code → `AuthService.wxLogin()` → calls WeChat API (`jscode2session`) → creates/updates user → signs JWT
|
|
- **Exports**: `AuthService`, `UserRepository`, `UserLevelProgressRepository` (used by other modules)
|
|
|
|
### User Module
|
|
|
|
- **Depends on**: AuthModule (for JWT guard, UserRepository)
|
|
- **Usage**: Profile endpoints, stamina management
|
|
|
|
### Level Module
|
|
|
|
- **Depends on**: AuthModule, UserModule, WechatGameModule
|
|
- **Entities**: Reused from WechatGameModule (Level, UserLevelProgress)
|
|
|
|
### Share Module
|
|
|
|
- **Entities**: ShareConfig, ShareParticipant, ShareLevelProgress (independent tables)
|
|
- **Depends on**: WechatGameModule, AuthModule
|
|
- **Pattern**: Multi-table repository pattern for complex queries
|
|
|
|
## Common Development Tasks
|
|
|
|
- **Add a new API endpoint**: Create DTO in `modules/{feature}/dto/`, add method to controller, implement in service, call `pnpm run lint && pnpm run test` to verify
|
|
- **Add a new entity**: Create `*.entity.ts` in module folder, add to TypeOrmModule.forFeature in module, update relevant repository
|
|
- **Modify API response format**: Update DTO/entity, regenerate Swagger docs, update `docs/api/*.md` manually if not auto-synced
|
|
- **Debug a failing test**: Run `pnpm run test:debug -- --testNamePattern="specific test"` and use Node inspector
|
|
- **Run migrations**: TypeORM in-dev synchronize mode auto-creates tables; for production, use TypeORM CLI or manual SQL
|
|
|
|
## Troubleshooting
|
|
|
|
- **Port 3000 in use**: `lsof -i :3000` and `kill -9 <PID>`, or change PORT env var
|
|
- **Database connection fails**: Verify DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD in `.env.local` match your MySQL setup
|
|
- **JWT verification fails**: Check JWT_SECRET is consistent across app instances and `.env` files
|
|
- **Swagger not loading**: Ensure app.listen() completes; check browser console for CORS errors
|
|
- **Tests hanging**: Check for open database connections; run `pnpm run test:debug` to inspect
|
|
- **Prettier/ESLint conflicts**: Run `pnpm run format && pnpm run lint` in sequence (format first, then lint)
|
|
|
|
## Additional Resources
|
|
|
|
- **NestJS docs**: https://docs.nestjs.com
|
|
- **TypeORM docs**: https://typeorm.io
|
|
- **Project-specific guidance**: See `AGENTS.md` for multi-agent collaboration patterns
|