Skip to content

Single-club resolution service + typed club errors from club-scoped apps #180

Description

@Sootopolis

Follow-up to the use-club verify work (#173). We currently answer "is this club OK?" three incompatible ways: Club.selectBySlug (exact DB match, no recovery) gates job submission; ClubSlugRenameResolver (DB + board + admin tiers) lives inside the apps; and the CLI string-matches error.startsWith("Club not found"). There is no single-club verification against the DB — let alone Chess.com — and no route for one.

Proposal

1. One shared single-club resolver returning a typed verdict ADT:

sealed trait ClubStatus
  case Known(club: Club)                 // in our DB under this canonical slug
  case Renamed(from: ClubSlug, club: Club) // old slug 404s; recovered to a new canonical one
  case OnChessComOnly(apiClub: ApiClub)  // exists on Chess.com, never ingested into our DB
  case NotFound(slug: ClubSlug)          // 404 everywhere, no recovery
  case Problematic(slug: ClubSlug, reason) // tombstoned / cancelled / other

DB-first; then rename recovery (reuse ClubSlugRenameResolver); then an opt-in Chess.com fetch (reuse ChessComClient.getCacheable[ApiClub]) so OnChessComOnly / NotFound are only reached when a caller asks to pay the external request.

2. Two consumers:

  • GET /api/clubs/{slug} returning the verdict. Powers use-club's verify (graduating it from managed-vs-not to a real existence check), the deferred interactive add-prompt, and a possible ccas club verify <slug>.
  • Replace the Club.selectBySlug gate in JobRoutes.submitClubJob with the resolver. This makes rename recovery reachable at submission (closes Club rename: stale completion suggestion, and ClubSlugRenameResolver is unreachable from job submission #176) and lets a Renamed verdict flow back so the CLI can auto-repoint current_club + the cache.

3. Type the wire error. ClubJobResult/JobResult currently carry only error: Option[String]. Add a discriminant (ClubProblem enum: NotFound / Renamed(to) / NotManaged / Problematic) so the CLI branches on it instead of startsWith("Club not found"), and so Renamed carries the new slug.

Caveats to bake in

Dissolves / unblocks

Design proposal — refine before building. Needs a decision on how far the Chess.com-hitting path is exposed vs gated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:serverBackend HTTP server, jobs, schedulerenhancementNew feature or requestpending-decisionWaiting on a direction to be chosen

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions