-
Notifications
You must be signed in to change notification settings - Fork 1
Open
Description
Goal
Introduce persistence and caching abstractions to support resumable sessions, leaderboards/statistics (future), and performance improvements via Redis.
Motivation
- Current implementation appears in-memory only; sessions disappear on restart.
- Redis + SQL Server already provisioned via Aspire but underutilized.
- Caching word lists and precomputed metadata reduces per-request computation and allocations.
Scope
Implement a persistence layer for active game sessions (Redis) and historical archival (SQL) with clear repository abstractions.
Design Overview
Interfaces:
- IGameSessionStore
- Task<GameSession?> GetAsync(gameId)
- Task SaveAsync(GameSession session)
- Task ExistsAsync(gameId)
- Optional: Task DeleteAsync(gameId) when complete
- ICompletedGameArchive
- Task ArchiveAsync(GameSessionSummary summary)
- IWordListCache
- Task<IReadOnlyList> GetAllAsync()
Data Flow:
- User starts game -> new GameSession created (Issue Refactor: Introduce Domain Services & Clean API Layer for Codele #8) -> stored in Redis via IGameSessionStore
- Each guess updates session then persists mutated state
- On completion, archive lightweight summary to SQL (GameId, Attempts, DurationSeconds, WinFlag, Timestamp)
- Optionally remove session from Redis after archival
Caching:
- Word list loaded once from embedded resource or file into Redis key
codele:words:v1 - Secondary cached structure: letter frequency map (Dictionary<char,int>) for analytics (stretch)
Persistence Technologies:
- Redis: StackExchange.Redis (already implicitly available in Aspire environment)
- SQL: Minimal table
CompletedGames(Id GUID PK, Attempts INT, Win BIT, DurationSeconds INT, CreatedUtc DATETIME2)
Implementation Plan
- Create data contracts (GameSession persistence model, GameSessionSummary)
- Implement RedisGameSessionStore (serialize with System.Text.Json source-gen for perf)
- Add SQL EF Core DbContext or Dapper micro layer for CompletedGames (keep minimal)
- Create migration / ensure table exists on startup (idempotent script)
- Implement WordListCache with warm-up on first request; store TTL (e.g., 24h) to allow refresh
- Integrate into GameService (from Issue Refactor: Introduce Domain Services & Clean API Layer for Codele #8) behind interfaces
- Add configuration toggles:
Persistence:ArchiveCompletedGames(bool) - Add metrics counters (games_started, games_completed, games_won) if OpenTelemetry metrics already wired (future if not in this issue)
- Tests: unit test serialization round-trip, store CRUD, archive path
Acceptance Criteria
- Starting a game produces a Redis key (inspect manually) containing session JSON
- Completing a game writes a row to SQL when archival enabled
- Word list served from cache after first load (log confirming cache hit)
- All new tests pass locally
Non-Goals
- Leaderboards API (future)
- Metrics exposition (future or separate issue)
Risk & Mitigation
- Redis serialization bloat -> use explicit DTO + source-gen context
- SQL migrations complexity -> keep single table, manual command or simple EF Core migration
Observability
- Log debug entries for cache warm, session save, archive
- (Optional) Add tracing span attributes: gameId, attemptCount
Definition of Done
PR merged with working Redis session persistence, SQL archival path, documentation in README, and tests.
Estimated Effort
Medium (5-7h).
Depends on: Issue #8 (domain service abstractions).
Metadata
Metadata
Assignees
Labels
No labels