Skip to content

Collapse the three collection endpoint modules into one generic owner-scoped module #97

Description

@mforce

What to build

Collapse the three collection endpoint modules (movies, music, games) into one generic owner-scoped collection endpoint module plus a thin per-type configuration.

The three endpoint files are 75–78% identical after renaming the entity token — the CRUD skeleton for movies vs games differs by zero lines. Auth, ownership scoping (hand-written in every handler), the page cap, tag filtering, validation strings, and cover/tag resolution are each re-declared per type; roughly 609 lines carry about 150 lines of genuinely distinct behavior. The distinct part is exactly: per-type filter parameters (movie format bitmask test, music format equality, game platform / digital / completion status), per-type DTO shape, and the game-specific PlatformLegacy clearing on update.

Build one generic module implementing list/get/create/update/delete with ownership scoping, paging, tag filtering, validation, and cover/tag resolution once, parameterized by a per-type config (DTO mapping, validator, filter strategy). Movies/Music/Games become declarations. Wire contracts must not change — routes, DTO shapes (including the movie Formats integer bitmask), status codes, and validation messages stay identical, which the parameterized endpoint test suite pins.

Acceptance criteria

  • Auth, ownership scoping, page cap, tag filtering, validation, and mapping are implemented once
  • Per-type filters and the PlatformLegacy clearing behavior are preserved via config
  • Wire contracts unchanged: the parameterized endpoint tests pass without modification
  • Adding a media type requires an entity plus a config declaration, not a new 200-line endpoint file

Blocked by

Added scope — F2: reflection guard that every write-boundary enum has a registered converter

Carried over from PR #141 review (issue #115 follow-up). Folded into this issue so the generic module ships with it from day one.

Problem: Program.cs hand-registers six enums (CollectionStatus, Condition, WatchStatus, CompletionStatus, DigitalStore, MusicFormat) with DefinedEnumConverter<TEnum>; GamePlatform gets GamePlatformJsonConverter; MovieFormat is an int bitmask validated in the module. Nothing today catches a forgotten registration. Under #97's "add a media type via config declaration, not a 200-line endpoint file" model, an author who adds a media type and omits the config declaration silently falls back to the permissive default converter — re-opening the hole #115 closed, with no test failure to warn.

Requirement (red-first TDD): a reflection test enumerates every concrete enum appearing in write DTO / endpoint bodies, and asserts the test's JsonSerializerOptions (mirroring Program.cs) has a registered converter (DefinedEnumConverter<TEnum> or GamePlatformJsonConverter). A brand-new enum with no registration must fail this named test with an actionable message naming the enum and the missing declaration (mutation-checked). MovieFormat is excluded (int bitmask, validated in the module); GamePlatform counts as covered via its dedicated converter. Non-goals (separate issues): F4 legacy-row heal path, 400-body normalization.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions