11 KiB
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
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
pnpm run lint # ESLint with auto-fix
pnpm run format # Prettier format (src/ and test/)
Testing
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
pnpm run deploy # Build, rsync to server, restart PM2 cluster
Architecture Patterns
Module Structure
Each feature module follows NestJS conventions:
// 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 injectJwtPayload { 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>:
{
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:covto generate coverage report incoverage/ - Individual tests:
pnpm run test -- --testNamePattern="test name"orpnpm 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:
- Ensure
.env.productionhas correct credentials (WX_APPID, WX_SECRET, JWT_SECRET, DB credentials) - Run
pnpm run deploy(triggersdeploy.sh) - Script: builds locally → rsyncs
dist/,package.json,pnpm-lock.yamlto/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, callpnpm run lint && pnpm run testto verify - Add a new entity: Create
*.entity.tsin module folder, add to TypeOrmModule.forFeature in module, update relevant repository - Modify API response format: Update DTO/entity, regenerate Swagger docs, update
docs/api/*.mdmanually 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 :3000andkill -9 <PID>, or change PORT env var - Database connection fails: Verify DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD in
.env.localmatch your MySQL setup - JWT verification fails: Check JWT_SECRET is consistent across app instances and
.envfiles - Swagger not loading: Ensure app.listen() completes; check browser console for CORS errors
- Tests hanging: Check for open database connections; run
pnpm run test:debugto inspect - Prettier/ESLint conflicts: Run
pnpm run format && pnpm run lintin sequence (format first, then lint)
Additional Resources
- NestJS docs: https://docs.nestjs.com
- TypeORM docs: https://typeorm.io
- Project-specific guidance: See
AGENTS.mdfor multi-agent collaboration patterns