Add GET /codes endpoint, enrich CodeResponse with location_name #14

Closed
opened 2026-03-16 19:52:47 +00:00 by forgejo_admin · 0 comments
Contributor

Lineage

plan-mcd-tracker → Phase 5 → Playground alignment gap (5d)

Repo

forgejo_admin/mcd-tracker-api

User Story

  • redeem: I need to see ALL my active codes across all locations in one list
  • history: I need codes with location names, not just IDs

Architecture

  • arch-dataflow-mcd-tracker#flow-3-redeem-bogo — user opens codes page, sees all active codes

Context

Playground review found two gaps:

  1. codes.html shows all user's codes across all locations, but API only has GET /locations/{id}/codes (per-location). Need GET /codes that lists all codes for the user.
  2. codes.html shows location name on each code card, but CodeResponse only has location_id. Need location_name in the response.

File Targets

Files to modify:

  • src/mcd_tracker_api/routes/locations.py — add GET /codes endpoint (list all user's codes, joined with location)
  • src/mcd_tracker_api/schemas.py — add location_name to CodeResponse, optionally create CodeWithLocationResponse
  • src/mcd_tracker_api/main.py — register new route if separate router
  • tests/test_locations.py — tests for GET /codes: list all, filter by status (active/redeemed/expired), user isolation

Files NOT to touch:

  • models.py — no schema changes
  • alembic/ — no migration

Acceptance Criteria

  • GET /codes returns all codes for authenticated user across all locations
  • Each code includes location_name (joined from Location table)
  • Optional query param ?status=active filters to active only (expires_at > now, not redeemed)
  • Optional query param ?status=redeemed filters to redeemed only
  • Optional query param ?status=expired filters to expired only (expires_at <= now)
  • No status param returns all codes
  • Results sorted by earned_at descending (newest first)
  • User isolation: user A can't see user B's codes
  • All existing tests still pass

Test Expectations

  • test: GET /codes returns codes from multiple locations
  • test: GET /codes?status=active returns only active
  • test: GET /codes?status=redeemed returns only redeemed
  • test: user isolation
  • test: each code has location_name field
  • Run: pytest tests/ -v

Constraints

  • Join Location table in query to get location_name — avoid N+1
  • Keep existing GET /locations/{id}/codes unchanged (backwards compatible)
  • Use same CodeResponse schema with added location_name: str | None field

Checklist

  • PR opened with Closes #13
  • Tests pass
  • Ruff clean
  • phase-mcd-tracker-5-core-api — parent phase
  • plan-mcd-tracker — parent plan
### Lineage `plan-mcd-tracker` → Phase 5 → Playground alignment gap (5d) ### Repo `forgejo_admin/mcd-tracker-api` ### User Story - `redeem`: I need to see ALL my active codes across all locations in one list - `history`: I need codes with location names, not just IDs ### Architecture - `arch-dataflow-mcd-tracker#flow-3-redeem-bogo` — user opens codes page, sees all active codes ### Context Playground review found two gaps: 1. `codes.html` shows all user's codes across all locations, but API only has `GET /locations/{id}/codes` (per-location). Need `GET /codes` that lists all codes for the user. 2. `codes.html` shows location name on each code card, but `CodeResponse` only has `location_id`. Need `location_name` in the response. ### File Targets Files to modify: - `src/mcd_tracker_api/routes/locations.py` — add `GET /codes` endpoint (list all user's codes, joined with location) - `src/mcd_tracker_api/schemas.py` — add `location_name` to `CodeResponse`, optionally create `CodeWithLocationResponse` - `src/mcd_tracker_api/main.py` — register new route if separate router - `tests/test_locations.py` — tests for GET /codes: list all, filter by status (active/redeemed/expired), user isolation Files NOT to touch: - models.py — no schema changes - alembic/ — no migration ### Acceptance Criteria - [ ] `GET /codes` returns all codes for authenticated user across all locations - [ ] Each code includes `location_name` (joined from Location table) - [ ] Optional query param `?status=active` filters to active only (expires_at > now, not redeemed) - [ ] Optional query param `?status=redeemed` filters to redeemed only - [ ] Optional query param `?status=expired` filters to expired only (expires_at <= now) - [ ] No status param returns all codes - [ ] Results sorted by earned_at descending (newest first) - [ ] User isolation: user A can't see user B's codes - [ ] All existing tests still pass ### Test Expectations - [ ] test: GET /codes returns codes from multiple locations - [ ] test: GET /codes?status=active returns only active - [ ] test: GET /codes?status=redeemed returns only redeemed - [ ] test: user isolation - [ ] test: each code has location_name field - Run: `pytest tests/ -v` ### Constraints - Join Location table in query to get location_name — avoid N+1 - Keep existing `GET /locations/{id}/codes` unchanged (backwards compatible) - Use same `CodeResponse` schema with added `location_name: str | None` field ### Checklist - [ ] PR opened with `Closes #13` - [ ] Tests pass - [ ] Ruff clean ### Related - `phase-mcd-tracker-5-core-api` — parent phase - `plan-mcd-tracker` — parent plan
Commenting is not possible because the repository is archived.
No labels
No milestone
No project
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ldraney/mcd-tracker-api#14
No description provided.