# MemeMind-Server Architecture Diagrams & Flows ## 1. System Architecture Overview ``` ┌───────────────────────────────────────────────────────────────┐ │ WeChat Mini-Game Client │ │ (Cocos Creator 3.8.8) │ │ │ │ • PageLoading.ts (startup) │ │ • LevelDataManager.ts (API calls) │ │ • PageLevel.ts (gameplay) │ │ • StorageManager.ts (localStorage) │ └────────────────────┬────────────────────────────────────────┘ │ │ HTTP Requests │ GET /api/v1/wechat-game/levels │ GET /api/v1/wechat-game/configs │ ┌────────────────────▼────────────────────────────────────────┐ │ MemeMind-Server (NestJS) │ │ http://ilookai.cn:3000/api │ │ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ HTTP Layer │ │ │ │ • GlobalPrefix: /api │ │ │ │ • CORS: Enabled │ │ │ │ • ValidationPipe: Global validation │ │ │ │ • Swagger: /api/docs │ │ │ └──────────────────────────────────────────────────────┘ │ │ │ │ │ ┌──────────────────────▼──────────────────────────────┐ │ │ │ WechatGameController │ │ │ │ POST /v1/wechat-game/configs │ │ │ │ GET /v1/wechat-game/configs/:key │ │ │ │ GET /v1/wechat-game/levels │ │ │ │ GET /v1/wechat-game/levels/:id │ │ │ └──────────────────────┬──────────────────────────────┘ │ │ │ │ │ ┌──────────────────────▼──────────────────────────────┐ │ │ │ WechatGameService │ │ │ │ • getAllConfigs() │ │ │ │ • getConfigByKey(key) │ │ │ │ • getAllLevels() │ │ │ │ • getLevelById(id) │ │ │ │ • toResponseDto() │ │ │ │ • toLevelResponseDto() │ │ │ └──────────────────────┬──────────────────────────────┘ │ │ │ │ │ ┌──────────────────────▼──────────────────────────────┐ │ │ │ Repository Layer │ │ │ │ ├─ LevelRepository │ │ │ │ └─ GameConfigRepository │ │ │ └──────────────────────┬──────────────────────────────┘ │ │ │ │ │ ┌──────────────────────▼──────────────────────────────┐ │ │ │ TypeORM / MySQL │ │ │ │ ├─ levels table │ │ │ │ └─ game_configs table │ │ │ └──────────────────────────────────────────────────────┘ │ │ │ └───────────────────────────────────────────────────────────────┘ │ │ Response (JSON) │ {success, data, message, timestamp} │ ┌────────────────────▼────────────────────────────────────────┐ │ WeChat Mini-Game Client │ │ • LevelDataManager stores in _apiData │ │ • PageLevel reads _apiData │ │ • Images preloaded via assetManager.loadRemote() │ └───────────────────────────────────────────────────────────────┘ ``` --- ## 2. Request-Response Flow ### Scenario 1: Get All Levels ``` Client Server │ │ ├─ GET /api/v1/wechat-game/levels │─────────────────────────────>│ │ │ │ [Controller] │ getAllLevels() │ │ │ [Service] │ levelRepository.findAllOrdered() │ │ │ [Repository] │ SELECT * FROM levels ORDER BY sort_order │ │ │ [MySQL] │ Returns Level[] │ │ │ [Service] │ Map to LevelResponseDto │ Add level numbers │ │ │ [Filter] │ Wrap in ApiResponseDto.success() │ │ │ <─────────────────────────────│ │ { │ │ "success": true, │ │ "data": { │ │ "levels": [...], │ │ "total": 50 │ │ }, │ │ "message": null, │ │ "timestamp": "2026-04-05..." │ │ } │ │ │ ├─ Store in _apiData ├─ Preload images └─ Ready for gameplay ``` ### Scenario 2: Get Config by Key ``` Client Server │ │ ├─ GET /api/v1/wechat-game/configs/HINT_COST │─────────────────────────────>│ │ │ │ [Controller] │ getConfigByKey("HINT_COST") │ │ │ [Service] │ gameConfigRepository.findByKey() │ │ │ [Repository] │ SELECT * FROM game_configs │ WHERE config_key = 'HINT_COST' │ │ │ [MySQL] │ Returns GameConfig or null │ │ │ ┌─────────┴─────────┐ │ │ │ │ FOUND NOT FOUND │ │ │ │ [Service] [Service] │ Map to DTO throw NotFoundException │ │ │ │ [Filter] [Filter] │ success() catch exception │ │ │ │ <─────────────────┤ │ │ { │ │ │ "success": true,│ │ │ "data": {...} │ │ │ } │ ┌────────────────┘ │ │ │ │ │ └─> { │ │ "success": false, │ │ "data": null, │ │ "message": "Game config... not found", │ │ "path": "/api/v1/..." │ │ } │ │ └────────────────────────────────── ``` --- ## 3. Module Dependency Graph ``` ┌──────────────────────────────┐ │ AppModule (root) │ ├──────────────────────────────┤ │ │ │ imports: [ │ │ AppConfigModule, │ │ TypeOrmModule, │ │ WechatGameModule │ │ ] │ │ │ └──┬───────────────────────────┘ │ ├─────────────────────────────────────┐ │ │ │ │ ┌──▼─────────────────┐ ┌──────────────▼──────────────┐ │ AppConfigModule │ │ WechatGameModule │ ├────────────────────┤ ├─────────────────────────────┤ │ @Global() │ │ imports: [ │ │ │ │ TypeOrmModule.forFeature( │ │ imports: [ │ │ [GameConfig, Level] │ │ ConfigModule │ │ ) │ │ ] │ │ ] │ │ │ │ │ │ exports: [ │ │ controllers: [ │ │ ConfigModule │ │ WechatGameController │ │ ] │ │ ] │ │ │ │ │ │ │ │ providers: [ │ │ │ │ WechatGameService, │ │ │ │ LevelRepository, │ │ │ │ GameConfigRepository │ │ │ │ ] │ │ │ │ │ │ │ │ exports: [ │ │ │ │ WechatGameService │ │ │ │ ] │ │ │ │ │ └────────────────────┘ └─────────────────────────────┘ │ │ ┌──────────▼───────────────┐ │ TypeOrmModule.forFeature│ ├───────────────────────────┤ │ Registers: │ │ • Level entity │ │ • GameConfig entity │ │ • Auto-creates repos │ └──────────────────────────┘ ``` --- ## 4. Data Model Relationships ``` ┌────────────────────────────────┐ │ levels │ ├────────────────────────────────┤ │ PK: id (VARCHAR 191) │ ├────────────────────────────────┤ │ id (PK) │ │ image_url (VARCHAR) │ │ answer (VARCHAR) │ │ hint1 (VARCHAR) │ │ hint2 (VARCHAR) │ │ hint3 (VARCHAR) │ │ sort_order (INT) │ │ created_at (DATETIME)│ │ updated_at (DATETIME)│ ├────────────────────────────────┤ │ Indexes: │ │ • PK: id │ │ • idx_sort_order: sort_order │ ├────────────────────────────────┤ │ Used by: │ │ • LevelRepository │ │ • WechatGameService │ └────────────────────────────────┘ ┌────────────────────────────────┐ │ game_configs │ ├────────────────────────────────┤ │ PK: id (UUID) │ ├────────────────────────────────┤ │ id (PK) │ │ config_key (VARCHAR) │ │ config_value (TEXT) │ │ description (VARCHAR) │ │ is_active (BOOLEAN) │ │ created_at (DATETIME)│ │ updated_at (DATETIME)│ ├────────────────────────────────┤ │ Indexes: │ │ • PK: id │ │ • UNIQUE: config_key │ │ • idx_active: is_active │ ├────────────────────────────────┤ │ Used by: │ │ • GameConfigRepository │ │ • WechatGameService │ └────────────────────────────────┘ ``` --- ## 5. Service Method Call Chain ### GET /api/v1/wechat-game/levels ``` Controller.getAllLevels() │ ├─> service.getAllLevels() │ │ │ ├─> levelRepository.findAllOrdered() │ │ │ │ │ └─> repository.find({ order: { sortOrder: 'ASC' } }) │ │ │ │ │ └─> [SELECT * FROM levels ORDER BY sort_order ASC] │ │ │ ├─> LOOP levels array: │ │ ├─> toLevelResponseDto(level, index + 1) │ │ │ │ │ │ │ └─> { │ │ │ level: 1 (or 2, 3, ...) │ │ │ id: level.id │ │ │ imageUrl: level.imageUrl │ │ │ answer: level.answer │ │ │ hint1: level.hint1 │ │ │ hint2: level.hint2 │ │ │ hint3: level.hint3 │ │ │ sortOrder: level.sortOrder │ │ │ createdAt: level.createdAt │ │ │ updatedAt: level.updatedAt │ │ │ } │ │ │ └─> return { │ levels: [LevelResponseDto[], ...] │ total: count │ } │ └─> ApiResponseDto.success(data) │ └─> { success: true data: { levels, total } message: null timestamp: new Date() } ``` --- ## 6. Error Handling Flow ``` ┌─────────────────┐ │ HTTP Request │ └────────┬────────┘ │ ┌────▼─────────────┐ │ ValidationPipe │ │ (Global) │ └────┬─────────────┘ │ ┌───┴────────────────────────┐ │ │ ▼ Valid ▼ Invalid Continue ValidationException │ [ExceptionFilter] catches @Catch() │ ApiResponseDto.error() │ {success: false, message: "...", path: "..."} │ ▼ Valid data [Controller] [Service] [Repository] [Database] │ ├─ Success ──┐ │ │ │ ▼ │ [Service] returns data │ │ │ [Controller] │ │ │ ApiResponseDto.success(data) │ │ │ Return to client │ └─ Exception ──┐ │ ▼ NotFoundException BadRequestException (or any HttpException) │ ▼ [HttpExceptionFilter] @Catch() catches exception │ ▼ Extract status & message │ ▼ ApiResponseDto.error(message) │ ▼ response.status(code).json(errorDto) │ ▼ Return to client with error ``` --- ## 7. Request Validation Pipeline ``` HTTP Request │ ├─ Path params extracted │ @Param('id') id: string │ @Param('key') key: string │ ├─ Query params extracted │ @Query() dto: QueryDto │ ├─ Body params extracted (for POST/PUT) │ @Body() dto: CreateDto │ ├─ Global ValidationPipe processes: │ │ │ ├─ whitelist: true │ │ └─ Remove unknown properties │ │ │ ├─ forbidNonWhitelisted: true │ │ └─ Throw if unknown properties found │ │ │ └─ transform: true │ └─ Transform strings to appropriate types │ (e.g., "123" → 123) │ ├─ class-validator decorators checked │ @IsString() │ @IsNumber() │ @IsEmail() │ etc. │ ├─ If validation fails │ └─> BadRequestException │ └─> ExceptionFilter catches │ └─> 400 status + error message │ └─ If validation passes └─> Continue to controller ``` --- ## 8. Data Transformation Chain ``` HTTP Request JSON │ ├─ Parse JSON ├─ Extract into DTO object │ { │ "@Type(() => Number)" hint: "5" ──> 5 (number) │ "@Transform()" name: "JOHN" ──> "john" (lowercased) │ } │ ├─ Validate against DTO decorators │ @IsNotEmpty() │ @IsNumber() │ @Min(0) │ @Max(100) │ ├─ Pass to Service │ ├─ Service transforms to Entity │ DTO ──> Entity │ {id, name} {id, name, timestamp} │ ├─ Database operations │ Entity ──> SQL │ TypeORM handles serialization │ ├─ Result from Database │ Entity[] ──> Entity[] │ ├─ Service transforms Entity to ResponseDto │ Entity ──> ResponseDto │ Remove sensitive fields │ Add computed fields │ ├─ Wrap in ApiResponseDto │ └─ Send as JSON Response { success: true, data: [...ResponseDtos...], message: null, timestamp: "..." } ``` --- ## 9. Database Connection Lifecycle ``` [Application Start] │ ▼ [config.module.ts loads] • validateEnvironment() • Reads .env, .env.local, .env.production │ ▼ [app.module.ts initializes] • TypeOrmModule.forRootAsync() • Uses ConfigService to get DB params │ ├─ DB_HOST: localhost ├─ DB_PORT: 3306 ├─ DB_USERNAME: meme_user ├─ DB_PASSWORD: (from env) ├─ DB_DATABASE: meme_mind │ ▼ [TypeORM connects to MySQL] mysql2 driver establishes connection │ ├─ If NODE_ENV === 'development' │ └─ synchronize: true │ └─ Auto-create/update tables │ ├─ If NODE_ENV === 'production' │ └─ synchronize: false │ └─ Use migrations instead │ ▼ [Repositories instantiated] @InjectRepository(Level) @InjectRepository(GameConfig) │ ▼ [Ready to accept requests] • findAllOrdered() ──> SELECT ... • findByKey() ──> SELECT ... │ ▼ [Application shutdown] TypeORM closes connection ``` --- ## 10. Environment to Runtime Configuration ``` .env.local / .env file │ ├─ NODE_ENV=development ├─ PORT=3000 ├─ DB_HOST=localhost ├─ DB_PORT=3306 ├─ DB_USERNAME=meme_user ├─ DB_PASSWORD=secret ├─ DB_DATABASE=meme_mind │ ▼ env.validation.ts • plainToInstance(EnvironmentVariables, config) • validateSync() • Throws if validation fails │ ▼ config.module.ts • ConfigModule.forRoot() • isGlobal: true ──> Available everywhere • validate: validateEnvironment │ ▼ database.config.ts registerAs('database', () => ({ type: 'mysql', host: configService.get('DB_HOST'), port: configService.get('DB_PORT'), username: configService.get('DB_USERNAME'), password: configService.get('DB_PASSWORD'), database: configService.get('DB_DATABASE'), ... })) │ ▼ app.module.ts TypeOrmModule.forRootAsync({ useFactory: (configService) => ({ ...configService.get('database') }) }) │ ▼ main.ts port = process.env.PORT ?? 3000 app.listen(port) │ ▼ Application Running • Connected to MySQL • Listening on port • Ready for requests ``` --- ## 11. API Response Mapping Example ### Request: ``` GET /api/v1/wechat-game/levels ``` ### Database Results: ```sql SELECT * FROM levels ORDER BY sort_order ASC LIMIT 2; Results: ┌─────────────┬──────────────────────┬────────┬───────┬───────┬───────┬────────────┬─────────────┬─────────────┐ │ id │ image_url │ answer │ hint1 │ hint2 │ hint3 │ sort_order │ created_at │ updated_at │ ├─────────────┼──────────────────────┼────────┼───────┼───────┼───────┼────────────┼─────────────┼─────────────┤ │ level-001 │ http://...img1.jpg │ meme │ image │ funny │ null │ 0 │ 2026-04-01 │ 2026-04-05 │ │ level-002 │ http://...img2.jpg │ code │ tech │ null │ null │ 1 │ 2026-04-02 │ 2026-04-05 │ └─────────────┴──────────────────────┴────────┴───────┴───────┴───────┴────────────┴─────────────┴─────────────┘ ``` ### Service Transformation: ```javascript levels.map((level, index) => toLevelResponseDto(level, index + 1)) Result: [ { level: 1, // Computed: index + 1 id: "level-001", imageUrl: "http://...img1.jpg", answer: "meme", hint1: "image", hint2: "funny", hint3: null, sortOrder: 0, createdAt: "2026-04-01T...", updatedAt: "2026-04-05T..." }, { level: 2, id: "level-002", imageUrl: "http://...img2.jpg", answer: "code", hint1: "tech", hint2: null, hint3: null, sortOrder: 1, createdAt: "2026-04-02T...", updatedAt: "2026-04-05T..." } ] ``` ### Final HTTP Response: ```json { "success": true, "data": { "levels": [ { "level": 1, "id": "level-001", "imageUrl": "http://...img1.jpg", "answer": "meme", "hint1": "image", "hint2": "funny", "hint3": null, "sortOrder": 0, "createdAt": "2026-04-01T00:00:00.000Z", "updatedAt": "2026-04-05T12:00:00.000Z" }, { "level": 2, "id": "level-002", "imageUrl": "http://...img2.jpg", "answer": "code", "hint1": "tech", "hint2": null, "hint3": null, "sortOrder": 1, "createdAt": "2026-04-02T00:00:00.000Z", "updatedAt": "2026-04-05T12:00:00.000Z" } ], "total": 2 }, "message": null, "timestamp": "2026-04-05T12:34:56.789Z" } ``` --- ## Summary of Diagrams 1. **System Architecture**: High-level components (Client, Server, Database) 2. **Request-Response Flow**: Detailed flow for GET and error scenarios 3. **Module Dependency Graph**: How modules depend on each other 4. **Data Model Relationships**: Database table structures 5. **Service Method Call Chain**: Stack of calls from Controller to DB 6. **Error Handling Flow**: Exception catching and wrapping 7. **Request Validation Pipeline**: Validation process 8. **Data Transformation Chain**: DTO → Entity → DB → Entity → ResponseDto 9. **Database Connection Lifecycle**: Connection initialization 10. **Environment to Runtime**: How .env becomes runtime config 11. **API Response Mapping**: Real example of transformation *Generated: 2026-04-05*