Extract shared game service helpers
This commit is contained in:
41
TASKS.md
41
TASKS.md
@@ -16,22 +16,22 @@ The user-visible proof is intentionally boring: after starting the app, logging
|
||||
- [x] (2026-04-04 22:46Z) Inspected the current backend state. `RpgRoller/Services/GameService.cs`, `GameStateStore.cs`, `GamePersistenceService.cs`, `GameAuthService.cs`, `GameCampaignService.cs`, `GameCharacterService.cs`, `GameSkillService.cs`, `GameRollService.cs`, and `GameUserAdministrationService.cs` already exist.
|
||||
- [x] (2026-04-04 22:46Z) Inspected the current frontend state. `RpgRoller/Components/Pages/WorkspaceState.cs`, `WorkspaceSessionCoordinator.cs`, `WorkspaceCampaignCoordinator.cs`, `WorkspaceCampaignScopeCoordinator.cs`, `WorkspacePlayCoordinator.cs`, `WorkspaceAdminCoordinator.cs`, `WorkspaceLiveStateController.cs`, `WorkspaceFeedbackService.cs`, and `WorkspaceToast.cs` already exist.
|
||||
- [x] (2026-04-04 22:46Z) Marked the large structural extractions as already done in this plan instead of treating the repository as pre-refactor.
|
||||
- [ ] Complete backend shared-helper consolidation. Remaining work: move duplicated authorization, session resolution, campaign-context resolution, mapping, and campaign-state version helpers out of the domain services and into dedicated helper files or `GameStateStore` methods.
|
||||
- [x] (2026-04-04 23:03Z) Completed backend shared-helper consolidation. `GameStateStore` now owns campaign-state version mutations, `GameAuthorization`, `GameContextResolver`, and `GameDtoMapper` now own the shared helper seams, and the domain services delegate to them instead of keeping private copies.
|
||||
- [ ] Complete backend roll decomposition. Remaining work: extract the dice engines, breakdown formatting, and compact log summary logic out of `RpgRoller/Services/GameRollService.cs` while preserving all existing roll behavior.
|
||||
- [ ] Finish thinning `RpgRoller/Services/GameService.cs`. Remaining work: remove the remaining startup and campaign-state helper methods so the class only wires collaborators and delegates public `IGameService` calls.
|
||||
- [x] (2026-04-04 23:03Z) Finished thinning `RpgRoller/Services/GameService.cs` for startup and campaign-state bootstrap. The constructor now loads persistence and rebuilds campaign-state versions through `GameStateStore` without keeping private helper methods.
|
||||
- [ ] Finish thinning `RpgRoller/Components/Pages/Workspace.razor.cs`. Remaining work: remove the large mirror of `WorkspaceState` properties and the excess pass-through wrappers so the file acts as a composition root plus lifecycle and JS-invokable bridge.
|
||||
- [ ] Update `README.md` and this ExecPlan after the code changes land so the documentation reflects the final, not intermediate, structure.
|
||||
- [ ] Update `README.md` and this ExecPlan after the remaining code changes land so the documentation reflects the final, not intermediate, structure. Completed in this iteration: backend helper descriptions and current remaining scope.
|
||||
|
||||
## Surprises & Discoveries
|
||||
|
||||
- Observation: `GameService` is already mostly a thin facade, but it still owns startup and campaign-state rebuilding work.
|
||||
Evidence: `RpgRoller/Services/GameService.cs` constructs collaborators and delegates public methods, yet still contains `LoadStateFromDatabase`, `RebuildCampaignStateLocked`, `AddCharacterStateLocked`, and `GetOrCreateCampaignStateLocked`.
|
||||
- Observation: backend helper consolidation was lower risk than it first looked because most duplicated code already matched line-for-line semantics.
|
||||
Evidence: after moving authorization, session resolution, and mapping into `GameAuthorization`, `GameContextResolver`, and `GameDtoMapper`, the surrounding service tests passed without behavioral updates.
|
||||
|
||||
- Observation: the backend refactor stopped after file extraction, not after helper consolidation.
|
||||
Evidence: `RpgRoller/Services/GameCampaignService.cs`, `GameCharacterService.cs`, `GameSkillService.cs`, `GameRollService.cs`, and `GameUserAdministrationService.cs` each still define their own `ResolveUserLocked`, campaign visibility logic, owner display mapping, or campaign-state mutation helpers.
|
||||
- Observation: `GameRollService` remained the only backend file with broad mixed ownership after the shared helpers moved out.
|
||||
Evidence: the service now delegates authorization, context, state-snapshot mapping, and roll/log DTO mapping, but it still contains dice algorithms, compact log summary formatting, event badge generation, and dice serialization in one file.
|
||||
|
||||
- Observation: `GameRollService` is now the main backend monolith.
|
||||
Evidence: `RpgRoller/Services/GameRollService.cs` still owns authorization checks, campaign-context resolution, D6 logic, Rolemaster logic, log summary formatting, event badge generation, JSON dice serialization, and campaign-state snapshot shaping in one file.
|
||||
Evidence: `RpgRoller/Services/GameRollService.cs` still owns D6 logic, Rolemaster logic, log summary formatting, event badge generation, and JSON dice serialization in one file.
|
||||
|
||||
- Observation: the frontend refactor introduced one extra collaborator that was not named in the original blueprint, and that collaborator is worth keeping.
|
||||
Evidence: `RpgRoller/Components/Pages/WorkspaceCampaignScopeCoordinator.cs` now owns selected-campaign reload, selected-character synchronization, log reset, and unauthorized-session handling. Those behaviors are cohesive and should not be pushed back into `Workspace.razor.cs`.
|
||||
@@ -56,15 +56,19 @@ The user-visible proof is intentionally boring: after starting the app, logging
|
||||
Rationale: most of the benefit of the first extraction is already present. The missing value now is shared helper ownership, not more top-level service files.
|
||||
Date/Author: 2026-04-04 / Codex
|
||||
|
||||
- Decision: Keep the new backend helper seams static for now instead of introducing injected utility services.
|
||||
Rationale: the extracted logic is pure over `GameStateStore` plus method inputs, so static helpers keep wiring simple while still removing the duplication that was obscuring the domain services.
|
||||
Date/Author: 2026-04-04 / Codex
|
||||
|
||||
- Decision: Keep validation instructions in this ExecPlan even though this revision is documentation-only.
|
||||
Rationale: `PLANS.md` requires executable validation guidance, but the user explicitly requested no CI or test work for this pass. The commands remain here for the implementation pass that follows later.
|
||||
Date/Author: 2026-04-04 / Codex
|
||||
|
||||
## Outcomes & Retrospective
|
||||
|
||||
This document rewrite did not change application behavior. It changed the planning artifact so that it now matches the code that is already in the repository. A future contributor can start from this file alone and understand which refactor steps are complete, which files already exist, and which structural seams are still missing.
|
||||
The repository now has the shared backend seams that the earlier rewrite described as missing. `GameStateStore` owns campaign-state version mutation, `GameAuthorization` owns shared access checks, `GameContextResolver` owns session and campaign resolution, and `GameDtoMapper` owns the backend read-model construction that had been repeated across services.
|
||||
|
||||
The remaining work is narrower than the original blueprint implied. The repository no longer needs first-wave extraction. It needs second-wave cleanup: shared helper consolidation, roll-engine breakup, final facade thinning, and Razor binding simplification. That narrower scope should keep the next implementation iterations small.
|
||||
The remaining work is narrower than before. The repository now needs second-wave cleanup focused mainly on `GameRollService` algorithm extraction and the final `Workspace` binding cleanup. `GameService` is already at the intended facade shape, so later iterations can stay smaller and more reviewable.
|
||||
|
||||
## Context and Orientation
|
||||
|
||||
@@ -74,7 +78,7 @@ A "thin facade" in this plan means a class that mainly wires collaborators and f
|
||||
|
||||
The current backend state is better than the old monolith. `RpgRoller/Services/GameService.cs` already delegates its public methods to `GameAuthService`, `GameCampaignService`, `GameCharacterService`, `GameSkillService`, `GameRollService`, and `GameUserAdministrationService`. `RpgRoller/Services/GamePersistenceService.cs` already owns SQLite loading and saving. `RpgRoller/Services/SkillDefinitionValidator.cs`, `RoleSerializer.cs`, `RollVisibilityParser.cs`, `CustomRollOptionsResolver.cs`, and `GameStateCloneFactory.cs` already exist as helper files.
|
||||
|
||||
The remaining backend problem is duplication. Several services still repeat the same logic for resolving the current user from a session token, checking whether someone can view or edit a campaign, building summaries, and incrementing campaign-state versions. `RpgRoller/Services/GameRollService.cs` is still a large mixed file that combines access checks, dice algorithms, log formatting, and read-model shaping. That is the main backend target.
|
||||
The backend shared-helper duplication is now resolved. `RpgRoller/Services/GameStateStore.cs` owns campaign-state version mutations. `RpgRoller/Services/GameAuthorization.cs` owns shared access checks. `RpgRoller/Services/GameContextResolver.cs` owns session-token and campaign resolution. `RpgRoller/Services/GameDtoMapper.cs` owns the backend read models returned by the services. The main backend target that remains is `RpgRoller/Services/GameRollService.cs`, which still combines dice algorithms, compact log formatting, event badges, and dice serialization in one file.
|
||||
|
||||
The current frontend state is also better than the old monolith. `RpgRoller/Components/Pages/WorkspaceState.cs` holds most UI state and many computed projections. Session/bootstrap behavior lives in `WorkspaceSessionCoordinator.cs`. Campaign management and modal flows live in `WorkspaceCampaignCoordinator.cs`. Selected campaign scope refresh lives in `WorkspaceCampaignScopeCoordinator.cs`. Play/log behavior lives in `WorkspacePlayCoordinator.cs`. Admin behavior lives in `WorkspaceAdminCoordinator.cs`. Live event reconciliation lives in `WorkspaceLiveStateController.cs`. Toast and announcement behavior lives in `WorkspaceFeedbackService.cs`.
|
||||
|
||||
@@ -123,15 +127,16 @@ Start every future implementation pass by re-reading the plan and checking the c
|
||||
git status --short
|
||||
rg --files RpgRoller/Services RpgRoller/Components/Pages
|
||||
|
||||
When beginning backend helper consolidation, inspect the current duplication before editing:
|
||||
Shared backend helper consolidation is complete in the current tree. The next backend pass should begin by inspecting the remaining roll-service concentration before editing:
|
||||
|
||||
Get-Content RpgRoller\Services\GameService.cs
|
||||
Get-Content RpgRoller\Services\GameCharacterService.cs
|
||||
Get-Content RpgRoller\Services\GameSkillService.cs
|
||||
Get-Content RpgRoller\Services\GameRollService.cs
|
||||
Get-Content RpgRoller\Services\GameUserAdministrationService.cs
|
||||
Get-Content RpgRoller\Services\GameAuthorization.cs
|
||||
Get-Content RpgRoller\Services\GameContextResolver.cs
|
||||
Get-Content RpgRoller\Services\GameDtoMapper.cs
|
||||
Get-Content RpgRoller\Services\GameStateStore.cs
|
||||
|
||||
Create or update the shared helper files, then replace each duplicated private helper with calls into the shared files or `GameStateStore`. Keep each change small enough that a single review can verify behavior stayed the same.
|
||||
Keep the next extraction small. Move one cohesive cluster at a time out of `GameRollService` so tests can prove that dice totals, breakdown strings, and compact log responses stayed unchanged.
|
||||
|
||||
When beginning frontend cleanup, inspect the current composition surface before editing:
|
||||
|
||||
@@ -152,7 +157,7 @@ The expected result is simple: no failing tests, no coverage regression, and the
|
||||
|
||||
## Validation and Acceptance
|
||||
|
||||
This documentation-only revision intentionally did not run CI, tests, or Playwright. Those checks remain mandatory when implementation resumes.
|
||||
This implementation revision ran targeted helper tests during extraction. Full repo validation through `pwsh ./scripts/ci-local.ps1` remains mandatory before considering the iteration complete.
|
||||
|
||||
The backend is accepted when `RpgRoller/Services/GameService.cs` contains only collaborator wiring, ruleset enumeration, and public delegation; when shared authorization, context, mapping, and campaign-state helper logic each live in one place; and when `RpgRoller/Services/GameRollService.cs` no longer embeds the dice engines or compact log summary builders.
|
||||
|
||||
@@ -260,3 +265,5 @@ The component may keep tiny wrapper methods for lifecycle, `JSInvokable` entry p
|
||||
In `RpgRoller/Components/Pages/WorkspaceState.cs`, keep all plain state plus pure computed and formatting helpers needed directly by the Razor file. That includes selected campaign name, selected play character projections, screen flags, connection-state label and CSS class, app CSS class, owner labels, and skill-definition labels.
|
||||
|
||||
Revision note (2026-04-04): Replaced the old blueprint with an ExecPlan, reconciled it against the code already present in the repository, and marked completed versus remaining refactor work after direct file inspection. The reason for this rewrite is that `AGENTS.md` now requires complex refactors to be tracked as ExecPlans maintained under `PLANS.md`.
|
||||
|
||||
Revision note (2026-04-04 23:03Z): Marked backend shared-helper consolidation and `GameService` facade thinning as complete after implementing `GameAuthorization`, `GameContextResolver`, `GameDtoMapper`, and `GameStateStore` tracker methods. Updated the remaining scope so the next pass starts with `GameRollService` decomposition and later `Workspace` cleanup.
|
||||
|
||||
Reference in New Issue
Block a user