Initial commit: NestJS backend for Child Gold Land

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-02 08:08:11 +02:00
co-authored by Cursor
commit edb79180a1
93 changed files with 11565 additions and 0 deletions
+107
View File
@@ -0,0 +1,107 @@
import {
Inject,
Injectable,
InternalServerErrorException,
Logger,
forwardRef,
} from '@nestjs/common'
import { DatabaseService } from '../database/database.service'
import { createDefaultUserState } from '../shared/catalog/default-user-state'
import type { MeResponse, UserState } from '../shared/types/user.types'
import { GoldLandProgressionService } from '../gold-land/services/progression.service'
@Injectable()
export class UsersService {
private readonly logger = new Logger(UsersService.name)
constructor(
@Inject(DatabaseService) private readonly database: DatabaseService,
@Inject(forwardRef(() => GoldLandProgressionService))
private readonly goldLandProgression: GoldLandProgressionService,
) {}
ensureUser(userId: string): UserState {
return this.getUserState(userId)
}
getUserState(userId: string): UserState {
const row = this.database
.getDb()
.prepare('SELECT state_json FROM users WHERE id = ?')
.get(userId) as { state_json: string } | undefined
if (row) {
return this.parseStateJson(row.state_json, userId)
}
const state = createDefaultUserState(userId)
this.database
.getDb()
.prepare('INSERT INTO users (id, state_json, updated_at) VALUES (?, ?, ?)')
.run(userId, JSON.stringify(state), new Date().toISOString())
return state
}
saveUserState(state: UserState): UserState {
this.database
.getDb()
.prepare('UPDATE users SET state_json = ?, updated_at = ? WHERE id = ?')
.run(JSON.stringify(state), new Date().toISOString(), state.id)
return state
}
toMeResponse(state: UserState): MeResponse {
return {
user: {
id: state.id,
name: state.name,
level: state.level,
xp: state.xp,
maxXp: state.maxXp,
coins: state.coins,
missionProgress: state.missionProgress,
missionTarget: state.missionTarget,
},
wallet: {
cash: state.cash,
goldGrams: state.goldGrams,
},
progress: {
completedChallenges: state.completedChallenges,
completedLessons: state.completedLessons,
completedGames: state.completedGames,
claimedRewards: state.claimedRewards,
ownedItems: state.ownedItems,
mapLevels: state.mapLevels,
totalStars: state.totalStars,
maxStars: state.maxStars,
},
achievements: state.achievements,
transactions: state.transactions,
market: {
selectedRange: state.marketSelectedRange,
},
}
}
getMe(userId: string): MeResponse {
const state = this.goldLandProgression.syncUserProgressionState(userId)
return this.toMeResponse(state)
}
updateProfile(userId: string, name: string): MeResponse {
const state = this.getUserState(userId)
state.name = name.trim()
this.saveUserState(state)
return this.toMeResponse(state)
}
private parseStateJson(raw: string, userId: string): UserState {
try {
return JSON.parse(raw) as UserState
} catch (error) {
this.logger.error(`Invalid state_json for user ${userId}`, error)
throw new InternalServerErrorException('داده کاربر نامعتبر است')
}
}
}