refactor(sponsor): migrate SponsorController to CQRS handlers #750

Open
opened 2026-07-20 21:18:18 +00:00 by spikerj · 1 comment
Owner

Follow-up from the Sponsor a Journey work. The entire Sponsor feature is controller-direct (raw SpikerDbContext in SpikerSoft.Api/Domain/Sponsor/SponsorController.cs, ~10+ endpoints) while the rest of Profile/Parental uses CQRS MediatR handlers under SpikerSoft.Business. The family-grouping work kept parity (pure logic extracted to SponsorFamilyBuilder) rather than half-migrating. Migrate the Sponsor queries/commands to SpikerSoft.Business/Domain/Sponsor/{Queries,Commands}/ per api-conventions (validation/caching pipeline; the public list + families queries are good caching candidates).

Repo: spikersoft-backend

Follow-up from the Sponsor a Journey work. The entire Sponsor feature is controller-direct (raw SpikerDbContext in SpikerSoft.Api/Domain/Sponsor/SponsorController.cs, ~10+ endpoints) while the rest of Profile/Parental uses CQRS MediatR handlers under SpikerSoft.Business. The family-grouping work kept parity (pure logic extracted to SponsorFamilyBuilder) rather than half-migrating. Migrate the Sponsor queries/commands to SpikerSoft.Business/Domain/Sponsor/{Queries,Commands}/ per api-conventions (validation/caching pipeline; the public list + families queries are good caching candidates). Repo: spikersoft-backend
Author
Owner

Audited against origin/masterNOT DONE. No CQRS migration has started, and the controller has grown since filing.

  • SpikerSoft.Api/Domain/Sponsor/SponsorController.cs is 1080 lines with 16 endpoints, and uses SpikerDbContext / _context. directly at 34 sites.
  • Zero _mediator.Send / IMediator usage in the controller.
  • No handler tree exists at all: git ls-tree -r --name-only origin/master | grep -E "Business/Domain/Sponsor/(Queries|Commands)" returns nothing, and there is no Business/Domain/Sponsor directory of any kind.
  • The only commit matching --grep="#750" is d4b7d750, which is a coincidental short-SHA collision — it's the #749 family-grouping feature, not migration work.

So this is untouched, and meanwhile the controller has taken on new responsibilities: the #868 family-card epic added LoadAwardsByUserAsync and the fund-money payload work (#884) to it, and #871's TopAwards aggregation is wired through SponsorFamilyBuilder alongside it. The surface to migrate is larger now than when this was filed.

One thing worth deciding before starting. SponsorController is the anonymous /sponsor read path — the same code that the #873 consent gate (SponsorFamilyBuilder.cs:373-374, parent-gated child ages) and #871's display-name-only privacy boundary run through. A 1080-line, 34-site refactor across that surface is exactly where a consent gate gets dropped silently. If this proceeds, the SponsorFamilyBuilderTests privacy assertions (:375, :406) are the ones that must not be weakened to make the refactor pass — they're the only thing pinning that boundary.

Remaining: all of it. Given the COPPA-adjacent surface, migrating in slices with the privacy tests held fixed would be safer than one large change.

Audited against `origin/master` — **NOT DONE. No CQRS migration has started, and the controller has grown since filing.** - `SpikerSoft.Api/Domain/Sponsor/SponsorController.cs` is **1080 lines** with **16** endpoints, and uses `SpikerDbContext` / `_context.` directly at **34** sites. - **Zero** `_mediator.Send` / `IMediator` usage in the controller. - **No handler tree exists at all**: `git ls-tree -r --name-only origin/master | grep -E "Business/Domain/Sponsor/(Queries|Commands)"` returns **nothing**, and there is no `Business/Domain/Sponsor` directory of any kind. - The only commit matching `--grep="#750"` is `d4b7d750`, which is a coincidental short-SHA collision — it's the #749 family-grouping feature, not migration work. So this is untouched, and meanwhile the controller has taken on new responsibilities: the #868 family-card epic added `LoadAwardsByUserAsync` and the fund-money payload work (#884) to it, and #871's `TopAwards` aggregation is wired through `SponsorFamilyBuilder` alongside it. The surface to migrate is larger now than when this was filed. **One thing worth deciding before starting.** `SponsorController` is the anonymous `/sponsor` read path — the same code that the #873 consent gate (`SponsorFamilyBuilder.cs:373-374`, parent-gated child ages) and #871's display-name-only privacy boundary run through. A 1080-line, 34-site refactor across that surface is exactly where a consent gate gets dropped silently. If this proceeds, the `SponsorFamilyBuilderTests` privacy assertions (`:375`, `:406`) are the ones that must not be weakened to make the refactor pass — they're the only thing pinning that boundary. **Remaining:** all of it. Given the COPPA-adjacent surface, migrating in slices with the privacy tests held fixed would be safer than one large change.
Sign in to join this conversation.