Skip to content

Give the web layer a shape: services behind interfaces #40

Description

@elgorro

The web layer has no seam between HTTP and behaviour. src/Ssabba.Web/Endpoints/MatchEndpoints.cs
is 256 lines holding both the route mapping and MatchQueries, a static class that takes a
SsabbaDbContext and does the reading, the writing and the rating application. Nothing is
registered in DI beyond IDbContextFactory<SsabbaDbContext>, so there is no unit of behaviour to
name, to reuse, or to exercise without a database.

Standing up the test tiers (#37) made this concrete: every test of match behaviour has to go through
a container and an HTTP request, because there is nothing smaller to call.

This is not a request for indirection everywhere — the rule stays "real collaborators over doubles"
(#37). It is about giving the behaviour a shape.

Target shape

  • Models — entities stay classes in Ssabba.Domain.Entities; DTOs stay records in
    Ssabba.Shared. Unchanged, already right.
  • ServicesMatchService : IMatchService in a new src/Ssabba.Web/Services/ (or
    Ssabba.Application if it grows past the web host), taking IDbContextFactory<SsabbaDbContext>
    by constructor injection. MatchQueries.ListAsync / CreateAsync / ListTeamsAsync move onto it
    unchanged in behaviour.
  • Interfaces — one per service, declared next to it, registered with
    services.AddScoped<IMatchService, MatchService>() in a AddSsabbaServices extension mirroring
    AddSsabbaInfrastructure.
  • EndpointsMatchEndpoints shrinks to routing: take IMatchService, call it, map the result
    to a status code. No EF types in the file.
  • Components — server-rendered pages inject IMatchService rather than the context factory, so
    the CLAUDE.md rule ("server-rendered components and the API return identical results") is enforced
    by construction instead of by discipline.

Tasks

  • Add src/Ssabba.Web/Services/ with IMatchService / MatchService and an AddSsabbaServices
    registration extension
  • Move MatchQueries onto MatchService without behaviour change; delete the static class
  • Reduce MatchEndpoints.cs to mapping only
  • Point the Razor pages under Components/Pages at IMatchService
  • Update the CLAUDE.md "Conventions" entry that currently names MatchQueries
  • Keep the suite green; the service is exercised through the existing container fixture, not a mock

Follows #37. Worth doing before #21/#24 add more behaviour to the same file.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: domainEntities and rating maths (Ssabba.Domain)area: webBlazor host and API endpoints (Ssabba.Web)type: choreMaintenance, refactors, tooling

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions