Commit Graph

115 Commits

Author SHA1 Message Date
syntaxbullet
70a149ab82 refactor(games): overhaul WS game system with improved UX and solo test support
Some checks failed
Deploy to Production / test (push) Failing after 35s
Backend:
- Fix session never being attached to ws.data at upgrade time
- Add GameServer class: connection registry, per-connection room tracking,
  automatic room cleanup on disconnect via ws.data.rooms
- Replace ws-handler.ts with typed event-driven architecture using mitt
- Remove redundant subscription tracking from RoomManager
- Add JOIN_RESULT with player/spectator lists replacing error-as-control-flow
- Add SESSION_REPLACED for multi-tab same-account detection
- Add FILL_ROOM command for admin solo testing (fills empty slots with host)
- Fix dual-schema routing; remove game types from WsMessageSchema
- Per-player personalized views sent directly after each action

Chess plugin:
- Allow same-player (solo) mode: skip color/turn ownership checks
- Fix forfeit and disconnect handling in solo mode (winner: null)

Frontend:
- Click-to-move with legal move dots and last-move highlight
- Auto-scroll move history, forfeit confirmation, turn-reactive board border
- JOIN_RESULT initialises player/spectator lists immediately on join
- Contextual connecting state, player slot cards in waiting room
- Copy-invite button with Copied! flash, Back to Lobby CTA on finish
- Session-replaced warning banner with Rejoin here action
- Lobby passes preferAs intent through route state
- Admin waiting room shows Start Solo Test button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 16:41:13 +02:00
syntaxbullet
26a0e532f6 fix(chess): prevent duplicate players and fix move detection
Some checks failed
Deploy to Production / test (push) Failing after 38s
- Prevent same player from joining as both white and black
- Add validation to reject duplicate players in RoomManager
- Fix spectator status not resetting when joining as player
- Use ref to track latest chess state in ChessBoard for accurate move validation
2026-04-02 15:36:05 +02:00
syntaxbullet
0dadc82f84 feat(chess): replace custom engine with chess.js and react-chessboard
Some checks failed
Deploy to Production / test (push) Failing after 39s
Swap the custom move validation and Unicode piece grid for chess.js
(full rules engine with check/checkmate/castling/en passant/promotion)
and react-chessboard (drag-and-drop SVG board). Board styled to match
the purple dark theme and auto-orients to the player's color.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 14:22:27 +02:00
syntaxbullet
55df982a0b feat(games): implement chess plugin with tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:25:54 +02:00
syntaxbullet
db10ebe220 feat(games): add room types and game WS message schemas
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:23:11 +02:00
syntaxbullet
a5478dce2b feat(games): add GamePlugin interface and registry
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:22:48 +02:00
syntaxbullet
5bd390b4ee docs: add JSDoc to service public methods
One-line JSDoc on 82 methods across 11 service files for quick
scanning without reading full implementations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 11:36:18 +02:00
syntaxbullet
5f8819bb46 docs: add subdirectory CLAUDE.md files for key domain modules
Provide non-obvious business rules and constraints for economy,
inventory, quest, moderation, trade, and trivia modules to reduce
context-gathering overhead for AI tools.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 11:36:12 +02:00
syntaxbullet
5188d86d61 fix(inventory): address code review findings
Some checks failed
Deploy to Production / test (push) Failing after 31s
- Replace setTimeout race in use-item flow with explicit Back button
- Fix collector end handler to re-render current view instead of blanking
- Add appendUseBackButton helper to attach navigation to use results
- Remove unused isInventoryInteraction import
- Fix rarity test type assertions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 17:49:12 +01:00
syntaxbullet
fa09ef25e2 feat(inventory): add squareEmoji to RARITY_CONFIG
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 17:04:07 +01:00
syntaxbullet
21b5fedfc9 chore: add migration for quest config column
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 16:29:42 +01:00
syntaxbullet
912ce5b942 feat: enforce active quest limit in assignQuest
Adds a limit check to assignQuest that reads maxActiveQuests from game
settings and throws a UserError when the user has reached their active
quest limit. Completed quests are excluded from the count.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 15:39:23 +01:00
syntaxbullet
4ead7e60b1 feat: wire QuestConfig into game settings service 2026-03-28 15:37:38 +01:00
syntaxbullet
e64ffdc4cb feat: add QuestConfig interface and column to game settings schema 2026-03-28 15:36:43 +01:00
syntaxbullet
1d601febcf fix: wire quest progress tracking for transfer, daily, trivia, and exam events
Some checks failed
Deploy to Production / test (push) Failing after 31s
These domain events were only connected to dashboard recording but never
called questService.handleEvent(), so quests with triggers TRANSFER_OUT,
DAILY_REWARD, TRIVIA_WIN, and EXAM_REWARD never tracked progress. Added
userId and tx to event payloads and switched from emit to emitAsync for
transaction atomicity.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 15:24:30 +01:00
syntaxbullet
782a138fd8 fix: strip query params from asset URLs before filesystem lookup
All checks were successful
Deploy to Production / test (push) Successful in 36s
Icon URLs stored with cache-busting query params (e.g. ?v=123) caused
existsSync to fail, preventing Discord attachment fallback and leaving
unresolvable localhost URLs as thumbnails.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 15:48:19 +01:00
syntaxbullet
602147e961 feat: cap daily reward at 500 AU
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 15:21:01 +01:00
syntaxbullet
9e6bb8b148 fix: add non-null assertion for default rarity config fallback
All checks were successful
Deploy to Production / test (push) Successful in 35s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 15:15:53 +01:00
syntaxbullet
86142cba6c feat: rewrite lootbox pull results with Components V2 and separate icon/image URLs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 21:51:28 +01:00
syntaxbullet
0517cd638c fix: add JSDoc header and null input test for rarity config 2026-03-18 21:49:10 +01:00
syntaxbullet
b8303a7e28 feat: add shared rarity config and helpers
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 21:46:21 +01:00
syntaxbullet
5d832c9601 fix: update trivia test to mock events instead of dashboardService
All checks were successful
Deploy to Production / test (push) Successful in 38s
The trivia service now emits domain events via systemEvents instead
of directly calling dashboardService.recordEvent. Updated the test
mock and assertions to match.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 13:37:31 +01:00
syntaxbullet
2bddab001a fix: verify receiver has no transaction records in insufficient funds test
Some checks failed
Deploy to Production / test (push) Failing after 9s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 13:26:50 +01:00
syntaxbullet
fc058effd5 feat: add integration test for economy transfer flow
Tests the full transfer cycle against a real database: debit/credit,
transaction records, insufficient funds rejection, self-transfer
rejection, non-positive amounts, and sequential transfers.

Uses *.integration.test.ts convention — excluded from default test
runs, included with --integration flag in CI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 13:24:49 +01:00
syntaxbullet
3f99a77446 test: add integration test for economy transfer flow
Covers the critical financial transfer path against a real database,
catching schema mismatches, constraint violations, and transaction
atomicity bugs that mocked unit tests cannot detect.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 13:21:31 +01:00
syntaxbullet
abe25e0ceb refactor: extract Discord.js code from shared services into bot layer
Move terminal.service.ts and prune.service.ts entirely to bot/modules/
since they are Discord-specific. Split lootdrop.service.ts: pure logic
(activity tracking, DB ops, claim) stays in shared/, Discord operations
(message sending, channel interactions) move to bot/modules/economy/
lootdrop.handler.ts. Move effect registry/handlers/types from bot/ to
shared/modules/inventory/ since they contain no Discord.js imports and
are needed by inventory.service.ts in shared.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 13:15:29 +01:00
syntaxbullet
5a20ed23f4 fix: guard against undefined username in trivia won event
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 13:06:33 +01:00
syntaxbullet
0142508eb5 fix: add type safety and error handling to event bus
- Add DomainEventPayloads interface to events.ts for typed event payloads
- Wrap dashboard listeners with fireAndForget() to prevent unhandled promise rejections
- Type all listener parameters explicitly using DomainEventPayloads
- Add idempotency guard to registerDomainEventListeners to prevent double registration on hot-reload

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 13:04:32 +01:00
syntaxbullet
5863418ae9 refactor: replace dynamic imports with event bus pattern
Replace 12 dynamic `await import()` calls with domain events emitted
through the existing systemEvents bus, breaking circular dependencies
between services (economy/inventory/leveling -> quest, * -> dashboard).

- Add `emitAsync` to SystemEventEmitter for sequential listener awaiting,
  preserving DB transaction atomicity for quest progress tracking
- Add DOMAIN event constants (BALANCE_CHANGED, XP_GAINED, ITEM_COLLECTED,
  ITEM_USED, TRANSFER_COMPLETED, DAILY_CLAIMED, TRIVIA_*, EXAM_PASSED)
- Create shared/lib/eventWiring.ts to register all domain event listeners
- Convert quest event calls to `await systemEvents.emitAsync()` (5 calls)
- Convert dashboard event calls to `systemEvents.emit()` fire-and-forget (5 calls)
- Convert exam.service.ts userService import to static import (1 call)
- Convert dashboard.service.ts events import to static import (1 call)
- Leave inventory.service.ts validateAndExecuteEffect import unchanged (Task 3)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 12:59:15 +01:00
syntaxbullet
a96c6caa49 fix: standardize error classes in shared service modules
Replace raw `Error` with `UserError` for user-facing conditions (invalid trade state, user not found, permission/channel type checks) and `SystemError` for internal failures (DB insert failures, external API errors, missing config). Improves Discord UX by ensuring user-facing errors are surfaced cleanly via withCommandErrorHandling.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 12:51:16 +01:00
syntaxbullet
2381f073ba feat: add admin panel with Discord OAuth and dashboard
Some checks failed
Deploy to Production / test (push) Failing after 37s
Adds a React admin panel (panel/) with Discord OAuth2 login,
live dashboard via WebSocket, and settings/management pages.
Includes Docker build support, Vite proxy config for dev,
game_settings migration, and open-redirect protection on auth callback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 20:27:14 +01:00
syntaxbullet
121c242168 fix: handle permission denied on backup directory
All checks were successful
Deploy to Production / test (push) Successful in 35s
The backups directory may have been created by Docker/root, making it
unwritable by the deploy user. The script now detects this and attempts
to fix permissions automatically (chmod, then sudo chown as fallback).

Also added shared/db/backups to .gitignore.
2026-02-13 14:48:06 +01:00
syntaxbullet
942875e8d0 fix: replace 'source .env' with safe env loader in all scripts
All checks were successful
Deploy to Production / test (push) Successful in 34s
The raw 'source .env' pattern breaks when values contain special bash
characters like ) in passwords or database URLs. This caused deploy:remote
to fail with 'syntax error near unexpected token )'.

Changes:
- Created shared/scripts/lib/load-env.sh: reads .env line-by-line with
  export instead of source, safely handling special characters
- Updated db-backup.sh, db-restore.sh, deploy-remote.sh, remote.sh to
  use the shared loader
- Reordered deploy-remote.sh: git pull now runs first (step 1) so the
  remote always has the latest scripts before running backup (step 2)
2026-02-13 14:46:30 +01:00
syntaxbullet
aca5538d57 chore: improve DX scripts, fix test suite, and harden tooling
All checks were successful
Deploy to Production / test (push) Successful in 32s
Scripts:
- remote.sh: remove unused open_browser() function
- deploy-remote.sh: add DB backup before deploy, --skip-backup flag, step numbering
- db-backup.sh: fix macOS compat (xargs -r is GNU-only), use portable approach
- db-restore.sh: add safety backup before restore, SQL file validation, file size display
- logs.sh: default to no-follow with --tail=100, order-independent arg parsing
- docker-cleanup.sh: add Docker health check, colored output
- test-sequential.sh: exclude *.integration.test.ts by default, add --integration flag
- simulate-ci.sh: pass --integration flag (has real DB)

Tests:
- db.test.ts: fix mock path from ./DrizzleClient to @shared/db/DrizzleClient
- server.settings.test.ts: rewrite mocks for gameSettingsService (old config/saveConfig removed)
- server.test.ts: add missing config.lootdrop and BotClient mocks, complete DrizzleClient chain
- indexes.test.ts: rename to indexes.integration.test.ts (requires live DB)

Config:
- package.json: test script uses sequential runner, add test:ci and db:restore aliases
- deploy.yml: use --integration flag in CI (has Postgres service)
2026-02-13 14:39:02 +01:00
syntaxbullet
0c67a8754f refactor: Implement Zod schema validation for inventory effect payloads and enhance item route DTO type safety.
Some checks failed
Deploy to Production / test (push) Failing after 38s
2026-02-13 14:12:46 +01:00
syntaxbullet
099601ce6d refactor: convert ModerationService and PruneService from classes to singleton objects
- Convert ModerationService class to moderationService singleton
- Convert PruneService class to pruneService singleton
- Update all command files to use new singleton imports
- Update web routes to use new singleton imports
- Update tests for singleton pattern
- Remove getNextCaseId from tests (now private module function)
2026-02-13 13:33:58 +01:00
syntaxbullet
55d2376ca1 refactor: convert LootdropService from class to singleton object pattern
- Move instance properties to module-level state (channelActivity, channelCooldowns)
- Convert constructor cleanup interval to module-level initialization
- Export state variables for testing
- Update tests to use direct state access instead of (service as any)
- Maintains same behavior while following project service pattern

Closes #4
2026-02-13 13:28:46 +01:00
syntaxbullet
6eb4a32a12 refactor: consolidate config types and remove file-based config
Tickets: #2, #3

- Remove duplicate type definitions from shared/lib/config.ts
- Import types from schema files (game-settings.ts, guild-settings.ts)
- Add GuildConfig interface to guild-settings.ts schema
- Rename ModerationConfig to ModerationCaseConfig in moderation.service.ts
- Delete shared/config/config.json and shared/scripts/migrate-config-to-db.ts
- Update settings API to use gameSettingsService exclusively
- Return DB format (strings) from API instead of runtime BigInts
- Fix moderation service tests to pass config as parameter

Breaking Changes:
- Removes legacy file-based configuration system
- API now returns database format with string values for BigInt fields
2026-02-13 13:24:02 +01:00
syntaxbullet
2d35a5eabb feat: Introduce TimerKey enum and refactor timer key usage across services with new tests.
Some checks failed
Deploy to Production / test (push) Failing after 27s
2026-02-13 13:11:16 +01:00
syntaxbullet
c2b1fb6db1 feat: implement database-backed game settings with a new schema, service, and migration script.
Some checks failed
Deploy to Production / test (push) Failing after 26s
2026-02-12 16:42:40 +01:00
syntaxbullet
58374d1746 refactor: migrate all code to use getGuildConfig() for guild settings
- Update all commands and events to fetch guild config once per execution
- Pass config to service methods that need it (ModerationService.issueWarning)
- Update terminal service to use guildSettingsService for persistence
- Remove direct imports of config for guild-specific settings

This consolidates configuration to database-backed guild settings,
eliminating the dual config system.
2026-02-12 16:09:37 +01:00
syntaxbullet
610d97bde3 feat(scripts): add config migration script for guild settings
Add script to migrate existing config.json values to database with
bun run db:migrate-config command.
2026-02-12 15:02:05 +01:00
syntaxbullet
babccfd08a feat(config): add getGuildConfig() for database-backed guild settings
Add function to fetch guild-specific config from database with:
- 60-second cache TTL
- Fallback to file-based config for migration period
- Cache invalidation helper
2026-02-12 15:00:21 +01:00
syntaxbullet
ee7d63df3e feat(service): add guild settings service layer
Implement service for managing per-guild configuration with methods for
getting, upserting, updating, and deleting settings. Includes helpers
for color role management.
2026-02-12 14:58:41 +01:00
syntaxbullet
5f107d03a7 feat(db): add guild_settings table for per-guild configuration
Store guild-specific settings (roles, channels, moderation options) in
database instead of config file, enabling per-guild configuration and
runtime updates without redeployment.
2026-02-12 14:57:24 +01:00
syntaxbullet
228005322e feat(commands): add beta feature flag support to command system
- Add beta and featureFlag properties to Command interface
- Add beta access check in CommandHandler before command execution
- Show beta feature message to non-whitelisted users
2026-02-12 14:45:58 +01:00
syntaxbullet
67a3aa4b0f feat(service): add feature flags service layer
Implement service for managing feature flags and access control with
methods for checking access, creating/enabling flags, and managing
whitelisted users/guilds/roles.
2026-02-12 14:43:11 +01:00
syntaxbullet
64804f7066 feat(db): add feature flags schema for beta feature testing
Add feature_flags and feature_flag_access tables to support controlled
beta testing of new features in production without a separate test environment.
2026-02-12 14:41:12 +01:00
syntaxbullet
8c306fbd23 refactor(inventory): flatten effects directory structure
Move effect handlers from effects/ subdirectory to flat structure:
- effects/handlers.ts → effect.handlers.ts
- effects/registry.ts → effect.registry.ts
- effects/types.ts → effect.types.ts

Update import path in inventory.service.ts from
'@/modules/inventory/effects/registry' to
'@/modules/inventory/effect.registry'.

This reduces directory nesting and follows the convention of
keeping module files flat unless there are 5+ files.
2026-02-12 12:15:17 +01:00
syntaxbullet
b0c3baf5b7 refactor(db): split schema into domain modules
Split the 276-line schema.ts into focused domain modules:
- users.ts: classes, users, userTimers (core identity)
- inventory.ts: items, inventory (item system)
- economy.ts: transactions, itemTransactions (currency flow)
- quests.ts: quests, userQuests (quest system)
- moderation.ts: moderationCases, lootdrops (moderation)

Original schema.ts now re-exports from schema/index.ts for backward
compatibility. All existing imports continue to work.
2026-02-12 12:14:15 +01:00