Locations like Mt. Moon (with 1F, B1F, B2F floors) are now grouped so only one encounter can be logged per location group, enforcing Nuzlocke first-encounter rules correctly. - Add parent_route_id column with self-referential FK to routes table - Add parent/children relationships on Route model - Update games API to return hierarchical route structure - Add validation in encounters API to prevent parent route encounters and duplicate encounters within sibling routes (409 conflict) - Update frontend with collapsible RouteGroup component - Auto-derive route groups from PokeAPI location/location-area structure - Regenerate seed data with 70 parent routes and 315 child routes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
64 lines
3.2 KiB
Markdown
64 lines
3.2 KiB
Markdown
---
|
|
# nuzlocke-tracker-u7i9
|
|
title: Combine sub-areas into single locations
|
|
status: completed
|
|
type: feature
|
|
priority: normal
|
|
created_at: 2026-02-05T14:27:13Z
|
|
updated_at: 2026-02-06T09:56:11Z
|
|
parent: nuzlocke-tracker-f5ob
|
|
---
|
|
|
|
Some game locations have multiple encounter tables (e.g. Mount Moon 1F, Mount Moon B1F, Mount Moon B2F) but are treated as a single location for Nuzlocke first-encounter rules.
|
|
|
|
Needs a concept of 'location groups' — a parent location that contains multiple sub-areas, each with their own encounter table. For Nuzlocke purposes, the first encounter in *any* sub-area of the group counts as that location's encounter.
|
|
|
|
## Implementation Summary
|
|
|
|
Added hierarchical route grouping so locations like Mt. Moon (with floors 1F, B1F, B2F) are treated as a single location for Nuzlocke first-encounter rules. The first encounter in ANY sub-area counts as that location's encounter.
|
|
|
|
### Changes Made
|
|
|
|
1. **Database Migration** (`c3d4e5f6a7b8_add_route_grouping.py`)
|
|
- Added nullable `parent_route_id` column with self-referential FK (CASCADE delete)
|
|
|
|
2. **Backend Model** (`backend/src/app/models/route.py`)
|
|
- Added `parent_route_id` field
|
|
- Added self-referential `parent` and `children` relationships
|
|
|
|
3. **Backend Schemas** (`backend/src/app/schemas/game.py`)
|
|
- Added `parent_route_id` to `RouteResponse`, `RouteCreate`, `RouteUpdate`
|
|
- Added `RouteWithChildrenResponse` with nested children
|
|
|
|
4. **Backend API - Games** (`backend/src/app/api/games.py`)
|
|
- Updated `list_game_routes` to support hierarchical response (default) or flat list (`?flat=true`)
|
|
|
|
5. **Backend API - Encounters** (`backend/src/app/api/encounters.py`)
|
|
- Added validation: cannot create encounter on parent route (400 error)
|
|
- Added validation: cannot create encounter if sibling already has one (409 error)
|
|
|
|
6. **Frontend Types** (`frontend/src/types/game.ts`)
|
|
- Added `parentRouteId` to `Route` interface
|
|
- Added `RouteWithChildren` interface
|
|
|
|
7. **Frontend Page** (`frontend/src/pages/RunEncounters.tsx`)
|
|
- Added `organizeRoutes()` helper to build hierarchy from flat list
|
|
- Added `getGroupEncounter()` to check if any child has an encounter
|
|
- Updated progress counter to count groups (not individual sub-routes)
|
|
- Added collapsible `RouteGroup` component
|
|
- Sibling routes are disabled after one has an encounter
|
|
|
|
8. **Seed Data** (`backend/src/app/seeds/fetch_pokeapi.py`)
|
|
- Updated to automatically detect grouped locations from PokeAPI's location/location-area structure
|
|
- Parent routes have empty encounters; children have actual encounters
|
|
- 70 parent routes with 315 child routes across all games
|
|
|
|
9. **Seed Loader** (`backend/src/app/seeds/loader.py`, `run.py`)
|
|
- Updated `upsert_routes` to handle hierarchical structure with parent_route_id
|
|
- Updated seed runner to process child route encounters
|
|
|
|
## Considerations
|
|
- [x] Data model: add a parent_route_id or location_group concept to the Route model
|
|
- [x] Seed data: identify which routes should be grouped (automatically derived from PokeAPI location/area structure)
|
|
- [x] Encounter tracking: when logging an encounter in a sub-area, mark the whole group as visited
|
|
- [x] Route list UI: show grouped locations as collapsible sections |