7.5 KiB
Implementation Plan: User Auth + Server-Side Lives Management
Current State Analysis
Client (Cocos Creator)
- Currency: "Lives" (生命值), new user starts with 10
- Earning: +1 life per correct answer (
PageLevel.showSuccess()→addLife()) - Spending: -1 life per hint unlock (hints 2 & 3 only,
PageLevel.onUnlockClue()→consumeLife()) - Storage: All local via
StorageManagerusingsys.localStorage - No auth: WxSDK only handles sharing/vibration, no
wx.login - HttpUtil: Has GET/POST, but no auth headers
Server (NestJS)
- Read-only: 4 GET endpoints (configs + levels)
- No auth, no user system, no guards
- Uses repository pattern consistently
Phase 1: Server - Auth Module (WeChat Login)
1.1 Install dependencies
cd MemeMind-Server
pnpm add @nestjs/jwt axios
1.2 New files to create
Entity: src/modules/auth/entities/user.entity.ts
id(UUID, PK)openid(varchar 128, unique index)sessionKey(varchar 255, nullable) - WeChat session_keynickname(varchar 100, nullable)avatarUrl(text, nullable)lives(int, default 10) - 生命值/积分createdAt,updatedAt
DTO: src/modules/auth/dto/wx-login.dto.ts
WxLoginRequestDto-{ code: string }WxLoginResponseDto-{ token: string, user: { id, nickname, lives } }
Repository: src/modules/auth/repositories/user.repository.ts
findByOpenid(openid),findById(id),create(data),save(user)
Service: src/modules/auth/auth.service.ts
wxLogin(code): Call WeChat APIhttps://api.weixin.qq.com/sns/jscode2sessionwith appid/secret + code → get openid/session_key → find or create user → sign JWT → return token + user info
Guard: src/common/guards/jwt-auth.guard.ts
- Custom Guard: extract Bearer token from header → verify JWT → attach user to request
Controller: src/modules/auth/auth.controller.ts
POST /v1/auth/wx-login- public endpoint, accepts{ code }, returns{ token, user }
Module: src/modules/auth/auth.module.ts
- Imports: JwtModule, TypeOrmModule.forFeature([User])
- Exports: JwtModule (so other modules can use JwtService)
1.3 Environment variables
Add to .env and env.validation.ts:
WX_APPID- 微信小程序 AppIDWX_SECRET- 微信小程序 AppSecretJWT_SECRET- JWT signing secret
Phase 2: Server - User Assets API (Lives Management)
2.1 New files
DTO: src/modules/auth/dto/user-assets.dto.ts
UserAssetsResponseDto-{ lives: number }ConsumeLifeRequestDto-{ reason: 'hint_unlock', levelId?: string, hintIndex?: number }EarnLifeRequestDto-{ reason: 'level_complete', levelId: string }
Endpoints added to auth controller (or new user controller):
GET /v1/user/assets- [Auth Required] Get current livesPOST /v1/user/assets/consume- [Auth Required] Consume 1 life (for hint unlock)POST /v1/user/assets/earn- [Auth Required] Earn 1 life (for level completion)
2.2 Business logic safety
- Consume: Check lives > 0 before deducting, return error if insufficient
- Earn: Server validates the reason, +1 life
- Idempotency consideration: For level_complete, track completed levels per user to prevent duplicate rewards
2.3 New Entity: src/modules/auth/entities/user-level-progress.entity.ts
id(UUID, PK)userId(varchar, FK → User)levelId(varchar, FK → Level)completedAt(datetime)- Unique index on (userId, levelId) - prevent duplicate completion rewards
Phase 3: Server - Protect Existing Endpoints + Loading Data API
3.1 Composite loading endpoint
GET /v1/user/game-data - [Auth Required] Returns everything needed at loading:
{
"user": { "id": "...", "lives": 10 },
"levels": [ ... ], // reuse existing level data
"progress": { "completedLevelIds": ["level-1", "level-2"] }
}
This replaces the client making multiple API calls during loading.
3.2 Auth on existing endpoints
Keep /v1/wechat-game/levels and /v1/wechat-game/configs as public (no auth needed for level data).
New user-specific endpoints require auth.
Phase 4: Client - WeChat Login Integration
4.1 WxSDK - Add login method
static login(): Promise<string> // returns wx code
Calls wx.login() → returns code
4.2 New file: assets/scripts/utils/AuthManager.ts
Singleton managing auth state:
login(): WxSDK.login() → POST /v1/auth/wx-login → store token + user datagetToken(): return cached tokengetUserLives(): return cached livesisLoggedIn(): boolean- Store token in localStorage
4.3 HttpUtil - Add auth support
- Add
setAuthToken(token)static method - Modify GET/POST to attach
Authorization: Bearer <token>header when token exists
Phase 5: Client - Connect Lives to Server
5.1 New file: assets/scripts/utils/UserAssetsManager.ts
Singleton managing user assets (lives) with server sync:
fetchAssets(): GET /v1/user/assets → update local livesconsumeLife(reason, levelId?, hintIndex?): POST /v1/user/assets/consume → update localearnLife(reason, levelId): POST /v1/user/assets/earn → update local- Falls back to local StorageManager if network fails
5.2 PageLoading - Updated flow
start()
→ WxSDK.login() get code
→ POST /auth/wx-login → get token + user data (including lives)
→ Store token, sync lives to StorageManager
→ GET /levels (existing, now with auth optional)
→ Preload assets
→ Open PageHome
5.3 PageLevel - Updated logic
onUnlockClue(): CallUserAssetsManager.consumeLife('hint_unlock', levelId, hintIndex)instead ofStorageManager.consumeLife()showSuccess()→nextLevel(): CallUserAssetsManager.earnLife('level_complete', levelId)instead ofStorageManager.addLife()- Keep StorageManager as local cache/fallback
File Change Summary
Server - New Files (10 files)
src/modules/auth/auth.module.tssrc/modules/auth/auth.controller.tssrc/modules/auth/auth.service.tssrc/modules/auth/entities/user.entity.tssrc/modules/auth/entities/user-level-progress.entity.tssrc/modules/auth/repositories/user.repository.tssrc/modules/auth/repositories/user-level-progress.repository.tssrc/modules/auth/dto/wx-login.dto.tssrc/modules/auth/dto/user-assets.dto.tssrc/common/guards/jwt-auth.guard.ts
Server - Modified Files (3 files)
src/app.module.ts- Import AuthModulesrc/config/env.validation.ts- Add WX_APPID, WX_SECRET, JWT_SECRETsrc/main.ts- Add Bearer auth to Swagger config
Client - New Files (2 files)
assets/scripts/utils/AuthManager.tsassets/scripts/utils/UserAssetsManager.ts
Client - Modified Files (4 files)
assets/scripts/utils/WxSDK.ts- Addlogin()methodassets/scripts/utils/HttpUtil.ts- Add auth token supportassets/PageLoading.ts- Add login flow before loadingassets/prefabs/PageLevel.ts- Use UserAssetsManager for earn/consume
API Endpoints Summary
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /v1/auth/wx-login |
No | WeChat code → JWT token |
| GET | /v1/user/assets |
Yes | Get user lives |
| POST | /v1/user/assets/consume |
Yes | Consume 1 life (hint) |
| POST | /v1/user/assets/earn |
Yes | Earn 1 life (level complete) |
| GET | /v1/user/game-data |
Yes | Loading composite endpoint |
| GET | /v1/wechat-game/levels |
No | Existing, stays public |
| GET | /v1/wechat-game/configs |
No | Existing, stays public |