Simplify workspace composition root
This commit is contained in:
35
TASKS.md
35
TASKS.md
@@ -19,8 +19,8 @@ The user-visible proof is intentionally boring: after starting the app, logging
|
||||
- [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.
|
||||
- [x] (2026-04-04 23:20Z) Completed backend roll decomposition. Dice execution now lives in `RollEngine`, `StandardRollEngine`, `D6RollEngine`, and `RolemasterRollEngine`, while `RollBreakdownFormatter` and `CampaignLogSummaryBuilder` own the extracted formatting and compact-log helpers.
|
||||
- [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 remaining code changes land so the documentation reflects the final, not intermediate, structure. Completed in this iteration: backend helper descriptions and current remaining scope.
|
||||
- [x] (2026-04-04 23:17Z) Finished thinning `RpgRoller/Components/Pages/Workspace.razor.cs`. The mirror block is gone, the Razor file binds through `State` and coordinator surfaces directly, and `WorkspaceState` now owns the pure owner-label and skill-label projections.
|
||||
- [x] (2026-04-04 23:17Z) Updated `README.md` and this ExecPlan so the documentation reflects the completed backend and frontend decomposition structure.
|
||||
|
||||
## Surprises & Discoveries
|
||||
|
||||
@@ -36,6 +36,9 @@ The user-visible proof is intentionally boring: after starting the app, logging
|
||||
- Observation: the roll split preserved behavior cleanly because the extracted helper boundaries were already pure and ruleset-scoped.
|
||||
Evidence: after moving dice execution into ruleset engines and moving summary text into `CampaignLogSummaryBuilder`, the existing D6, Rolemaster, log paging, detail, custom-roll, and Playwright smoke tests passed without contract changes.
|
||||
|
||||
- Observation: the frontend cleanup was safer once the Razor file bound straight to `State` because the mirror aliases were only indirection, not logic.
|
||||
Evidence: removing the alias block from `Workspace.razor.cs` did not require coordinator behavior changes; the existing smoke tests still covered play, custom rolls, and Rolemaster UI flows successfully.
|
||||
|
||||
- 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`.
|
||||
|
||||
@@ -67,6 +70,10 @@ The user-visible proof is intentionally boring: after starting the app, logging
|
||||
Rationale: the new engines depend only on `IDiceRoller`, so local construction keeps the facade wiring small while still carving the algorithmic work out of the service orchestration path.
|
||||
Date/Author: 2026-04-04 / Codex
|
||||
|
||||
- Decision: Keep a few tiny wrapper methods in `Workspace.razor.cs` only where they break coordinator-construction cycles or support component-local lifecycle behavior.
|
||||
Rationale: direct binding through `State`, `Session`, `Campaigns`, `Play`, `Admin`, `Scope`, and `Live` removed the noisy aliases, but a minimal set of wrapper methods still keeps lazy coordinator construction acyclic and the composition root readable.
|
||||
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
|
||||
@@ -75,7 +82,7 @@ The user-visible proof is intentionally boring: after starting the app, logging
|
||||
|
||||
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 before. The repository now needs the final `Workspace` binding cleanup. `GameService` is already at the intended facade shape, and `GameRollService` is now primarily orchestration plus persistence-facing log record handling.
|
||||
The planned decomposition work is now complete. `GameService` is at the intended facade shape, `GameRollService` is primarily orchestration plus persistence-facing log record handling, and `Workspace.razor.cs` now reads as a composition root instead of a duplicated state bag.
|
||||
|
||||
## Context and Orientation
|
||||
|
||||
@@ -87,9 +94,7 @@ The current backend state is better than the old monolith. `RpgRoller/Services/G
|
||||
|
||||
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. Roll execution is now split across `RpgRoller/Services/RollEngine.cs`, `StandardRollEngine.cs`, `D6RollEngine.cs`, `RolemasterRollEngine.cs`, `RollBreakdownFormatter.cs`, and `CampaignLogSummaryBuilder.cs`, leaving `RpgRoller/Services/GameRollService.cs` as a smaller workflow coordinator.
|
||||
|
||||
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`.
|
||||
|
||||
The remaining frontend problem is that `RpgRoller/Components/Pages/Workspace.razor.cs` still mirrors a large amount of `WorkspaceState` into local alias properties and exposes many single-line wrapper methods only because the Razor file has not been fully retargeted to the composed surface. The next pass should delete those mirrors rather than add more wrappers.
|
||||
The frontend state is now at the intended shape. `RpgRoller/Components/Pages/WorkspaceState.cs` holds plain UI state plus pure computed and formatting 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`. `RpgRoller/Components/Pages/Workspace.razor.cs` is now mainly the composition root that wires those collaborators together.
|
||||
|
||||
## Plan of Work
|
||||
|
||||
@@ -134,7 +139,7 @@ Start every future implementation pass by re-reading the plan and checking the c
|
||||
git status --short
|
||||
rg --files RpgRoller/Services RpgRoller/Components/Pages
|
||||
|
||||
The remaining implementation pass is frontend-focused. Begin by inspecting the `Workspace` composition surface before editing:
|
||||
The implementation work is complete. If a future contributor needs to re-check the final frontend composition surface, start here:
|
||||
|
||||
Get-Content RpgRoller\Components\Pages\Workspace.razor.cs
|
||||
Get-Content RpgRoller\Components\Pages\Workspace.razor
|
||||
@@ -142,17 +147,7 @@ The remaining implementation pass is frontend-focused. Begin by inspecting the `
|
||||
Get-Content RpgRoller\Components\Pages\WorkspaceCampaignScopeCoordinator.cs
|
||||
Get-Content RpgRoller\Components\Pages\WorkspacePlayCoordinator.cs
|
||||
|
||||
Keep the next extraction small. Remove one block of mirrored state or pass-through wrappers at a time so component behavior can stay stable and the Playwright smoke flow can keep proving the result.
|
||||
|
||||
When beginning frontend cleanup, inspect the current composition surface before editing:
|
||||
|
||||
Get-Content RpgRoller\Components\Pages\Workspace.razor.cs
|
||||
Get-Content RpgRoller\Components\Pages\Workspace.razor
|
||||
Get-Content RpgRoller\Components\Pages\WorkspaceState.cs
|
||||
Get-Content RpgRoller\Components\Pages\WorkspaceCampaignScopeCoordinator.cs
|
||||
Get-Content RpgRoller\Components\Pages\WorkspacePlayCoordinator.cs
|
||||
|
||||
Move pure projections into `WorkspaceState`, simplify the composition root, and then retarget the Razor file to the composed surface. Keep the child components in `RpgRoller/Components/Pages/HomeControls/` stable unless a binding signature must change to support the cleanup.
|
||||
The final frontend layout keeps child-component contracts stable while binding through `State` and the coordinator surfaces directly.
|
||||
|
||||
When code work resumes later, validate after each meaningful iteration with the repo-standard commands:
|
||||
|
||||
@@ -163,7 +158,7 @@ The expected result is simple: no failing tests, no coverage regression, and the
|
||||
|
||||
## Validation and Acceptance
|
||||
|
||||
This implementation revision ran targeted helper tests during extraction and later full repo validation through `pwsh ./scripts/ci-local.ps1`. The same full validation remains mandatory after the frontend pass.
|
||||
This implementation revision ran targeted helper tests during extraction, added `WorkspaceState` tests for the new pure projections, and then ran full repo validation through `pwsh ./scripts/ci-local.ps1`.
|
||||
|
||||
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.
|
||||
|
||||
@@ -275,3 +270,5 @@ Revision note (2026-04-04): Replaced the old blueprint with an ExecPlan, reconci
|
||||
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.
|
||||
|
||||
Revision note (2026-04-04 23:20Z): Marked backend roll decomposition as complete after extracting `RollEngine`, the ruleset-specific engines, `RollBreakdownFormatter`, and `CampaignLogSummaryBuilder`. Updated the remaining scope so the next pass can focus entirely on `Workspace` cleanup.
|
||||
|
||||
Revision note (2026-04-04 23:17Z): Marked `Workspace` cleanup as complete after deleting the state-mirroring alias block, moving pure display helpers into `WorkspaceState`, rebinding the Razor file through `State` and coordinator surfaces, and adding `WorkspaceState` coverage tests.
|
||||
|
||||
Reference in New Issue
Block a user