Add wallet and inventory schema
This commit is contained in:
parent
5570973f74
commit
a23f1abc12
@ -31,7 +31,7 @@
|
||||
|---|------|------|----------|
|
||||
| G0-1 | 梳理游戏化规则常量模块 | [x] | 新增集中规则定义,覆盖红心、挑战组、XP、等级、金币、道具、广告恢复、周榜周期 |
|
||||
| G0-2 | 新增挑战组数据模型 | [x] | 支持 challenge session、session answers、组状态、正确数、完成时间、幂等提交 |
|
||||
| G0-3 | 新增钱包和道具库存模型 | [ ] | 支持金币余额、道具库存、道具获得/消耗流水 |
|
||||
| G0-3 | 新增钱包和道具库存模型 | [x] | 支持金币余额、道具库存、道具获得/消耗流水 |
|
||||
| G0-4 | 新增奖励流水模型 | [ ] | 记录奖励来源、幂等 key、奖励快照、发放前后状态 |
|
||||
| G0-5 | 新增每日任务或每日进度模型 | [ ] | 可统计每日首组挑战、每日任务完成、每日高奖励次数 |
|
||||
| G0-6 | 新增周 XP 统计模型或扩展周榜快照 | [ ] | 可按自然周统计 XP,支持每周一刷新和历史快照 |
|
||||
|
||||
@ -210,6 +210,58 @@ export const challengeSessionAnswers = mysqlTable('challenge_session_answers', {
|
||||
foreignKey({ columns: [table.questionId], foreignColumns: [questions.id] }),
|
||||
]);
|
||||
|
||||
// ── Wallets and Inventory ──────────────────────────────────────────
|
||||
|
||||
// 用户金币钱包,所有余额变化必须通过流水记录追踪。
|
||||
export const userWallets = mysqlTable('user_wallets', {
|
||||
userId: char('user_id', { length: 36 }).primaryKey(),
|
||||
coinsBalance: int('coins_balance').default(0), // 当前金币余额。
|
||||
lifetimeCoinsEarned: int('lifetime_coins_earned').default(0), // 历史累计获得金币。
|
||||
lifetimeCoinsSpent: int('lifetime_coins_spent').default(0), // 历史累计消耗金币。
|
||||
createdAt: datetime('created_at').default(sql`CURRENT_TIMESTAMP`), // 创建时间。
|
||||
updatedAt: datetime('updated_at').default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`), // 更新时间。
|
||||
}, (table) => [
|
||||
foreignKey({ columns: [table.userId], foreignColumns: [users.id] }),
|
||||
]);
|
||||
|
||||
// 用户道具库存,以 item_id 聚合当前可用数量和最近有效期。
|
||||
export const userInventoryItems = mysqlTable('user_inventory_items', {
|
||||
id: char('id', { length: 36 }).primaryKey(),
|
||||
userId: char('user_id', { length: 36 }).notNull(),
|
||||
itemId: mysqlEnum('item_id', ['streak_shield', 'double_xp_potion', 'heart_supply', 'hint_feather', 'mascot_outfit']).notNull(), // 道具标识。
|
||||
quantity: int('quantity').default(0), // 当前库存数量。
|
||||
activeUntil: datetime('active_until'), // 时效型道具的生效截止时间。
|
||||
metadata: json('metadata').$type<Record<string, unknown>>(), // 装扮、头像框等展示权益的扩展信息。
|
||||
createdAt: datetime('created_at').default(sql`CURRENT_TIMESTAMP`), // 创建时间。
|
||||
updatedAt: datetime('updated_at').default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`), // 更新时间。
|
||||
}, (table) => [
|
||||
uniqueIndex('uk_inventory_user_item').on(table.userId, table.itemId),
|
||||
index('idx_inventory_user_active').on(table.userId, table.activeUntil),
|
||||
foreignKey({ columns: [table.userId], foreignColumns: [users.id] }),
|
||||
]);
|
||||
|
||||
// 钱包和道具库存流水,记录金币与道具的获得、消耗和调整来源。
|
||||
export const inventoryTransactions = mysqlTable('inventory_transactions', {
|
||||
id: char('id', { length: 36 }).primaryKey(),
|
||||
userId: char('user_id', { length: 36 }).notNull(),
|
||||
inventoryItemId: char('inventory_item_id', { length: 36 }),
|
||||
itemId: mysqlEnum('item_id', ['coins', 'streak_shield', 'double_xp_potion', 'heart_supply', 'hint_feather', 'mascot_outfit']).notNull(), // 流水涉及的资源。
|
||||
direction: mysqlEnum('direction', ['grant', 'consume', 'adjust']).notNull(), // 获得、消耗或运营调整。
|
||||
quantityDelta: int('quantity_delta').notNull(), // 资源数量变化,消耗为负数。
|
||||
balanceAfter: int('balance_after'), // 变更后的金币余额或道具库存。
|
||||
sourceType: mysqlEnum('source_type', ['challenge', 'daily_task', 'level_up', 'theme_node', 'chest', 'shop_purchase', 'ad_recovery', 'subscription', 'admin_grant', 'system_adjust']).notNull(), // 资源变化来源。
|
||||
sourceId: varchar('source_id', { length: 120 }), // 来源业务 ID,如挑战组、订单或广告会话。
|
||||
idempotencyKey: varchar('idempotency_key', { length: 160 }), // 幂等边界,防止重复发放或重复扣减。
|
||||
snapshot: json('snapshot').$type<Record<string, unknown>>(), // 本次变更的上下文快照。
|
||||
createdAt: datetime('created_at').default(sql`CURRENT_TIMESTAMP`), // 创建时间。
|
||||
}, (table) => [
|
||||
uniqueIndex('uk_inventory_transaction_idempotency').on(table.userId, table.idempotencyKey),
|
||||
index('idx_inventory_transaction_user_created').on(table.userId, table.createdAt),
|
||||
index('idx_inventory_transaction_source').on(table.sourceType, table.sourceId),
|
||||
foreignKey({ columns: [table.userId], foreignColumns: [users.id] }),
|
||||
foreignKey({ columns: [table.inventoryItemId], foreignColumns: [userInventoryItems.id] }),
|
||||
]);
|
||||
|
||||
// ── Question Ratings ──────────────────────────────────────────────
|
||||
|
||||
// 用户对题目的好坏反馈数据。
|
||||
|
||||
Loading…
Reference in New Issue
Block a user