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).
Goal
Introduce persistence and caching abstractions to support resumable sessions, leaderboards/statistics (future), and performance improvements via Redis.
Motivation
Scope
Implement a persistence layer for active game sessions (Redis) and historical archival (SQL) with clear repository abstractions.
Design Overview
Interfaces:
Data Flow:
Caching:
codele:words:v1Persistence Technologies:
CompletedGames(Id GUID PK, Attempts INT, Win BIT, DurationSeconds INT, CreatedUtc DATETIME2)Implementation Plan
Persistence:ArchiveCompletedGames(bool)Acceptance Criteria
Non-Goals
Risk & Mitigation
Observability
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).