Consolidate room leave/delete event handling into RoomManager emitter, remove redundant PLAYER_LEFT publishes from GameServer, and delete the chess game plugin (board, types, tests) in favor of the new plugin architecture. Add per-module CLAUDE.md files for leveling, guild-settings, feature-flags, db, api, and panel to improve agent navigability. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2.3 KiB
2.3 KiB
Database Layer
Column Types
- Bigint (
mode: 'bigint'): All Discord snowflake IDs (userId,guildId,roleId,channelId), currency amounts (balance,xp, transactionamount, itemprice, inventoryquantity). Use0nBigInt literals, neverNumber(). - Integer: Small counts and internal IDs —
level,daily_streak,progress,reward_amountin lootdrops, auto-incrementserial('id')for items.
Composite Primary Keys
inventory(userId, itemId)— one stack per user per itemuserQuests(userId, questId)— one assignment per user per questuserTimers(userId, type, key)— one timer per user per type/key combo
Constraints
inventory.quantity > 0check constraint — never store zero-quantity rowsclasses.nameanditems.nameare unique- Cascade deletes on user FK; set null on
relatedUserId(preserves transaction history)
JSON Columns (JSONB)
quests.requirements:{ target: number }quests.rewards:{ xp?: number, balance?: number }gameSettingsfields: Typed via.$type<T>()—LevelingConfig,EconomyConfig, etc.guildSettings.featureOverrides:Record<string, boolean>(sparse)guildSettings.colorRoleIds:string[]users.settings,userTimers.metadata,items.usageData: Untyped JSONB, default{}
Enums
Defined as TypeScript enums in shared/lib/constants.ts, not as database enums. Schema columns use varchar with length constraints. Key enum types:
TimerType: COOLDOWN, EFFECT, ACCESS, EXAM_SYSTEM, TRIVIA_COOLDOWNTransactionType: TRANSFER_IN, DAILY_REWARD, etc. (8 values)ModerationCaseType: warn, timeout, kick, ban, note, pruneItemType: MATERIAL, CONSUMABLE, EQUIPMENT, QUEST
Notable Indexes
user_timers_lookup_idx: Composite on (userId, type, key) — fast timer checksuser_timers_expires_at_idx: Expiry-based cleanup queriesusers_balance_idx/users_level_xp_idx: Leaderboard queries
Client Setup
DrizzleClientis a singleton inshared/db/DrizzleClient.ts(postgres-js driver, no prefetch).withTransactionutility inbot/lib/db.tswraps Drizzle transactions and tracks count for graceful shutdown. Accepts optional existingtxfor nested calls.- No soft deletes anywhere.
moderationCasesusesactive: boolean+resolvedAt/resolvedByfor lifecycle, but rows are never deleted.