Compare commits

2 Commits

Author SHA1 Message Date
c2e98b17ed Add bean 3a5n for seed data condition merge via PokeDB
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 22:48:23 +01:00
9029f1632a Add encounter condition support with rate display
Add a `condition` column to RouteEncounter for time-of-day, weather,
and season variants. Seed loader expands `conditions` dict into
per-condition rows. EncounterModal shows condition filter tabs with
per-condition encounter rates, and displays rates for all standard
encounter methods (walk, surf, fishing, etc.).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 22:42:49 +01:00
392 changed files with 21475 additions and 55634 deletions

View File

@@ -0,0 +1,19 @@
---
# nuzlocke-tracker-009n
title: Add CLI export for all seed data types
status: completed
type: feature
priority: normal
created_at: 2026-02-08T11:37:27Z
updated_at: 2026-02-08T11:38:48Z
---
Add export functions for games, pokemon, routes/encounters, and evolutions to the seed CLI, matching the existing export API endpoints. Consolidate with the existing --export-bosses into a single --export flag that dumps everything.
## Checklist
- [x] Add export_games() to run.py — writes games.json
- [x] Add export_pokemon() to run.py — writes pokemon.json
- [x] Add export_routes() to run.py — writes {game_slug}.json per game (routes + encounters)
- [x] Add export_evolutions() to run.py — writes evolutions.json
- [x] Replace --export-bosses with --export flag that exports all data types
- [x] Update __main__.py docstring

View File

@@ -0,0 +1,30 @@
---
# nuzlocke-tracker-0arz
title: Integration tests for Runs & Encounters API
status: draft
type: task
created_at: 2026-02-10T09:33:21Z
updated_at: 2026-02-10T09:33:21Z
parent: nuzlocke-tracker-yzpb
---
Write integration tests for the core run tracking and encounter API endpoints. This is the heart of the application.
## Checklist
- [ ] Test run CRUD operations (create, list, get, update, delete)
- [ ] Test run creation with rules configuration (JSONB field)
- [ ] Test encounter logging on a run (create encounter on a route)
- [ ] Test encounter status changes (alive → dead, alive → retired, etc.)
- [ ] Test duplicate encounter prevention (dupes clause logic)
- [ ] Test shiny encounter handling
- [ ] Test egg encounter handling
- [ ] Test ending a run (completion/failure)
- [ ] Test error cases (encounter on invalid route, duplicate route encounters, etc.)
## Notes
- Run endpoints: `backend/src/app/api/runs.py`
- Encounter endpoints: `backend/src/app/api/encounters.py`
- This is the most critical area — Nuzlocke rules enforcement should be thoroughly tested
- Tests need game + pokemon + route fixtures as prerequisites

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-0pas
title: Extract version groups and route ordering to JSON files
status: completed
type: task
priority: normal
created_at: 2026-02-07T13:27:37Z
updated_at: 2026-02-07T13:32:30Z
---
Move VERSION_GROUPS and ROUTE_ORDER from fetch_pokeapi.py into separate JSON files (version_groups.json, route_order.json) for easier editing. Update the script to load from the JSON files.

View File

@@ -0,0 +1,28 @@
---
# nuzlocke-tracker-0q8f
title: Encounter Tracking Interface
status: completed
type: task
priority: normal
created_at: 2026-02-04T15:44:37Z
updated_at: 2026-02-05T14:21:54Z
parent: nuzlocke-tracker-f5ob
---
Build the main interface for tracking encounters on each route/area.
## Checklist
- [x] Create route list component showing all areas in the game
- [x] Display encounter status per route (uncaught, caught, failed, skipped)
- [x] Build encounter modal/form:
- [x] Select Pokémon from route's available encounters
- [x] Enter nickname for caught Pokémon
- [x] Mark as caught, failed (ran/KO'd), or skipped (duplicates clause)
- [x] Show route progression (e.g., 15/45 routes completed)
- [x] Allow editing/updating existing encounters
- [x] Support marking gift/static encounters separately (deferred to nuzlocke-tracker-rxrt)
## UX Considerations
- Quick entry flow - minimize clicks to log an encounter
- Visual distinction between route types (grass, water, cave, etc.)
- Mobile-friendly for tracking while playing

View File

@@ -0,0 +1,50 @@
---
# nuzlocke-tracker-1e9k
title: Populate encounter data for Gen 8+ stub games
status: completed
type: task
priority: normal
created_at: 2026-02-10T08:59:02Z
updated_at: 2026-02-11T13:39:09Z
parent: nuzlocke-tracker-rzu4
---
Fill in encounter data for games that currently have null/stub seed files. These games are not covered by PokeAPI and require manual curation or an alternative data source.
## Games with null/stub data:
- [ ] Sword (null)
- [ ] Shield (null)
- [ ] Brilliant Diamond (null)
- [ ] Shining Pearl (null)
- [ ] Scarlet (null)
- [ ] Violet (null)
- [ ] Legends Arceus (null)
## Format requirements:
Each game's JSON file must follow the existing structure:
\`\`\`json
[
{
"name": "Route Name",
"order": 1,
"encounters": [
{
"pokeapi_id": 25,
"pokemon_name": "pikachu",
"method": "walk",
"encounter_rate": 10,
"min_level": 5,
"max_level": 8
}
],
"children": []
}
]
\`\`\`
## Notes:
- This is likely the largest manual task unless the "explore automated sources" task finds a viable alternative
- Depends on findings from the automated data sources task — if automation is viable, this becomes much easier
- Sword/Shield and Scarlet/Violet use open-world/Wild Area mechanics that may need special handling
- Legends Arceus has a fundamentally different encounter system (overworld encounters, alpha Pokémon, space-time distortions)
- BD/SP are remakes of Diamond/Pearl — existing D/P data could serve as a starting point

View File

@@ -0,0 +1,30 @@
---
# nuzlocke-tracker-1guz
title: Component tests for key frontend components
status: draft
type: task
created_at: 2026-02-10T09:33:45Z
updated_at: 2026-02-10T09:33:45Z
parent: nuzlocke-tracker-yzpb
---
Write component tests for the most important frontend React components, focusing on user interactions and rendering correctness.
## Checklist
- [ ] Test `EncounterModal` — form submission, validation, Pokemon selection
- [ ] Test `StatusChangeModal` — status transitions, confirmation flow
- [ ] Test `EndRunModal` — run completion/failure flow
- [ ] Test `GameGrid` — game selection rendering, click handling
- [ ] Test `RulesConfiguration` — rules toggle interactions, state management
- [ ] Test `Layout` — navigation rendering, responsive behavior
- [ ] Test admin form modals (GameFormModal, RouteFormModal, PokemonFormModal) — CRUD form flows
- [ ] Test `AdminTable` — sorting, filtering, action buttons
## Notes
- Focus on user-facing behavior, not implementation details
- Use @testing-library/user-event for simulating clicks, typing, etc.
- Mock API responses for components that fetch data
- Don't aim for 100% coverage — prioritise the most complex/interactive components
- Page components (RunEncounters, RunDashboard, etc.) are large and complex — consider testing their sub-components instead

View File

@@ -0,0 +1,34 @@
---
# nuzlocke-tracker-1iuh
title: Project Setup & Tech Stack
status: completed
type: task
priority: normal
created_at: 2026-02-04T15:43:55Z
updated_at: 2026-02-04T15:55:46Z
parent: nuzlocke-tracker-f5ob
blocking:
- nuzlocke-tracker-sm1b
- nuzlocke-tracker-k5lm
- nuzlocke-tracker-uw2j
- nuzlocke-tracker-dgax
- nuzlocke-tracker-0q8f
- nuzlocke-tracker-hm6t
- nuzlocke-tracker-8tuw
- nuzlocke-tracker-8fcj
---
Set up the initial project structure and choose the technology stack.
## Checklist
- [x] Initialize the project (e.g., Vite + React/Vue/Svelte or Next.js)
- [x] Set up TypeScript configuration
- [x] Configure linting (ESLint) and formatting (Prettier)
- [x] Set up basic folder structure (components, types, utils, data)
- [x] Add Tailwind CSS or chosen styling solution
- [x] Create basic app shell with routing
## Considerations
- Should be a web app for accessibility
- Consider PWA capabilities for offline use
- Keep bundle size small for fast loading

View File

@@ -0,0 +1,89 @@
---
# nuzlocke-tracker-25mh
title: Genlocke tracking
status: completed
type: epic
priority: normal
created_at: 2026-02-08T12:17:19Z
updated_at: 2026-02-09T11:07:51Z
---
Track a **genlocke** — a series of linked nuzlocke runs, typically one per generation or region. The player picks one game per generation/region and surviving Pokemon carry over between legs.
## User Flow
### 1. Create Genlocke
The user starts a new genlocke and gives it a name.
### 2. Select Games (Legs)
The user picks which games to play, in order. The UI offers **preset templates** to speed this up, but the user can always customize:
- **True Genlocke** — One original game per generation (Red/Blue/Yellow → Gold/Silver/Crystal → Ruby/Sapphire/Emerald → ...). Uses the original releases only.
- **Normal Genlocke** — Uses the latest remake or enhanced version for each region (FireRed/LeafGreen → HeartGold/SoulSilver → Emerald → Platinum → ...). This is the most common format.
- **Custom** — The user picks any games in any order. No restrictions on which games or how many.
For the preset templates, the user still picks *which* game within each generation/region slot (e.g., FireRed vs LeafGreen for Gen 1). The template just determines which slots are shown. The user can add/remove/reorder legs after selecting a template.
Games are grouped by **region** (not release generation) for the purpose of presets, since that's how genlocke players think about it (e.g., FireRed is a "Kanto" leg, not a "Gen 3" leg).
### 3. Configure Rules
Two categories of rules are configured:
**Per-game nuzlocke rules** — The standard nuzlocke ruleset (first encounter only, permadeath, duplicates clause, level caps, etc.). These are set once and apply uniformly to all legs. Uses the existing `NuzlockeRules` interface.
**Genlocke-specific rules** — Overarching rules that govern how legs connect:
- **Keep HoF** (default) — Pokemon that enter the Hall of Fame at the end of a leg are transferred to the next leg as eggs (breed at level 1). This is the standard genlocke mechanic.
- **Retire HoF** — Pokemon that enter the Hall of Fame are retired. They (and their evolutionary families) become unavailable in future legs (added to a cumulative dupe list). This is also known as the "Gauntlet" rule. Increases difficulty by forcing new Pokemon each leg.
- Potentially more rules in the future (e.g., item carry-over restrictions, level scaling).
### 4. Sequential Run Progression
- When the genlocke is created, the **first leg** is automatically started as a new nuzlocke run.
- Each leg is a full nuzlocke run, tracked exactly like any standalone run (encounters, team, bosses, graveyard, etc.).
- When a leg is marked as **completed** (Hall of Fame), the next leg is started. A transfer step happens between legs where the user selects which surviving Pokemon to carry forward.
- When a leg is marked as **failed** (wipe), the genlocke itself is marked as failed (game over).
- The final leg's completion marks the entire genlocke as completed.
### 5. Genlocke Overview Page
A dedicated page showing:
- **Progress** — Which leg is active, which are completed, which are upcoming. Visual timeline or step indicator.
- **Configuration** — Selected games, rules, genlocke-specific rules.
- **Cumulative Stats** — Total encounters, total deaths, total HoF entries across all legs.
- **Lineage Tracking** — Show Pokemon that have carried over across multiple legs (their journey through the genlocke).
- **Cumulative Graveyard** — All deaths across all legs in one view.
## Data Model
### New entities:
- **`Genlocke`** — Top-level entity: name, status (active/completed/failed), genlocke rules (JSONB), created_at.
- **`GenlockeLeg`** — Join table linking a Genlocke to a NuzlockeRun: genlocke_id, run_id, leg_order. Defines the sequence.
### Changes to existing entities:
- **`NuzlockeRun`** — No schema changes needed. A run that's part of a genlocke is just a normal run that happens to be referenced by a GenlockeLeg. The genlocke-level rules are stored on the Genlocke, not duplicated per run.
### Transfer tracking:
- **`GenlockeTransfer`** — Records which Pokemon were carried between legs: from_leg_id, to_leg_id, encounter_id (the source encounter from the completed leg), to_encounter_id (the egg/gift encounter created in the next leg).
## Child Features (suggested breakdown)
1. **Genlocke creation wizard** — Multi-step UI: name → game selection (with presets) → rules → confirm
2. **Genlocke overview page** — Dashboard with progress, stats, configuration
3. **Leg progression** — Auto-start next leg when current completes, transfer step
4. **Transfer UI** — Select surviving Pokemon to carry forward between legs
5. **Lineage tracking** — Show a Pokemon's journey across legs
6. **Cumulative graveyard** — Deaths across all legs in one view
7. **Gauntlet/Retire HoF rule** — Enforce the "retire" mechanic with cumulative dupe list
## Success Criteria
- [x] A user can create a new genlocke via a multi-step wizard (name, game selection with presets, rules)
- [x] Games can be selected using True Genlocke, Normal Genlocke, or Custom presets, grouped by region
- [x] Nuzlocke rules are configured once and applied uniformly to all legs
- [x] Genlocke-specific rules (Keep HoF / Retire HoF) can be selected
- [x] The first leg starts automatically upon genlocke creation
- [x] Each leg is a full nuzlocke run, tracked identically to standalone runs
- [x] Completing a leg triggers a transfer step where surviving Pokemon can be carried forward
- [x] Failing a leg marks the entire genlocke as failed
- [x] Completing the final leg marks the genlocke as completed
- [x] A genlocke overview page shows progress, configuration, cumulative stats, lineage, and graveyard
- [x] Transferred Pokemon appear as eggs (base form, level 1) in the next leg
- [x] Pokemon lineage is trackable across multiple legs
- [x] A cumulative graveyard shows all deaths across the entire genlocke
- [x] The Retire HoF / Gauntlet rule correctly retires HoF Pokemon and adds their families to the dupe list

View File

@@ -0,0 +1,19 @@
---
# nuzlocke-tracker-29oy
title: Boss seed data pipeline
status: completed
type: feature
priority: normal
created_at: 2026-02-08T11:33:33Z
updated_at: 2026-02-08T11:35:13Z
---
Export boss data from admin, save as seed JSON files, and load them during seeding.
## Checklist
- [x] Add unique constraint to boss_battles (version_group_id, order) + Alembic migration
- [x] Add upsert_bosses to seed loader (loader.py)
- [x] Add boss loading step to seed runner (run.py)
- [x] Add boss count to verify() function
- [x] Add export_bosses() function to run.py
- [x] Add --export-bosses flag to __main__.py

View File

@@ -0,0 +1,36 @@
---
# nuzlocke-tracker-2b4r
title: Add route ordering for Gen 5+ games
status: scrapped
type: task
priority: normal
created_at: 2026-02-10T08:58:55Z
updated_at: 2026-02-11T13:54:47Z
parent: nuzlocke-tracker-rzu4
---
Add route progression ordering in `route_order.json` for all games that currently lack it. Routes should be ordered to match the typical in-game progression (main story first, post-game after).
## Games needing route ordering:
- [ ] Diamond/Pearl (could alias to Platinum if progression is similar enough)
- [ ] Black/White
- [ ] Black 2/White 2
- [ ] X/Y
- [ ] Sun/Moon
- [ ] Ultra Sun/Ultra Moon (could alias to Sun/Moon if similar enough)
- [ ] Sword/Shield
- [ ] Brilliant Diamond/Shining Pearl (could alias to Platinum/Diamond-Pearl)
- [ ] Scarlet/Violet
- [ ] Legends Arceus
- [ ] Legends Z-A
- [ ] Let's Go Pikachu/Eevee (currently aliased to firered-leafgreen — verify this is correct)
## Approach:
- Reference Bulbapedia "walkthrough" or "appendix" pages for progression order
- Consider aliasing games that share the same region and route progression
- Mark a clear divider between main story and post-game routes where applicable
- The format is an array of route name strings in `route_order.json`, keyed by version group slug
## Notes:
- This is primarily manual work — play order guides are widely available online
- Verify route names match exactly what's in the encounter data files (case-sensitive)

View File

@@ -0,0 +1,23 @@
---
# nuzlocke-tracker-338l
title: Verify fetch_pokeapi.py rewrite
status: scrapped
type: task
priority: normal
created_at: 2026-02-07T15:08:10Z
updated_at: 2026-02-07T19:05:29Z
---
All code changes are complete. Run verification:
1. Run the script to completion
2. Verify output (pokemon.json has forms, correct IDs, etc.)
3. Verify cache speedup on second run
4. Frontend build check
## Checklist
- [ ] Run fetch_pokeapi.py to completion
- [ ] Verify pokemon.json has more entries with forms (megas, gmax, regionals)
- [ ] Verify pokeapi_id/national_dex split is correct
- [ ] Verify route/encounter JSON files
- [ ] Verify cache speedup on second run
- [ ] Frontend build passes

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-36wg
title: Make footer stick to bottom of viewport
status: completed
type: bug
priority: normal
created_at: 2026-02-13T07:47:48Z
updated_at: 2026-02-13T12:59:22Z
---
On pages with little content, the footer appears right after the content instead of staying at the bottom of the viewport. The footer should always be at the bottom of the browser window, pushing down when there's enough content but not floating in the middle of the page when content is short (sticky footer pattern).

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-37gk
title: Curate route ordering to match game progression
status: completed
type: feature
priority: normal
created_at: 2026-02-07T12:25:05Z
updated_at: 2026-02-07T12:27:11Z
---
Implement ROUTE_ORDER in fetch_pokeapi.py for progression-based sorting, and add Export Order button to AdminGameDetail. See bean j28y for full plan.

View File

@@ -0,0 +1,52 @@
---
# nuzlocke-tracker-3a5n
title: Add condition data to seed files via PokeDB merge
status: todo
type: task
priority: normal
created_at: 2026-02-14T21:48:03Z
updated_at: 2026-02-14T21:48:03Z
parent: oqfo
---
## Problem
The PokeDB data already contains per-condition encounter rates (`rate_morning`, `rate_day`, `rate_night`, `rate_spring`, `rate_summer`, etc.), but the current importer in `tools/import-pokedb` flattens them to `max()` in `extract_encounter_rate()`. We need to preserve these as `conditions` dicts in the seed JSON files.
Re-running the full import would overwrite route names (normalized in bean r48e) and route ordering (refined in bean qvww), so we need a targeted merge approach.
## Approach
Update the import tool to emit condition data, then merge it into existing seed files without touching route names or order.
## Checklist
- [ ] Update `Encounter` model in `tools/import-pokedb/import_pokedb/models.py` to carry an optional `conditions: dict[str, int] | None` field
- [ ] Update `extract_encounter_rate` in `processing.py` to return conditions alongside the flat rate (Gen 2/4 time-of-day, Gen 5 seasons, Gen 8 weather)
- [ ] Update `aggregate_encounters` in `processing.py` to handle condition dicts (merge/sum per condition key)
- [ ] Update `output.py` to emit `conditions` dict in seed JSON when present, with `encounter_rate` set to `null`
- [ ] Write a merge script/mode that:
- Runs the PokeDB processing for a game to get condition-aware encounters
- Reads the **existing** seed JSON file (preserving route names, order, and structure)
- For each encounter in the existing file, looks up the condition data from PokeDB
- Adds the `conditions` dict where applicable, without changing anything else
- Writes back to the same file
- [ ] Run the merge for Gen 2/4 games: gold, silver, crystal, heartgold, soulsilver, diamond, pearl, platinum, brilliant-diamond, shining-pearl
- [ ] Run the merge for Gen 5 games: black, white, black-2, white-2
- [ ] Run the merge for Gen 8 Sw/Sh: sword, shield
- [ ] Verify seed loader handles all new condition data correctly (re-seed and spot check)
- [ ] Remove the proof-of-concept manual conditions from heartgold.json Route 29 (replaced by real data)
## Affected games by condition type
- **morning/day/night**: Gold, Silver, Crystal, HeartGold, SoulSilver, Diamond, Pearl, Platinum, Brilliant Diamond, Shining Pearl
- **spring/summer/autumn/winter**: Black, White, Black 2, White 2
- **weather (clear, rain, thunderstorm, etc.)**: Sword, Shield
- **No conditions (flat rates)**: Gen 1, Gen 3, Gen 6, Gen 7, Gen 9 — no changes needed
## Key files
- `tools/import-pokedb/import_pokedb/processing.py``extract_encounter_rate()` currently flattens with `max()`
- `tools/import-pokedb/import_pokedb/models.py``Encounter` dataclass
- `tools/import-pokedb/import_pokedb/output.py` — seed JSON writer
- `backend/src/app/seeds/loader.py` — already supports `conditions` dict expansion

View File

@@ -0,0 +1,16 @@
---
# nuzlocke-tracker-3c9l
title: Set up branching structure
status: completed
type: task
priority: normal
created_at: 2026-02-09T15:30:35Z
updated_at: 2026-02-10T10:49:55Z
parent: nuzlocke-tracker-ahza
---
Create the `develop` branch from `main` and establish the `main`/`develop`/`feature/*` branching workflow.
- Create `develop` branch from current `main`
- Push `develop` to remote
- Set `develop` as the default working branch

View File

@@ -0,0 +1,29 @@
---
# nuzlocke-tracker-3el1
title: Run progression dividers (main story / endgame)
status: completed
type: feature
priority: normal
created_at: 2026-02-08T13:40:14Z
updated_at: 2026-02-08T20:25:59Z
---
Add support for dividing a run's boss battle progression into sections like "Main Story" and "Endgame" (e.g., post-Elite Four content). This helps players visually distinguish where the main campaign ends and optional/endgame content begins.
## Context
Currently boss battles are displayed as a flat ordered list. In many Pokemon games there's a clear distinction between the main story (up through the Champion) and endgame content (rematches, Battle Frontier, Kanto in GSC/HGSS, etc.). A visual divider would make it easier to track progress through each phase.
## Scope
- **Admin side**: Allow marking boss battles or defining breakpoints that separate progression phases (e.g., "everything after this boss is endgame")
- **Run side**: Render a visual divider/section header between main story and endgame boss battles
- Should support at minimum two sections (main story, endgame), but consider whether the design should be flexible enough for arbitrary sections (e.g., "Kanto" in HGSS)
## Checklist
- [ ] Decide on data model approach (e.g., a `section` field on boss battles, or a separate progression divider entity tied to the version group)
- [ ] Add backend models and migrations
- [ ] Add API support for managing sections/dividers
- [ ] Update admin UI to allow assigning bosses to sections or inserting dividers
- [ ] Update run-side boss progression display to render section headers/dividers

View File

@@ -0,0 +1,18 @@
---
# nuzlocke-tracker-3lfw
title: Configure Nginx Proxy Manager for nuzlocke-tracker
status: completed
type: task
priority: normal
created_at: 2026-02-09T15:30:50Z
updated_at: 2026-02-10T08:44:18Z
parent: nuzlocke-tracker-ahza
blocking:
- nuzlocke-tracker-vpn5
---
Add a proxy host entry in Nginx Proxy Manager on Unraid to route LAN traffic to the app.
- Add a proxy host (e.g., `nuzlocke.local`) pointing to the frontend/API containers
- Configure appropriate ports and forwarding rules
- Test access from other devices on the LAN

View File

@@ -0,0 +1,17 @@
---
# nuzlocke-tracker-48ds
title: Database backup strategy
status: completed
type: task
priority: normal
created_at: 2026-02-09T15:30:55Z
updated_at: 2026-02-10T10:55:15Z
parent: nuzlocke-tracker-ahza
---
Set up a simple scheduled backup for the production PostgreSQL database.
- Create a backup script using `pg_dump` that runs inside or against the PostgreSQL container
- Set up a cron job on Unraid to run the backup on a schedule (e.g., daily)
- Store backups in a designated location on Unraid with rotation (keep last N backups)
- Document the restore procedure

View File

@@ -0,0 +1,30 @@
---
# nuzlocke-tracker-4c31
title: Backend Setup & Framework
status: completed
type: task
priority: normal
created_at: 2026-02-04T15:46:49Z
updated_at: 2026-02-04T16:10:13Z
parent: nuzlocke-tracker-f5ob
blocking:
- nuzlocke-tracker-l7e3
- nuzlocke-tracker-bkhs
---
Set up the backend API project with chosen framework and structure.
## Checklist
- [x] Choose backend framework (Node.js/Express, Fastify, NestJS, Go, Python/FastAPI, etc.) - **Python/FastAPI**
- [x] Initialize backend project
- [x] Set up TypeScript (if applicable) - N/A (Python with type hints via Pydantic)
- [x] Configure linting and formatting - **ruff**
- [x] Set up project structure (routes, controllers, services, models)
- [x] Add environment configuration (.env handling) - **pydantic-settings**
- [x] Set up development server with hot reload - **uvicorn --reload**
- [x] Add basic health check endpoint - `/health` and `/`
## Considerations
- Should match team's expertise
- Consider ease of deployment
- TypeScript preferred for type safety with frontend

View File

@@ -0,0 +1,44 @@
---
# nuzlocke-tracker-4ph2
title: Fix and complete route ordering for all games
status: completed
type: task
priority: normal
created_at: 2026-02-11T13:55:09Z
updated_at: 2026-02-11T14:21:24Z
parent: nuzlocke-tracker-rzu4
---
Audit existing route ordering and add missing ordering for all games in `route_order.json`. Use Bulbapedia walkthrough/appendix pages as the primary reference for game progression order.
## Approach:
- Reference Bulbapedia walkthrough pages (e.g. `Appendix:FireRed_and_LeafGreen_walkthrough`) to determine correct progression order
- Cross-reference route names from walkthroughs against actual route names in encounter data files
- Consider building a script to semi-automate this (scrape walkthrough pages → match against encounter data → generate ordering)
## Games to fix (existing but incorrect):
- [x] Platinum — fixed ordering to start with Twinleaf Town, matched names to encounter data
## Games to add ordering for:
- [x] Diamond/Pearl (separate ordering, slight differences from Platinum)
- [x] Black/White
- [x] Black 2/White 2
- [x] X/Y
- [x] Sun/Moon
- [x] Ultra Sun/Ultra Moon (separate ordering, has additional areas)
- [x] Sword/Shield
- [x] Brilliant Diamond/Shining Pearl (separate ordering with Grand Underground)
- [x] Scarlet/Violet
- [x] Legends Arceus
- [x] Legends Z-A
## Games to audit (existing, likely correct):
- [x] FireRed/LeafGreen (and aliases: Red/Blue, Yellow, Let's Go) — rewritten with correct encounter data names
- [x] HeartGold/SoulSilver (and aliases: Gold/Silver, Crystal) — rewritten with correct encounter data names
- [x] Emerald (and aliases: Ruby/Sapphire, ORAS) — rewritten with correct encounter data names
## Notes:
- Route names must match exactly what's in the encounter data files (case-sensitive)
- "Starter" should be the first entry for each game
- Post-game areas placed after main story areas
- Replaces beans nuzlocke-tracker-6lud and nuzlocke-tracker-2b4r

View File

@@ -0,0 +1,26 @@
---
# nuzlocke-tracker-55kp
title: Docker Development Environment Setup
status: completed
type: task
priority: normal
created_at: 2026-02-04T16:07:25Z
updated_at: 2026-02-04T16:13:04Z
parent: nuzlocke-tracker-f5ob
---
Set up Docker and docker-compose for local development environment.
## Checklist
- [x] Create Dockerfile for backend API
- [x] Create Dockerfile for frontend (if needed)
- [x] Create docker-compose.yml with services (api, db, frontend)
- [x] Add PostgreSQL service configuration
- [x] Configure volume mounts for hot reload
- [x] Add environment variable handling
- [x] Create .dockerignore files
- [x] Document usage in README
## Notes
- Should support hot reload for development
- Database data should persist between restarts

View File

@@ -0,0 +1,31 @@
---
# nuzlocke-tracker-5bez
title: Non-evolution form changes
status: completed
type: feature
priority: normal
created_at: 2026-02-07T13:40:00Z
updated_at: 2026-02-08T11:57:36Z
---
Some Pokemon can change form without evolving, using items or abilities. These form changes affect types, stats, and appearance but are not part of the evolution chain.
## Examples
- **Oricorio**: Changes form (Baile/Pom-Pom/Pa'u/Sensu) by using nectar items from different islands. Each form has a different type (Fire, Electric, Psychic, Ghost + Flying).
- **Darmanitan**: Has a Zen Mode ability that changes it to Darmanitan (Zen) in battle (Fire/Psychic). Galarian Darmanitan Zen Mode is Ice/Fire.
- **Rotom**: Changes form by interacting with appliances (Heat/Wash/Frost/Fan/Mow), each with different secondary types.
- **Shaymin**: Changes between Land and Sky forme using the Gracidea flower.
- **Tornadus/Thundurus/Landorus**: Incarnate vs Therian forms via the Reveal Glass.
- **Hoopa**: Confined vs Unbound via the Prison Bottle.
## Scope
This is lower priority than basic form support (bean f44d) and submodule update (bean 6aje). It matters for tracking because a player might catch an Oricorio in one form and change it to another — the tracker should reflect the current form's types.
## Design considerations
- Should the tracker allow manually changing a caught Pokemon's form?
- Or should it just track the form as encountered and leave it static?
- How to represent form-change items/methods in the data model?
- This may not need seed data support — could be a manual UI action on a caught Pokemon

View File

@@ -0,0 +1,28 @@
---
# nuzlocke-tracker-5o1v
title: Improve encounter method input in route encounter form
status: completed
type: feature
priority: normal
created_at: 2026-02-08T19:06:10Z
updated_at: 2026-02-08T19:17:14Z
parent: nuzlocke-tracker-iu5b
---
Replace the free-text encounter method input in the route encounter form (RouteEncounterFormModal) with a smarter selector that leverages the known encounter methods already defined in the codebase.
## Current behavior
- The encounter method field in RouteEncounterFormModal is a plain `<input type="text">` with a placeholder "e.g. Walking, Surfing, Fishing"
- Easy to introduce typos or inconsistent naming (e.g. "walking" vs "walk" vs "Grass")
- The app already has a well-defined set of encounter methods in `EncounterMethodBadge.tsx` with METHOD_CONFIG and METHOD_ORDER (starter, gift, fossil, trade, walk, headbutt, surf, rock-smash, old-rod, good-rod, super-rod)
- The backend stores this as a `String(30)` column, so it's not strictly enum-constrained
## Desired behavior
- Replace the free-text input with a dropdown/select that lists the known encounter methods from METHOD_ORDER, using the human-readable labels from getMethodLabel()
- Include an "Other" option that reveals a text input for custom methods not in the predefined list
- When editing an existing encounter, pre-select the correct method
- Consider showing the colored badge preview next to each option for visual consistency with how methods appear elsewhere in the app
## Files
- `frontend/src/components/admin/RouteEncounterFormModal.tsx` — replace the text input with new selector
- `frontend/src/components/EncounterMethodBadge.tsx` — export METHOD_CONFIG or add a helper to get the list of known methods

View File

@@ -0,0 +1,66 @@
---
# nuzlocke-tracker-5tac
title: Enable naming generator for Genlockes
status: completed
type: task
priority: normal
created_at: 2026-02-11T21:14:21Z
updated_at: 2026-02-14T08:52:16Z
---
## Overview
Genlockes are multiple nuzlocke runs played back-to-back. Currently, naming scheme selection is only available per-run, meaning genlocke runs don't get naming schemes at all (they're created automatically during genlocke creation and leg advancement). This task adds genlocke-level naming scheme selection and lineage-aware name suggestions.
## Key Behaviors
### 1. Genlocke-Level Naming Scheme
- When creating a genlocke, the user selects a naming scheme (same categories as standalone runs)
- This scheme is stored on the `Genlocke` model and automatically applied to every leg's `NuzlockeRun`
- Both the initial run (created in `create_genlocke`) and subsequent runs (created in `advance_leg`) inherit the genlocke's naming scheme
### 2. Name Suggestions (Current Leg Only)
- Duplicate name checking stays scoped to the current run (already the case)
- Transferred pokemon carry their nicknames forward, so they naturally occupy names in the current run's used-name set
### 3. Lineage-Aware Name Suggestions (Roman Numerals)
- When catching a pokemon in a genlocke leg (leg 2+), the system checks if any pokemon from the same **evolution family** was caught in a previous leg
- If so, the original nickname is suggested with a roman numeral suffix (e.g., "Heracles II", "Heracles III")
- The numeral represents the Nth distinct leg where this evolution family was originally caught (not transferred)
- Leg 1: Magikarp → "Heracles" (no numeral, first appearance)
- Leg 2: Magikarp or Gyarados caught → suggest "Heracles II"
- Leg 3: Magikarp caught again → suggest "Heracles III"
- Transferred pokemon don't count as new appearances (they're the same individual)
- The "base name" is taken from the first original encounter of that family across all legs
- The lineage suggestion appears as a **priority suggestion** alongside regular naming scheme suggestions
- The user can always choose a different name
### 4. How the API Changes
- `GET /runs/{run_id}/name-suggestions` gains an optional `pokemon_id` query param
- When `pokemon_id` is provided AND the run belongs to a genlocke:
- Determine the pokemon's evolution family
- Query previous legs' encounters (excluding transfer-target encounters) for matching family members
- If matches found: compute the roman numeral and prepend "{base_name} {numeral}" to the suggestions list
- Regular naming scheme suggestions are returned as before
## Checklist
### Backend
- [x] Add `naming_scheme` column to `genlockes` table (Alembic migration)
- [x] Update `Genlocke` model with `naming_scheme: Mapped[str | None]`
- [x] Update `GenlockeCreate` schema to accept optional `naming_scheme: str | None`
- [x] Update `GenlockeResponse` and `GenlockeDetailResponse` to include `naming_scheme`
- [x] Update `create_genlocke` endpoint: pass `naming_scheme` to the first leg's `NuzlockeRun`
- [x] Update `advance_leg` endpoint: pass the genlocke's `naming_scheme` to the new leg's `NuzlockeRun`
- [x] Add roman numeral helper function (e.g., in `services/naming.py`)
- [x] Update `get_name_suggestions` endpoint to accept optional `pokemon_id` param
- [x] Implement lineage lookup: when in genlocke context with `pokemon_id`, query prior legs for evolution family matches (excluding transfers) and compute suggestion with roman numeral
- [ ] Add tests for lineage-aware name suggestions
### Frontend
- [x] Update `CreateGenlockeInput` type to include `namingScheme?: string | null`
- [x] Add naming scheme selector to genlocke creation wizard (in the Rules step or as a new step)
- [x] Update `GenlockeResponse` / `GenlockeDetailResponse` types to include `namingScheme`
- [x] Update `EncounterModal` to pass selected `pokemonId` to name suggestions API when in genlocke context
- [x] Update `getNameSuggestions` API client to accept optional `pokemonId` param
- [x] Display lineage suggestion prominently in the suggestions UI (e.g., first pill with distinct styling)

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-5uoz
title: Fix webp sprites not loading in production nginx
status: completed
type: bug
priority: normal
created_at: 2026-02-11T12:21:29Z
updated_at: 2026-02-11T12:24:02Z
---
Sprites (.webp) don't load in prod while .png images work fine. The files are in the container but nginx/proxy isn't serving them correctly. Fix by adding explicit webp MIME type to nginx config.

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-5wsn
title: Add run management to admin panel
status: completed
type: feature
priority: normal
created_at: 2026-02-08T09:53:01Z
updated_at: 2026-02-08T09:53:25Z
---
Create AdminRuns page with table listing all runs (name, game, status, started date) with delete functionality. Wire it into routing and admin navigation.

View File

@@ -0,0 +1,37 @@
---
# nuzlocke-tracker-66hg
title: Auto-select boss team variant based on starter choice
status: completed
type: feature
priority: normal
created_at: 2026-02-08T20:21:40Z
updated_at: 2026-02-08T20:34:35Z
---
When a run's starter Pokemon is known, automatically match it against boss battle condition labels (e.g., "Chose Bulbasaur") and pre-select the matching variant instead of showing the pill selector.
## Context
Currently, bosses with variant teams (condition_label) display a pill selector on the run page (BossDefeatModal and RunEncounters BossTeamPreview) so the user can manually toggle between team variants. However, if the run's starter choice is known, the correct variant can be inferred automatically.
## Behavior
- If the run has a starter Pokemon recorded, check each variant's condition label for a match (e.g., starter name "Bulbasaur" matches condition label "Chose Bulbasaur")
- If exactly one condition label matches, auto-select that variant and hide the pill selector entirely
- If no match is found (or the run has no starter), fall back to showing the pill selector as today
- Matching should be case-insensitive and check if the starter name appears anywhere in the condition label (substring match)
## Affected Components
- `BossDefeatModal` — auto-select variant, hide pills when matched
- `BossTeamPreview` in `RunEncounters` — same logic
- May need to check how/where the run's starter Pokemon is stored and accessible
## Checklist
- [x] Determine how the starter Pokemon is stored/accessible from the run data
- [x] Add matching logic to find the right variant from condition labels
- [x] Update BossDefeatModal to auto-select and hide pills when starter matches
- [x] Update BossTeamPreview in RunEncounters with same logic
- [ ] Test with variant bosses where starter matches a condition
- [ ] Test fallback behavior when no starter is set or no match found

View File

@@ -0,0 +1,30 @@
---
# nuzlocke-tracker-6aje
title: Update PokeAPI data submodule to latest version
status: completed
type: task
priority: high
created_at: 2026-02-06T10:53:45Z
updated_at: 2026-02-07T14:35:41Z
---
The local PokeAPI data repository we use as a submodule is outdated. It's missing data for newer Pokemon forms and potentially newer games.
## Why this is important now
After adding form support to seeding (bean f44d), we discovered that the submodule is missing many form entries. Currently only 16 forms are included — all from Gen 7 (Alolan + Oricorio/Lycanroc). Missing forms include:
- **Galarian forms** (Gen 8): Galarian Meowth, Ponyta, Rapidash, Slowpoke, Farfetch'd, Weezing, Mr. Mime, Corsola, Zigzagoon, Linoone, Darumaka, Darmanitan, Stunfisk, Yamask
- **Hisuian forms** (Gen 8/Legends Arceus): Hisuian Growlithe, Voltorb, Typhlosion, Samurott, Decidueye, Zorua, Zoroark, Braviary, Goodra, Avalugg, Sneasel, Lilligant, Qwilfish, Sliggoo
- **Paldean forms** (Gen 9): Paldean Wooper, Tauros
- **Other missing forms**: Basculin (White-Striped), regional bird variants, etc.
These forms have different types and stats from their base species and appear in encounter data for their respective games. Without them in the submodule, the seeding script can't create Pokemon records for them.
## Action
- Check for updates to the PokeAPI data repository
- Update the submodule to the latest version
- Re-run fetch_pokeapi.py to regenerate seed data
- Add any new games to VERSION_GROUPS in fetch_pokeapi.py
- Verify that form count increases significantly after update

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-6kux
title: 'Admin Panel: Tabs for Routes/Bosses + Boss Export'
status: completed
type: feature
priority: normal
created_at: 2026-02-08T10:49:47Z
updated_at: 2026-02-08T10:51:25Z
---
Add tabbed UI to AdminGameDetail (Routes/Bosses tabs) and boss battle export endpoint

View File

@@ -0,0 +1,31 @@
---
# nuzlocke-tracker-6lud
title: Audit and fix route ordering for Gen 1-4 games
status: scrapped
type: task
priority: normal
created_at: 2026-02-10T08:59:16Z
updated_at: 2026-02-11T13:54:47Z
parent: nuzlocke-tracker-rzu4
---
Review the existing route ordering for Gen 1-4 games that already have ordering defined. The current ordering may not accurately reflect typical game progression.
## Games to audit:
- [ ] FireRed/LeafGreen (and aliased: Red/Blue, Yellow, Let's Go)
- [ ] HeartGold/SoulSilver (and aliased: Gold/Silver, Crystal)
- [ ] Emerald (and aliased: Ruby/Sapphire, Omega Ruby/Alpha Sapphire)
- [ ] Platinum
## What to check:
- Routes are in correct progression order (match typical walkthrough)
- No routes are missing from the ordering
- No routes are listed that don't exist in the encounter data
- Aliases make sense (e.g. Red/Blue may have slightly different progression from FR/LG)
- Post-game areas are placed after main story areas
- Sub-areas (children) inherit parent ordering correctly
## Notes:
- Cross-reference with Bulbapedia walkthrough pages
- The Platinum ordering currently starts with cities and mines rather than the starting town/routes — this may be incorrect
- Diamond/Pearl currently aliases to nothing — check if it should alias to Platinum or needs its own ordering

View File

@@ -0,0 +1,12 @@
---
# nuzlocke-tracker-6r4z
title: 'Admin table improvements: Routes and Bosses'
status: completed
type: task
priority: normal
created_at: 2026-02-13T13:01:55Z
updated_at: 2026-02-13T13:06:08Z
---
1. Routes table: add column for 'pinwheel close' and a column for quicklink to encounters
2. Bosses table: add column for Position after route column, ideally as an inline dropdown for mass editing

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-704x
title: Run progression dividers (main story / endgame)
status: completed
type: feature
priority: normal
created_at: 2026-02-08T13:46:12Z
updated_at: 2026-02-08T13:48:28Z
---
Add section field to boss battles to enable visual dividers between game progression phases (Main Story, Endgame, etc.) in both admin and run views.

View File

@@ -0,0 +1,20 @@
---
# nuzlocke-tracker-765i
title: Update CLAUDE.md with branching rules
status: completed
type: task
priority: normal
created_at: 2026-02-09T15:30:38Z
updated_at: 2026-02-10T10:49:56Z
parent: nuzlocke-tracker-ahza
blocking:
- nuzlocke-tracker-3c9l
---
Once the branching structure is in place, add instructions to CLAUDE.md enforcing the branching strategy:
- Never commit directly to `main`
- Day-to-day work happens on `develop`
- New work is done on `feature/*` branches off `develop`
- Merge flow: `feature/*``develop``main`
- `main` is always production-ready

View File

@@ -0,0 +1,27 @@
---
# nuzlocke-tracker-7jba
title: Review and complete special encounters for all games
status: completed
type: task
priority: normal
created_at: 2026-02-10T08:59:24Z
updated_at: 2026-02-11T13:52:06Z
parent: nuzlocke-tracker-rzu4
---
Only starters were missing from the encounter data. Gifts, trades, and fossils are already present in the per-game encounter JSON files.
The `special_encounters.json` file previously contained starters, gifts, and fossils for Gen 1-3 — but only the starters were actually needed (the rest was redundant). Additionally, starters were missing for Gen 4+ games. Yellow and Let's Go were incorrectly aliased to firered-leafgreen (wrong starters).
## Checklist:
- [x] Remove non-starter entries from special_encounters.json
- [x] Add Yellow starter (Pikachu) — was incorrectly aliased to firered-leafgreen
- [x] Add Let's Go starters (Pikachu, Eevee) — was incorrectly aliased to firered-leafgreen
- [x] Add Gen 4 starters (Diamond/Pearl/Platinum/BD/SP)
- [x] Add Gen 5 starters (Black/White/B2/W2)
- [x] Add Gen 6 starters (X/Y)
- [x] Add Gen 7 starters (Sun/Moon/USUM)
- [x] Add Gen 8 starters (Sword/Shield)
- [x] Add Gen 9 starters (Scarlet/Violet)
- [x] Add Legends Arceus starters
- [x] Add Legends Z-A starters

View File

@@ -0,0 +1,37 @@
---
# nuzlocke-tracker-8fcj
title: Frontend API Integration
status: completed
type: task
priority: normal
created_at: 2026-02-04T15:44:42Z
updated_at: 2026-02-05T13:55:52Z
parent: nuzlocke-tracker-f5ob
blocking:
- nuzlocke-tracker-uw2j
- nuzlocke-tracker-0q8f
- nuzlocke-tracker-hm6t
- nuzlocke-tracker-8tuw
---
Implement frontend services to communicate with the backend API.
## Checklist
- [x] Create API client/service layer
- [x] Implement API calls for:
- [x] Fetch available games
- [x] Fetch routes for a game
- [x] Fetch Pokémon data
- [x] Create/update/delete Nuzlocke runs
- [x] Create/update encounters
- [x] Update Pokémon status
- [x] Add loading states and error handling
- [x] Add retry logic for failed requests
## Technical Notes
- Using native `fetch` via `src/api/client.ts` wrapper
- Using TanStack Query for caching, loading states, and retry
- All API responses typed with TypeScript
- Vite dev proxy configured for `/api` → backend
- Query hooks in `src/hooks/` for each domain (games, pokemon, runs, encounters)
- Mutations auto-invalidate relevant query caches

View File

@@ -0,0 +1,28 @@
---
# nuzlocke-tracker-8tuw
title: Run Dashboard/Overview
status: completed
type: task
priority: normal
created_at: 2026-02-04T15:44:38Z
updated_at: 2026-02-05T14:16:36Z
parent: nuzlocke-tracker-f5ob
---
Create the main dashboard showing the current state of the Nuzlocke run.
## Checklist
- [x] Show run statistics:
- [x] Total encounters (caught/failed/skipped)
- [x] Total deaths
- [x] Routes completed
- [x] Quick navigation to:
- [x] Route list / encounter tracking
- [x] Graveyard (fallen Pokémon)
- [x] Show active rules as badges/icons
- [x] Display game name and run start date
## UX Considerations
- This is the home screen users return to most
- Keep it clean and informative at a glance
- Easy access to add new encounters

View File

@@ -0,0 +1,40 @@
---
# nuzlocke-tracker-8w9s
title: Gauntlet rule option for genlockes
status: completed
type: feature
priority: normal
created_at: 2026-02-08T19:15:43Z
updated_at: 2026-02-09T09:05:12Z
parent: nuzlocke-tracker-25mh
---
Add the **Retire HoF** (aka Gauntlet) rule as a genlocke-specific rule option. When enabled, Pokemon that enter the Hall of Fame at the end of a leg are NOT transferred to the next game — instead, they and their entire evolutionary families are added to a cumulative dupe list for all subsequent legs.
## Behavior
- Toggled as a genlocke-specific rule during genlocke creation (step 3 of the wizard)
- Mutually exclusive with "Keep HoF" — you pick one or the other
- When a leg is completed:
- Surviving HoF Pokemon are marked as "retired" rather than being available for transfer
- Their evolutionary families (full chain: e.g., Charmander/Charmeleon/Charizard) are added to a cumulative dupe list
- In subsequent legs, the duplicates clause treats these families as already caught/dead
- The cumulative dupe list grows with each completed leg, making later legs increasingly restrictive
- The genlocke overview page should display the cumulative retired/duped families
## Dependencies
- Requires the genlocke creation wizard (to set the rule)
- Requires the leg progression system (to trigger retirement on leg completion)
- Should integrate with the existing duplicates clause enforcement in the encounter system
## Notes
- This is a popular variant that increases difficulty by forcing entirely new Pokemon each generation
- The dupe list should be visible somewhere in the genlocke dashboard so the player knows which families are off-limits
## Checklist
- [x] Add a `retireHoF` boolean (or equivalent) to the genlocke rules JSONB schema
- [x] On leg completion with Retire HoF enabled: resolve the full evolutionary families of all surviving HoF Pokemon
- [x] Store the cumulative retired families list (could be a JSONB field on the Genlocke, or derived from completed legs)
- [x] Implement `GET /api/v1/genlockes/{id}/retired-families` — return the list of retired evolutionary families with which leg they were retired in
- [x] Integrate with the encounter system's duplicates clause: when logging an encounter in a genlocke leg, check the cumulative retired list and flag duplicates
- [ ] Build a "Retired Families" display on the genlocke overview page showing all off-limits Pokemon with their sprites
- [x] Ensure the creation wizard's genlocke rules step correctly toggles between Keep HoF and Retire HoF

View File

@@ -0,0 +1,29 @@
---
# nuzlocke-tracker-94hx
title: Add sort options to run team overview
status: completed
type: feature
priority: normal
created_at: 2026-02-09T10:03:49Z
updated_at: 2026-02-09T11:09:33Z
---
The Active Team / Final Team section on the run dashboard (`RunDashboard.tsx`) currently displays Pokemon in whatever order encounters arrive from the backend — there is no explicit sorting. Add a sort dropdown so the user can choose how their team is ordered.
## Sort options
- **Route order** (default) — sort by the route's `order` field, matching game progression
- **Catch level** — sort by `catchLevel`, ascending
- **Species name** — sort alphabetically by the display Pokemon's name (accounting for evolutions via `currentPokemon`)
- **National Dex** — sort by the display Pokemon's `nationalDex` number
## Scope
- Frontend-only change — all data is already available in the `EncounterDetail` objects
- Add a small sort control (dropdown or segmented buttons) above the team grid
- Persist the selected sort in component state (no need for localStorage)
- Apply the same sort options to both the Active Team and Graveyard sections
## Checklist
- [x] Add sort state and sort logic to `RunDashboard.tsx`
- [x] Add sort dropdown/control above the team grid
- [x] Apply sorting to both `alive` and `dead` encounter arrays
- [x] Verify sort works correctly with evolved Pokemon (use `currentPokemon ?? pokemon` for name/dex)

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-94v0
title: Handle Pokemon Forms properly
status: scrapped
type: task
priority: normal
created_at: 2026-02-05T17:47:30Z
updated_at: 2026-02-07T13:21:32Z
---
Some pokemon have different forms, either regional forms or based on other criteria. They behave differently, are different encounters and might have different evolutions. This needs to be handled.

View File

@@ -0,0 +1,30 @@
---
# nuzlocke-tracker-9c66
title: Integration tests for Genlockes & Bosses API
status: draft
type: task
created_at: 2026-02-10T09:33:26Z
updated_at: 2026-02-10T09:33:26Z
parent: nuzlocke-tracker-yzpb
---
Write integration tests for the genlocke challenge and boss battle API endpoints.
## Checklist
- [ ] Test genlocke CRUD operations (create, list, get, update, delete)
- [ ] Test leg management (add/remove legs to a genlocke)
- [ ] Test Pokemon transfers between genlocke legs
- [ ] Test boss battle CRUD (create, list, update, delete per game)
- [ ] Test boss battle results per run (record win/loss)
- [ ] Test stats endpoint for run statistics
- [ ] Test export endpoint
- [ ] Test error cases (invalid transfers, boss results for wrong game, etc.)
## Notes
- Genlocke endpoints: `backend/src/app/api/genlockes.py`
- Boss endpoints: `backend/src/app/api/bosses.py`
- Stats endpoints: `backend/src/app/api/stats.py`
- Export endpoints: `backend/src/app/api/export.py`
- Genlocke tests require multiple runs as fixtures

View File

@@ -0,0 +1,25 @@
---
# nuzlocke-tracker-9c8d
title: Rebrand to Another Nuzlocke Tracker (ANT)
status: todo
type: task
priority: normal
created_at: 2026-02-10T14:46:09Z
updated_at: 2026-02-10T14:46:56Z
---
Adopt the new branding: **Another Nuzlocke Tracker**, abbreviated **ANT**.
## Context
- No existing Nuzlocke tracker uses this name or acronym.
- The name is self-deprecating/playful ("yet another...") and the acronym opens up mascot/logo possibilities (ant character).
- **Durant** (Steel/Bug, Gen V) is the mascot Pokémon — an actual ant Pokémon that ties the ANT acronym directly into the Pokémon universe.
## Checklist
- [ ] Update project name in package.json / config files
- [ ] Update page titles, meta tags, and any visible app name references
- [ ] Update README and any documentation with the new name
- [ ] Design or source a Durant-themed logo/icon
- [ ] Update favicon and app icons

View File

@@ -0,0 +1,25 @@
---
# nuzlocke-tracker-9cx2
title: Drag-and-drop reordering for boss battles
status: completed
type: feature
priority: normal
created_at: 2026-02-08T12:33:18Z
updated_at: 2026-02-08T13:11:50Z
parent: nuzlocke-tracker-iu5b
---
Add drag-and-drop reordering for boss battles, matching the existing pattern used for routes.
## Current behavior
- Boss battles have a manual 'order' field that must be edited individually
- Routes already have drag-and-drop reordering via @dnd-kit
## Desired behavior
- Boss battles in the AdminGameDetail bosses tab support drag-and-drop reordering
- Same visual pattern as routes: drag handle on the left, auto-recalculate order on drop
- Reuse the same @dnd-kit setup already in place for routes
## Files
- frontend/src/pages/admin/AdminGameDetail.tsx — add DnD to bosses tab
- Backend may need a reorder endpoint for bosses (similar to routes reorder)

View File

@@ -0,0 +1,67 @@
---
# nuzlocke-tracker-9ngw
title: Stats Screen
status: completed
type: feature
priority: normal
created_at: 2026-02-07T19:19:40Z
updated_at: 2026-02-07T19:45:55Z
---
A dedicated stats page aggregating data across all runs. Accessible from the main navigation.
## Sections
### 1. Run Overview
- Total runs, active runs, completed runs, failed runs
- Win rate (completed / (completed + failed), excluding active)
- Average run duration (started_at → completed_at for finished runs)
- Pie or bar chart: runs by game (using game.name / game.color)
- Pie or bar chart: runs by region (game.region)
- Pie or bar chart: runs by generation (game.generation)
### 2. Encounter Stats
- Total encounters across all runs
- Breakdown by status: caught / fainted / missed (counts + percentages)
- Catch rate: caught / total encounters
- Average encounters per run
### 3. Pokemon Rankings
- Top N most-caught Pokemon (by pokemon_id frequency across encounters with status=caught), showing sprite + name + count
- Top N most-encountered Pokemon (any status), same display
- Configurable N (default 5, expandable to 10/all)
### 4. Team & Deaths
- Total Pokemon caught, total deaths (caught with faint_level != null)
- Mortality rate: deaths / caught
- Most common death causes (death_cause field, grouped + counted, top 5)
- Average catch level, average faint level
- Type distribution of caught Pokemon (bar chart of pokemon.types, counted across all caught encounters)
## Data Access
### Option A — Frontend-only (compute from existing data)
The list-runs endpoint already returns all runs with encounters. Stats can be computed client-side by fetching all runs. This is simpler but won't scale well with many runs.
### Option B — Dedicated backend endpoint (recommended for scale)
Add `GET /api/stats` that runs aggregate queries server-side and returns pre-computed stats. This is more work but performs better and keeps the frontend thin.
**Recommendation:** Start with Option A for simplicity. If performance becomes an issue, migrate to Option B.
## UI Notes
- New route: `/stats`
- Add "Stats" link to the main nav/sidebar
- Use the existing `StatCard` component for top-level numbers
- Charts: consider a lightweight library (e.g., recharts) or simple CSS bar charts to avoid heavy dependencies
- Responsive grid layout matching the existing design system (dark mode support)
## Checklist
- [x] Add `/stats` route and page component
- [x] Add "Stats" navigation link
- [x] Fetch all runs with encounters (or add backend stats endpoint)
- [x] Run Overview section (counts, win rate, duration)
- [x] Encounter Stats section (caught/fainted/missed breakdown)
- [x] Pokemon Rankings section (top caught, top encountered, expandable)
- [x] Team & Deaths section (mortality, death causes, type distribution)
- [x] Charts for region/generation/type breakdowns
- [x] Responsive layout + dark mode styling

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-9z2k
title: Implement non-evolution form changes
status: completed
type: feature
priority: normal
created_at: 2026-02-08T11:51:18Z
updated_at: 2026-02-08T11:52:36Z
---
Add ability to change Pokemon forms (e.g. Rotom appliances, Oricorio nectar forms) without evolving. Mirror existing evolution UI pattern with a new 'Change Form' button in StatusChangeModal.

View File

@@ -0,0 +1,19 @@
---
# nuzlocke-tracker-a7q2
title: Handle pokemon evolutions
status: completed
type: feature
priority: normal
created_at: 2026-02-05T14:27:07Z
updated_at: 2026-02-05T18:26:11Z
parent: nuzlocke-tracker-f5ob
---
Add support for pokemon evolutions in the tracker. When a pokemon evolves during a Nuzlocke run, the tracker should reflect the new species while preserving the encounter history (original catch route, catch level, nickname, etc.).
## Implementation
- **Data model**: `Evolution` table with from/to pokemon, trigger, level, item, and condition fields. `Encounter.current_pokemon_id` tracks evolved species separately from original.
- **Seed data**: Evolution chains fetched from PokeAPI submodule data, with an overrides file for manual corrections.
- **API**: `GET /pokemon/{id}/evolutions` returns available evolutions. `PATCH /encounters/{id}` accepts `current_pokemon_id` to record an evolution.
- **Frontend**: "Evolve" button in StatusChangeModal shows available evolutions with trigger details. PokemonCard displays the current (evolved) species with "Originally: {name}" label.

View File

@@ -0,0 +1,58 @@
---
# nuzlocke-tracker-ahza
title: Deployment Strategy
status: completed
type: epic
priority: normal
created_at: 2026-02-09T14:03:53Z
updated_at: 2026-02-10T11:36:07Z
---
Define and implement a deployment strategy for running the nuzlocke-tracker in production on a local Unraid server while keeping laptop/PC as the development environment.
## Context
- **Components:** API (Python/FastAPI), Frontend (Vite/React), PostgreSQL database
- **Dev environment:** Laptop/PC — continue using the existing `docker-compose.yml` for local development
- **Production host:** Unraid server running Docker containers
- **Networking:** LAN-only access, Nginx Proxy Manager already in place on Unraid
- **Orchestration:** Docker Compose for production (matching dev workflow). Deploy via SSH from the dev machine.
## Decided Approach
**Docker Compose + SSH + Gitea (source hosting, container registry)**
1. **Gitea** runs on Unraid behind Nginx Proxy Manager with SSL (e.g., `gitea.nerdboden.de`). It serves as the self-hosted Git remote and container registry.
2. **Images are built on the dev machine** (podman or docker, cross-compiled for linux/amd64) and pushed to Gitea's container registry as **user-level packages** (e.g., `gitea.nerdboden.de/thefurya/nuzlocke-tracker-api:latest`, `gitea.nerdboden.de/thefurya/nuzlocke-tracker-frontend:latest`).
3. **Production runs docker compose** on Unraid at `/mnt/user/appdata/nuzlocke-tracker/`, pulling images from the Gitea container registry instead of mounting source.
4. **A deploy script** on the dev machine automates the full flow: build images → push to Gitea registry → SCP compose file to Unraid → generate `.env` if missing → SSH to pull images and (re)start containers.
5. **Nginx Proxy Manager** handles routing on the LAN (e.g., `nuzlocke.nerdboden.de` → frontend container, `gitea.nerdboden.de` → Gitea).
6. **Database** uses a bind mount (`./data/postgres`) for persistence on the Unraid disk; migrations run automatically on API container startup.
## Branching Strategy
**`main` + `develop` + feature branches**
- **`main`** — always production-ready. Only receives merges from `develop` when ready to deploy. The deploy script builds from `main`.
- **`develop`** — integration branch for day-to-day work. Features are merged here and tested before promoting to `main`.
- **`feature/*`** — short-lived branches off `develop` for individual features/fixes. Merged back into `develop` via PR or direct merge when complete.
**Workflow:**
1. Create `feature/xyz` from `develop`
2. Work on the feature, commit, merge into `develop`
3. When ready to deploy: merge `develop``main`
4. Run `./deploy.sh` (builds from `main`, pushes to Gitea registry, deploys to Unraid via SSH)
## Checklist
- [x] **Set up branching structure** — create `develop` branch from `main`, establish the `main`/`develop`/`feature/*` workflow
- [x] **Update CLAUDE.md with branching rules** — once the branching structure is in place, add instructions to CLAUDE.md that the branching strategy must be adhered to (always work on feature branches, never commit directly to `main`, merge flow is `feature/*``develop``main`)
- [x] **Configure Gitea container registry** — create an access token with `read:package` and `write:package` scopes, verify `docker login gitea.nerdboden.de` works, test pushing and pulling an image as a user-level package
- [x] **Create production docker-compose file** (`docker-compose.prod.yml`) — uses images from the Gitea container registry, production env vars, no source volume mounts, proper restart policies
- [x] **Create production Dockerfiles (or multi-stage builds)** — ensure frontend is built and served statically (e.g., via the API or a lightweight nginx container), API runs without debug mode
- [x] **Create deploy script**`./deploy.sh` builds images (podman/docker, linux/amd64), pushes to Gitea registry, SCPs compose file, generates `.env` if needed, pulls and starts containers via SSH
- [x] **Configure Nginx Proxy Manager** — add proxy host entries for Gitea and the nuzlocke-tracker frontend/API on the appropriate ports
- [x] **Environment & secrets management** — deploy script auto-generates `.env` with `POSTGRES_PASSWORD` on Unraid if missing; file lives at `/mnt/user/appdata/nuzlocke-tracker/.env`
- [x] **Implement Gitea Actions CI/CD pipeline** — set up Gitea Actions runner on Unraid, create CI workflow (lint/test on `develop`) and deploy workflow (build/push/deploy on `main`); uses GitHub Actions-compatible syntax for portability
- [x] **Database backup strategy** — set up a simple scheduled backup for the PostgreSQL data (e.g., cron + `pg_dump` script on Unraid)
- [x] **Document the deployment workflow** — README or docs covering how to deploy, redeploy, rollback, and manage the production instance

View File

@@ -0,0 +1,24 @@
---
# nuzlocke-tracker-aiw6
title: Create deploy script
status: completed
type: task
priority: normal
created_at: 2026-02-09T15:30:48Z
updated_at: 2026-02-09T17:28:22Z
parent: nuzlocke-tracker-ahza
blocking:
- nuzlocke-tracker-izf6
- nuzlocke-tracker-vpn5
- nuzlocke-tracker-xmyh
- nuzlocke-tracker-jzqz
---
Create a `./deploy.sh` script for the dev machine that automates the full deployment flow.
- Ensure the script runs from `main` branch (or warns if not)
- Build Docker images for API and frontend
- Tag images for the local registry (e.g., `unraid:5000/nuzlocke-api:latest`)
- Push images to the local registry
- Trigger the Portainer webhook to redeploy the stack
- Print status/confirmation of each step

View File

@@ -0,0 +1,24 @@
---
# nuzlocke-tracker-b9oj
title: Implement Dupes Clause & Shiny Clause Enforcement
status: completed
type: feature
priority: normal
created_at: 2026-02-07T20:03:12Z
updated_at: 2026-02-07T20:07:50Z
---
Add enforcement for duplicatesClause and shinyClause rules:
- Dupes Clause: Grey out Pokemon in encounter modal whose evolution family is already caught
- Shiny Clause: Dedicated Shiny Box for bonus shiny catches that bypass route locks
## Checklist
- [x] Migration: Add is_shiny column to encounters table
- [x] Backend model + schema: Add is_shiny field
- [x] Backend: Shiny route-lock bypass in create_encounter
- [x] Backend: Evolution families endpoint (GET /pokemon/families)
- [x] Frontend types + API: Add isShiny fields and fetchPokemonFamilies
- [x] Frontend: Dupes Clause greying in EncounterModal
- [x] Frontend: ShinyEncounterModal + ShinyBox components
- [x] Frontend: RunEncounters orchestration (split encounters, duped IDs, shiny box)
- [x] TypeScript type check passes

View File

@@ -0,0 +1,35 @@
---
# nuzlocke-tracker-bi4e
title: Integrate name suggestions into encounter registration UI
status: completed
type: task
priority: normal
created_at: 2026-02-11T15:56:44Z
updated_at: 2026-02-11T20:48:02Z
parent: nuzlocke-tracker-igl3
---
Show name suggestions in the encounter registration flow so users can pick a nickname with a single click.
## Requirements
- When a user registers a new Pokemon encounter, display 5-10 name suggestions below/near the nickname input
- Each suggestion is a clickable chip/button that fills in the nickname field
- Include a "regenerate" button to get a fresh batch of suggestions
- Only show suggestions if the run has a naming scheme selected
- The nickname input should still be editable for manual entry
## Implementation Notes
- **Data fetching**: Call `GET /api/v1/runs/{run_id}/name-suggestions?count=10` to get suggestions from the backend.
- **Regeneration**: Each call to the endpoint returns a fresh random batch (backend handles exclusion of used names).
- **No dictionary data in frontend**: All suggestion logic lives in the backend.
## Checklist
- [x] Add a name suggestions component (chips/buttons with regenerate)
- [x] Integrate the component into the encounter registration modal/form
- [x] Wire up the backend API endpoint to the component via React Query
- [x] Ensure clicking a suggestion populates the nickname field
- [x] Ensure regenerate fetches a new batch from the API
- [x] Hide suggestions gracefully if no naming scheme is set on the run

View File

@@ -0,0 +1,40 @@
---
# nuzlocke-tracker-bkhs
title: API Endpoints Implementation
status: completed
type: task
priority: normal
created_at: 2026-02-04T15:46:59Z
updated_at: 2026-02-05T13:47:57Z
parent: nuzlocke-tracker-f5ob
blocking:
- nuzlocke-tracker-8fcj
- nuzlocke-tracker-hy41
---
Implement the REST/GraphQL API endpoints for the tracker.
## Checklist
- [x] Reference Data endpoints (read-only for tracker):
- [x] GET /api/v1/games - List all games
- [x] GET /api/v1/games/:id - Get game details with routes
- [x] GET /api/v1/games/:id/routes - List routes for a game
- [x] GET /api/v1/routes/:id/pokemon - List available Pokémon for a route
- [x] GET /api/v1/pokemon/:id - Get Pokémon details
- [x] Run Management endpoints:
- [x] POST /api/v1/runs - Create new run
- [x] GET /api/v1/runs - List all runs
- [x] GET /api/v1/runs/:id - Get run details with encounters
- [x] PATCH /api/v1/runs/:id - Update run (settings, status)
- [x] DELETE /api/v1/runs/:id - Delete a run
- [x] Encounter endpoints:
- [x] POST /api/v1/runs/:id/encounters - Log new encounter
- [x] PATCH /api/v1/encounters/:id - Update encounter (status, nickname)
- [x] DELETE /api/v1/encounters/:id - Remove encounter
- [x] Add request validation
- [x] Add proper error responses
## Notes
- Follow REST conventions
- Return appropriate HTTP status codes
- Include pagination for list endpoints if needed

View File

@@ -0,0 +1,108 @@
---
# nuzlocke-tracker-bs05
title: Build PokeDB.org data import tool
status: completed
type: feature
priority: normal
created_at: 2026-02-10T14:04:11Z
updated_at: 2026-02-11T10:54:04Z
parent: nuzlocke-tracker-rzu4
blocking:
- nuzlocke-tracker-spx3
---
Build a standalone Python tool that converts PokeDB.org's JSON data export into our existing seed JSON format. This replaces PokeAPI as the single source of truth for ALL games (Gen 1-9).
Python was chosen over Go because:
- The backend is already Python, so the team is familiar with it
- We're processing local JSON files — no need for Go's concurrency
- Remains a standalone tool in `tools/import-pokedb/`, not part of the backend
## Data source
PokeDB.org provides a full data export at https://pokedb.org/data-export with JSON downloads:
- `encounters.json` (69MB, 37,724 records) — all encounter data across all games
- `locations.json` — 839 locations
- `location_areas.json` — 2,672 location areas
- `encounter_methods.json` — 73 encounter methods
- `versions.json` — 82 game versions
- `pokemon_forms.json` — Pokemon forms with identifiers
**No scraping required.** Just download the JSON files and process them locally.
**Terms of use:** "Data is provided for educational, research, and non-commercial purposes." Attribution to PokeDB requested.
## Encounter data coverage
Encounter counts by version:
- Sword: 10,160 / Shield: 10,144
- Scarlet: 4,135 / Violet: 4,101
- SoulSilver: 2,492 / HeartGold: 2,475
- Shining Pearl: 2,021 / Brilliant Diamond: 2,013
- Legends Arceus: 1,756
- Black 2: 1,418 / White 2: 1,418
- Crystal: 1,375 / Alpha Sapphire: 1,338 / Platinum: 1,337
- Diamond: 1,292 / Pearl: 1,289 / Silver: 1,284 / Gold: 1,282
- LeafGreen: 987 / FireRed: 985 / White: 981 / Black: 947
- Ultra Moon: 886 / Ultra Sun: 885 / X: 880 / Y: 879
- Emerald: 763 / Let's Go Eevee: 710 / Sun: 709 / Moon: 707
- Sapphire: 707 / Ruby: 707 / Let's Go Pikachu: 690
- Blue: 528 / Red: 526 / Yellow: 496
## Data format details
Each encounter record has:
- `pokemon_form_identifier` — e.g. "pidgey-default", "mr-mime-default"
- `version_identifiers` — array of game version IDs (e.g. ["sword", "shield"])
- `location_area_identifier` — e.g. "route-01-kanto", "axews-eye"
- `encounter_method_identifier` — e.g. "walking-tall-grass", "surfing", "npc-trade"
- `levels` — string like "2 - 4" or "67"
- Rate fields vary by game generation:
- Gen 1/3/6: `rate_overall` (single percentage)
- Gen 2/4: `rate_morning`, `rate_day`, `rate_night` (time-of-day percentages)
- Gen 5: `rate_spring`, `rate_summer`, `rate_autumn`, `rate_winter` (seasonal)
- Gen 8 Sw/Sh: `weather_*_rate` fields (per-weather percentages, e.g. "40%")
- Gen 8 Legends Arceus: `during_*` and `while_*` booleans (time+weather conditions)
- Gen 9 Sc/Vi: `probability_*` fields (overworld probability weights)
- `trade_for` — Pokemon form identifier for NPC trades
- `alpha_levels` — for Legends Arceus alpha encounters
- `visible` — overworld vs hidden encounter
- Max Raid and Tera Raid fields for special encounters
## Subtasks
Work is broken into child task beans:
- [ ] **Set up Python tool scaffold** — project structure, CLI entry point, PokeDB JSON file loading
- [ ] **Build reference data mappings** — pokemon_form → pokeapi_id, location_area → name/region, encounter method mapping
- [ ] **Core encounter processing** — filter by game version, parse levels, handle rate variants, group by location area
- [ ] **Output seed JSON** — produce per-game JSON in existing format, integrate route ordering + special encounters
- [ ] **Validation & full generation** — compare against existing data, run for all games, fix discrepancies
## Encounter method mapping (draft)
PokeDB method → Our seed method:
- `walking-tall-grass`, `walking-*` → "walk"
- `surfing`, `surfing-*` → "surf"
- `fishing-old-rod` → "old-rod"
- `fishing-good-rod` → "good-rod"
- `fishing-super-rod` → "super-rod"
- `fishing` → "fishing"
- `rock-smash` → "rock-smash"
- `headbutt-*` → "headbutt"
- `npc-gift`, `egg`, `revive` → "gift"
- `npc-trade` → "trade"
- `symbol-encounter` → "walk" (overworld, Gen 8+)
- `wanderer` → "walk" (overworld visible)
- `fixed-encounter`, `static-encounter` → "static"
- `swarm` → "swarm"
- `poke-radar` → "pokeradar"
- `dual-slot-mode` → "dual-slot"
- Others: TBD based on relevance
## Notes
- This tool replaces `tools/fetch-pokeapi/` as the primary data source for all games
- Pokemon form identifiers need mapping to pokeapi IDs — may need a fuzzy match since naming conventions differ
- The existing `pokemon.json` has names and pokeapi IDs we can use as a lookup
- S/V probability weights are not percentages — they represent relative spawn weights
- Legends Arceus uses boolean conditions (during_night + while_clear) rather than rates

View File

@@ -0,0 +1,36 @@
---
# nuzlocke-tracker-c6ly
title: Build name suggestion engine
status: completed
type: task
priority: normal
created_at: 2026-02-11T15:56:44Z
updated_at: 2026-02-11T20:44:27Z
parent: nuzlocke-tracker-igl3
blocking:
- nuzlocke-tracker-bi4e
---
Build the backend service and API endpoint that picks random name suggestions from the dictionary based on a selected naming scheme.
## Requirements
- Given a category and a run ID, return 5-10 unique suggestions
- The engine queries the run's existing encounter nicknames and excludes them from suggestions
- Support regeneration (return a fresh batch, avoiding previously shown suggestions where possible)
- Handle edge case where category is nearly exhausted gracefully (return fewer suggestions)
## Implementation Notes
- **Backend service**: A Python module that loads the dictionary JSON, filters by category, excludes used names, and picks random suggestions.
- **API endpoint**: `GET /api/v1/runs/{run_id}/name-suggestions?count=10` — reads the run's `naming_scheme`, fetches encounter nicknames, returns suggestions.
- **No new DB tables needed**: Used names come from `Encounter.nickname` on the run's encounters.
- **Caching**: Load the dictionary once and cache in memory (it's static data).
## Checklist
- [x] Create a service module for name suggestion logic (e.g. `services/name_suggestions.py`)
- [x] Implement dictionary loading with in-memory caching
- [x] Implement random selection from a category with exclusion of used names
- [x] Add API endpoint for fetching suggestions
- [x] Add unit tests for the suggestion logic

View File

@@ -0,0 +1,29 @@
---
# nuzlocke-tracker-cdmx
title: 'Clean up Sword/Shield encounter data: wild Pokemon incorrectly listed as gifts'
status: completed
type: bug
priority: normal
created_at: 2026-02-14T19:56:12Z
updated_at: 2026-02-14T21:15:04Z
---
## Problem
In the Sword and Shield seed data, wild Pokemon on almost all encounter locations are also duplicated as gift encounters. This appears to be an issue with the PokeDB export process.
## Goal
Investigate why the PokeDB export produced duplicate gift entries for wild encounters, then clean up the data so that only genuine gifts are listed as gifts.
## Findings
The PokeDB export duplicated walk encounters as gift encounters on 6 locations in each game. The affected locations were: Route 1 (Galar), Galar Mine, Motostoke Outskirts, Route 6 (Galar), Glimwood Tangle, and Route 7 (Galar). Route 6 also had legitimate fossil gifts (Arctovish, Arctozolt, Dracovish, Dracozolt) which were preserved.
## Checklist
- [x] Investigate the PokeDB export logic to understand why wild Pokemon are being duplicated as gifts
- [x] Identify which encounters are legitimately gifts vs incorrectly tagged
- [x] Remove erroneous gift entries from Sword seed data (39 removed)
- [x] Remove erroneous gift entries from Shield seed data (40 removed)
- [x] Verify remaining gift encounters are accurate

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-ceeh
title: Clean up old seed generation tools
status: completed
type: task
priority: normal
created_at: 2026-02-11T12:52:31Z
updated_at: 2026-02-11T13:55:49Z
---
Remove the old Go fetch-pokeapi tool from tools/fetch-pokeapi/ and update README.md references to point to the new import-pokedb tool instead.

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-cftf
title: Filter out routes with no encounters for active game
status: completed
type: task
priority: normal
created_at: 2026-02-14T14:38:05Z
updated_at: 2026-02-14T14:38:19Z
---
Route orders are per version group, so both games in a pair share the same route list. Routes with no encounters for the active game should be filtered out in the list_game_routes endpoint.

View File

@@ -0,0 +1,26 @@
---
# nuzlocke-tracker-ch77
title: Integration tests for Games & Routes API
status: draft
type: task
created_at: 2026-02-10T09:33:13Z
updated_at: 2026-02-10T09:33:13Z
parent: nuzlocke-tracker-yzpb
---
Write integration tests for the games and routes API endpoints in `backend/src/app/api/games.py`.
## Checklist
- [ ] Test CRUD operations for games (create, list, get, update, delete)
- [ ] Test route management within a game (create, list, reorder, update, delete)
- [ ] Test route encounter management (add/remove Pokemon to routes)
- [ ] Test bulk import functionality
- [ ] Test region grouping/filtering
- [ ] Test error cases (404 for missing games, validation errors, duplicate handling)
## Notes
- Use the httpx AsyncClient fixture from the test infrastructure task
- Each test should be independent — use fixtures to set up required data
- Test both success and error response codes and bodies

View File

@@ -0,0 +1,29 @@
---
# nuzlocke-tracker-czeh
title: Improve admin panel UX
status: completed
type: feature
priority: normal
created_at: 2026-02-05T18:28:04Z
updated_at: 2026-02-07T11:59:49Z
parent: nuzlocke-tracker-f5ob
---
Improve the admin panel with better interactions and missing management capabilities.
## Checklist
- [x] Evolution data management:
- [x] List evolutions (searchable/filterable)
- [x] Add new evolution
- [x] Edit evolution details (trigger, level, item, conditions)
- [x] Delete evolution
- [x] Route reordering:
- [x] Replace up/down buttons with drag-and-drop
- [x] Table sorting (Games table):
- [x] Add sortable column support to AdminTable component
- [x] Enable sorting by Region, Generation, and Release Year on Games table
- [x] General UX improvements:
- [x] Improve table layouts and spacing
- [x] Add loading states and better error feedback
- [x] Add confirmation toasts for successful actions
- [x] Improve mobile responsiveness of admin views

View File

@@ -0,0 +1,33 @@
---
# nuzlocke-tracker-d8cp
title: Set up frontend test infrastructure
status: draft
type: task
priority: normal
created_at: 2026-02-10T09:33:33Z
updated_at: 2026-02-10T09:34:00Z
parent: nuzlocke-tracker-yzpb
blocking:
- nuzlocke-tracker-ee9s
- nuzlocke-tracker-1guz
---
Set up the test infrastructure for the React/TypeScript frontend. No testing tooling currently exists.
## Checklist
- [ ] Install Vitest, @testing-library/react, @testing-library/jest-dom, @testing-library/user-event, jsdom
- [ ] Configure Vitest in `vite.config.ts` or a dedicated `vitest.config.ts`
- [ ] Set up jsdom as the test environment
- [ ] Create a test setup file (e.g. `src/test/setup.ts`) that imports @testing-library/jest-dom matchers
- [ ] Create test utility helpers (e.g. render wrapper with providers — QueryClientProvider, BrowserRouter)
- [ ] Add a \`test\` script to package.json
- [ ] Verify the setup by writing a simple smoke test
- [ ] Set up MSW (Mock Service Worker) or a similar API mocking strategy for hook/component tests
## Notes
- Vitest integrates natively with Vite, which the project already uses
- React Testing Library is the standard for testing React components
- The app uses React Query (TanStack Query) and React Router — the test wrapper needs to provide these contexts
- MSW is recommended for mocking API calls in hook and component tests, but simpler approaches (vi.mock) may suffice initially

View File

@@ -0,0 +1,30 @@
---
# nuzlocke-tracker-dgax
title: Nuzlocke Rules Configuration
status: completed
type: task
priority: normal
created_at: 2026-02-04T15:44:22Z
updated_at: 2026-02-04T15:58:43Z
parent: nuzlocke-tracker-f5ob
---
Create the rules/difficulty settings screen for customizing the Nuzlocke run.
## Checklist
- [x] Create rules configuration component
- [x] Implement core Nuzlocke rules toggles:
- [x] Standard rules (catch first encounter only, permadeath)
- [x] Nickname requirement toggle
- [x] Duplicates clause (can skip already-caught species)
- [x] Shiny clause (can catch shinies regardless)
- [x] Add optional difficulty modifiers:
- [x] Hardcore mode (no items in battle)
- [x] Level caps (can't overlevel gym leaders)
- [x] Set mode only (no switch after KO)
- [x] Persist selected rules to run state (local state; backend API TBD)
- [x] Show rule explanations/tooltips
## Notes
- Rules should be toggleable after run starts (user preference)
- Default to standard Nuzlocke rules

View File

@@ -0,0 +1,30 @@
---
# nuzlocke-tracker-dqyb
title: Set up Python tool scaffold
status: completed
type: task
priority: normal
created_at: 2026-02-11T08:42:58Z
updated_at: 2026-02-11T08:49:55Z
parent: nuzlocke-tracker-bs05
blocking:
- nuzlocke-tracker-zno2
---
Set up the standalone Python tool project in `tools/import-pokedb/`.
## Checklist
- [x] Create `tools/import-pokedb/` directory structure
- [x] Set up `pyproject.toml` with dependencies (just stdlib should suffice for JSON processing, maybe `click` for CLI)
- [x] Create CLI entry point (`__main__.py` or similar) that accepts:
- Path to directory containing PokeDB JSON export files
- Target output directory (default: `backend/src/app/seeds/data/`)
- Optional: specific game version to generate (default: all)
- [x] Load and parse all PokeDB JSON files: `encounters.json`, `locations.json`, `location_areas.json`, `encounter_methods.json`, `versions.json`, `pokemon_forms.json`
- [x] Basic validation that all expected files are present and parseable
## Notes
- Keep it as a standalone tool, not part of the backend
- The PokeDB JSON files are downloaded manually from https://pokedb.org/data-export — no need to automate the download
- Model the CLI similarly to how `tools/fetch-pokeapi/` works (cd into dir, run the tool)

View File

@@ -0,0 +1,40 @@
---
# nuzlocke-tracker-dyzh
title: Click-to-edit pattern across admin tables
status: completed
type: feature
priority: high
created_at: 2026-02-08T12:32:53Z
updated_at: 2026-02-08T12:45:17Z
parent: nuzlocke-tracker-iu5b
blocking:
- nuzlocke-tracker-fxi7
- nuzlocke-tracker-mg46
---
Replace the current pattern of separate Edit/Delete action buttons with an inline click-to-edit pattern across all admin pages.
## Current behavior
- Table rows show data with Edit and Delete buttons on the right
- Clicking Edit opens a modal form
- Clicking Delete opens a confirmation dialog
## Desired behavior
- Clicking a table row opens an edit card/panel inline or as a detail view
- The edit card shows all fields in editable form
- A Delete button is available within the edit card
- Save/Cancel buttons to confirm or discard changes
- Clicking outside or pressing Escape cancels
## Affected pages
- AdminPokemon (pokemon table)
- AdminEvolutions (evolutions table)
- AdminGames (games table)
- AdminGameDetail routes tab (routes table)
- AdminGameDetail bosses tab (boss battles table)
- AdminRouteDetail (route encounters table)
- AdminRuns (runs table — delete only, no edit)
## Notes
- Some pages already have row click handlers (Games navigates to detail). Preserve that where it makes sense — the edit card could be the detail page itself.
- Keep modal forms for Create (adding new entities) since there's no row to click yet.

View File

@@ -1,19 +0,0 @@
---
# nuzlocke-tracker-ecn3
title: Prune stale seed data during seeding
status: completed
type: bug
priority: normal
created_at: 2026-02-21T16:28:37Z
updated_at: 2026-02-21T16:29:43Z
---
Seeds only upsert (add/update), they never remove routes, encounters, or bosses that no longer exist in the seed JSON. When routes are renamed, old route names persist in production.
## Fix
After upserting each entity type, delete rows not present in the seed data:
1. **Routes**: After upserting all routes for a version group, delete routes whose names are not in the seed set. FK cascades handle child routes and encounters.
2. **Encounters**: After upserting encounters for a route+game, delete encounters not in the seed data for that route+game pair.
3. **Bosses**: After upserting bosses for a version group, delete bosses with order values beyond what the seed provides.

View File

@@ -0,0 +1,31 @@
---
# nuzlocke-tracker-ee9s
title: Unit tests for frontend utilities and hooks
status: draft
type: task
created_at: 2026-02-10T09:33:38Z
updated_at: 2026-02-10T09:33:38Z
parent: nuzlocke-tracker-yzpb
---
Write unit tests for the frontend utility functions and custom React hooks.
## Checklist
- [ ] Test `utils/formatEvolution.ts` — evolution chain formatting logic
- [ ] Test `utils/download.ts` — file download utility
- [ ] Test `hooks/useRuns.ts` — run CRUD hook with mocked API
- [ ] Test `hooks/useGames.ts` — game fetching hook
- [ ] Test `hooks/useEncounters.ts` — encounter operations hook
- [ ] Test `hooks/usePokemon.ts` — pokemon data hook
- [ ] Test `hooks/useGenlockes.ts` — genlocke operations hook
- [ ] Test `hooks/useBosses.ts` — boss operations hook
- [ ] Test `hooks/useStats.ts` — stats fetching hook
- [ ] Test `hooks/useAdmin.ts` — admin operations hook
## Notes
- Utility functions are pure functions — straightforward to test
- Hooks wrap React Query — test that they call the right API endpoints, handle loading/error states, and invalidate queries correctly
- Use `@testing-library/react`'s `renderHook` for hook testing
- Mock the API client (from `src/api/`) rather than individual fetch calls

View File

@@ -0,0 +1,13 @@
---
# nuzlocke-tracker-eltb
title: Deduplicate case-only duplicate sub-areas in seed data
status: completed
type: bug
priority: normal
created_at: 2026-02-08T12:21:44Z
updated_at: 2026-02-08T12:22:37Z
---
PokeAPI returns both lowercase and uppercase floor names (e.g. '1f' vs '1F') as separate sub-areas with identical encounter data. This causes duplicate routes in the UI. Fix by merging case-insensitive duplicate children in all seed JSON files, keeping the uppercase name and combining encounters.
649 duplicates across all 22 seed files.

View File

@@ -0,0 +1,28 @@
---
# nuzlocke-tracker-em40
title: Add filtering to admin tables
status: completed
type: feature
priority: low
created_at: 2026-02-08T12:33:46Z
updated_at: 2026-02-08T19:28:04Z
parent: nuzlocke-tracker-iu5b
---
Add filter controls to admin tables beyond the existing text search.
## Current state
- Pokemon and Evolutions have text search
- No other filter dimensions available
## Desired filters
- **Pokemon**: Filter by type, generation (derived from dex range)
- **Evolutions**: Filter by trigger type (level-up, trade, item, etc.)
- **Games**: Filter by region, generation
- **Routes**: Filter by encounter method availability
- **Runs**: Filter by status (active, completed, failed), game
## UX
- Filter chips or dropdown selectors above the table, next to the existing search bar
- Filters combine with search (AND logic)
- Clear all filters button

View File

@@ -0,0 +1,10 @@
---
# nuzlocke-tracker-ey30
title: Reorder Crystal routes to match Gold ordering
status: completed
type: task
created_at: 2026-02-13T14:23:40Z
updated_at: 2026-02-13T14:23:40Z
---
Adjusted the route ordering of crystal.json to match gold.json. The sequence is identical — only the order field was changed, encounters were preserved. Crystal is missing Cerulean City (not present in Crystal) so orders are offset by -1 from that point.

View File

@@ -0,0 +1,32 @@
---
# nuzlocke-tracker-f44d
title: Add Pokemon forms support to seeding
status: completed
type: task
priority: normal
created_at: 2026-02-06T10:11:23Z
updated_at: 2026-02-07T13:30:57Z
---
The current seeding only fetches base Pokemon species. It should also include alternate forms (Alolan, Galarian, Mega, regional variants, etc.) which have different types and stats.
## Scope
1. **Data model evaluation**: Determine if Pokemon forms need a separate table or can be handled with additional fields on the existing Pokemon model (e.g., `form_name`, `base_pokemon_id`)
2. **PokeAPI structure**: Investigate how forms are represented in PokeAPI data:
- `pokemon-form` endpoint
- `pokemon` endpoint (forms like `pikachu-alola` have separate entries)
- Relationship between species and forms
3. **Seed data updates**: Update `fetch_pokeapi.py` to:
- Fetch all forms for Pokemon that appear in encounter tables
- Include form-specific data (types, sprites)
- Handle form naming consistently
4. **Frontend considerations**: Ensure Pokemon selector in encounter modal can distinguish forms when relevant
## Questions to resolve
- Should forms be stored as separate Pokemon records or as variants of a base Pokemon?
- How do encounter tables reference forms vs base species in PokeAPI?
- Which games have form-specific encounters that need to be supported?

View File

@@ -0,0 +1,35 @@
---
# nuzlocke-tracker-f5ob
title: MVP - Core Nuzlocke Tracker
status: completed
type: epic
priority: normal
created_at: 2026-02-04T15:43:34Z
updated_at: 2026-02-07T12:31:15Z
blocking:
- nuzlocke-tracker-f0fm
---
The minimum viable product for the Nuzlocke Tracker application. This epic covers the essential features needed for a user to track a basic Nuzlocke run.
## Architecture
- **Frontend**: Web application for users to track their runs
- **Backend API**: RESTful or GraphQL API for data persistence
- **Database**: Persistent storage for game data, user runs, and encounters
- **Admin Panel**: Interface for managing reference data (games, routes, Pokémon)
## Goals
- Allow users to select a Pokémon game to play
- Support optional difficulty/rule settings
- Track encounters per route/area
- Track Pokémon status (alive, dead, boxed)
- Provide a clear overview of the current run
- Admin can manage game/route/Pokémon reference data
## Out of Scope for MVP
- User authentication (single user assumed)
- Multiple simultaneous runs
- Cloud sync across devices
- Team builder/planner
- Detailed statistics and analytics
- Social features

View File

@@ -0,0 +1,43 @@
---
# nuzlocke-tracker-fxi7
title: Pokemon detail card with encounters and evolution chain
status: completed
type: feature
priority: high
created_at: 2026-02-08T12:33:05Z
updated_at: 2026-02-08T12:53:13Z
parent: nuzlocke-tracker-iu5b
---
When viewing/editing a Pokemon in the admin panel, show contextual information about where it can be encountered and its evolution chain.
## Desired behavior
- The pokemon edit card (from click-to-edit) shows:
1. Editable fields (name, types, dex number, sprite, etc.)
2. **Encounter locations**: A list of routes/games where this pokemon appears as a route encounter. Grouped by game, showing route name + encounter method + levels.
3. **Evolution chain**: Visual display of the pokemon's evolution family — predecessors and successors with triggers (level, item, trade, etc.)
- Encounter locations link to the route detail page in admin for quick navigation
- Evolution chain entries are clickable to open the EvolutionFormModal for direct editing
## Implementation
### Tabbed modal (edit mode)
In edit mode, the PokemonFormModal uses three tabs instead of a single scrolling view:
- **Details** — the form fields (PokeAPI ID, name, types, etc.) with Save/Delete/Cancel footer
- **Evolutions** — clickable evolution chain rows that open a stacked EvolutionFormModal for direct editing
- **Encounters** — encounter locations grouped by game, with route names linking to admin route detail pages
In create mode, no tabs are shown (just the form fields).
### Backend endpoints
- `GET /pokemon/{id}/encounter-locations` — returns encounters grouped by game with route/game names eagerly loaded
- `GET /pokemon/{id}/evolution-chain` — BFS to find full evolution family, returns all edges with from/to Pokemon
### Frontend
- New types: `PokemonEncounterLocationItem`, `PokemonEncounterLocation`
- New API functions: `fetchPokemonEncounterLocations`, `fetchPokemonEvolutionChain`
- New hooks: `usePokemonEncounterLocations`, `usePokemonEvolutionChain`
- Extracted `formatEvolutionMethod` to shared `utils/formatEvolution.ts`
## Notes
- This helps the admin quickly verify data completeness — 'is this pokemon assigned to the right routes?' and 'are its evolutions set up correctly?'

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-g57d
title: Implement conditional boss battle teams
status: completed
type: feature
priority: normal
created_at: 2026-02-08T19:51:02Z
updated_at: 2026-02-08T19:54:52Z
---
Wire up the existing condition_label column on boss_pokemon to support variant teams in the UI. This includes: admin BossTeamEditor with variant tabs, BossDefeatModal with variant selector, RunEncounters boss card variant display, and schema additions for BulkBossPokemonItem and frontend BossPokemonInput.

View File

@@ -0,0 +1,49 @@
---
# nuzlocke-tracker-g8zi
title: 'Fix Pokemon form identification: separate PokeAPI ID from national dex'
status: completed
type: bug
priority: high
created_at: 2026-02-07T13:44:25Z
updated_at: 2026-02-07T13:54:29Z
blocking:
- 6aje
---
## Problem
Pokemon forms (Alolan, Galarian, etc.) share a national dex number with their base species (e.g., Alolan Rattata is still national dex #19, same as regular Rattata). However, the current data model uses the PokeAPI internal ID (e.g., 10091 for Alolan Rattata) as the `national_dex` field. This is semantically wrong and causes:
1. **Wrong display**: Frontend shows "#10091" next to Alolan Rattata instead of "#19"
2. **Broken sorting**: Forms sort at the end of the Pokemon list instead of next to their base species
3. **Misleading data**: The field name implies a national Pokedex number but contains an internal API ID
## Current architecture
The `national_dex` field is deeply embedded as the unique Pokemon identifier:
- **Database**: `SmallInteger` column with `UNIQUE` constraint (`alembic/versions/03e5f186a9d5`)
- **Models**: `pokemon.py``mapped_column(SmallInteger, unique=True)`
- **Seeder**: `loader.py` — upsert conflict resolution on `national_dex`, builds `{national_dex: id}` mapping for linking encounters and evolutions
- **Seed data**: `fetch_pokeapi.py` — uses PokeAPI pokemon ID as `national_dex` for both base species and forms
- **API**: All CRUD operations key on `national_dex`, returned as `nationalDex` in JSON
- **Frontend**: Displayed as `#nationalDex` in Pokemon selector, admin table, encounter modals
## Proposed fix
Add a `pokemon_id` (or similar) field as the true unique identifier (the PokeAPI pokemon ID), and keep `national_dex` as the real national dex number (shared between forms). This requires changes across every layer.
## Checklist
- [ ] Add new migration: add `pokemon_id` column (unique, not null), change `national_dex` unique constraint to non-unique
- [ ] Update Pokemon model to add `pokemon_id` field
- [ ] Update seed data: `pokemon.json` entries get both `pokemon_id` (PokeAPI ID) and `national_dex` (real dex number, from species endpoint)
- [ ] Update `fetch_pokeapi.py`: for forms, look up the species to get the real national dex, store PokeAPI ID separately
- [ ] Update `loader.py`: upsert on `pokemon_id` instead of `national_dex`, update encounter/evolution linking
- [ ] Update API schemas and endpoints to expose both fields
- [ ] Update frontend to display real `national_dex` but use `pokemon_id` internally for uniqueness
- [ ] Update encounter seed data to reference `pokemon_id` instead of `national_dex`
## Impact
Touches almost every layer: migration, model, seeder, API, frontend. Should be done before more forms are added (bean 6aje) to avoid migrating bad data.

View File

@@ -0,0 +1,31 @@
---
# nuzlocke-tracker-gkcy
title: Output seed JSON
status: completed
type: task
priority: normal
created_at: 2026-02-11T08:43:21Z
updated_at: 2026-02-11T10:00:00Z
parent: nuzlocke-tracker-bs05
blocking:
- nuzlocke-tracker-vdks
---
Generate the final per-game JSON files in the existing seed format.
## Checklist
- [x] **Apply route ordering**: Use the existing `backend/src/app/seeds/route_order.json` to assign `order` values to routes. Handle aliases (e.g. "red-blue" → "firered-leafgreen"). Log warnings for routes not in the order file.
- [x] **Merge special encounters**: Integrate starters, gifts, fossils, and trades from `backend/src/app/seeds/special_encounters.json` into the appropriate routes. Pokemon names are resolved to proper display names via PokemonMapper.
- [x] **Output per-game JSON**: Write `{game-slug}.json` files matching the existing format:
```json
[{"name": "Route 1", "order": 3, "encounters": [...], "children": []}]
```
- [x] **Output games.json**: Generate the global games list from `version_groups.json` — 38 games written, matching existing count.
- [x] **Output pokemon.json**: Generate the global pokemon list including all pokemon referenced in any encounter. Include pokeapi_id, national_dex, name, types, sprite_url.
- [x] **Handle version exclusives**: Encounters are filtered by `version_identifiers` per game — verified FireRed vs LeafGreen have 18 exclusives each.
## Notes
- The output must be a drop-in replacement for the existing files in `backend/src/app/seeds/data/`
- Boss data (`{game}-bosses.json`) is NOT generated by this tool — it's manually curated
- Evolutions data is also separate (currently from PokeAPI) — out of scope for this task

View File

@@ -0,0 +1,43 @@
---
# nuzlocke-tracker-glh8
title: Gather generation metadata (games, regions)
status: completed
type: task
priority: normal
created_at: 2026-02-08T19:20:49Z
updated_at: 2026-02-09T08:06:19Z
parent: nuzlocke-tracker-25mh
blocking:
- nuzlocke-tracker-kz5g
---
Collect and store metadata about each Pokemon generation to support genlocke features. This data is needed so the app can present generation-aware options when setting up a genlocke (e.g. "pick one game per generation").
## Data to gather per generation
- **Generation number** (19)
- **Main region** (e.g. Gen 1 → Kanto, Gen 2 → Johto, etc.)
- **Games in the generation** — including remakes and enhanced versions:
- Original titles (e.g. Red, Blue, Yellow)
- Remakes that belong to the generation's region (e.g. FireRed/LeafGreen are Gen 1 region but Gen 3 era)
- Consider whether remakes should be listed under their original generation (by region) or their release generation (by engine/dex) — genlocke players typically organize by region
## Notes
- This could be stored as seed data (JSON) or as a database table
- The existing Game model already has `generation` and `region` fields, so some of this data may already be derivable from existing games in the DB
- However, a dedicated generations reference would be useful for UI purposes (showing all generations even if not all games are seeded yet)
- Check if `backend/src/app/seeds/data/generations.json` already exists or if this needs to be created from scratch
## Decisions
- Legends games (Hisui, Lumiose) are excluded from genlocke presets — available via Custom only
- Black 2/White 2 are grouped with Black/White in the same Unova slot (category: sequel)
- Normal Genlocke defaults use best mainline remake: FireRed, HeartGold, Alpha Sapphire, Platinum, Ultra Sun
- Metadata stored as `category` field on Game model + standalone `regions.json` seed file
## Checklist
- [x] Define the generation-to-region mapping (Gen 1 = Kanto, Gen 2 = Johto, ..., Gen 9 = Paldea)
- [x] Determine how to group games by region (use `region` field on existing Game model, or create a dedicated lookup)
- [x] Create a `regions.json` seed file (or equivalent) with: generation number, region name, region order, and which games belong to each region
- [x] Categorize each game as "original", "remake", "enhanced", "sequel", or "spinoff" so presets can filter appropriately
- [x] Define which game is the "default" pick per region for the Normal Genlocke preset (e.g., FireRed for Kanto, HeartGold for Johto)
- [x] Add an API endpoint or extend the games endpoint to return games grouped by region with generation metadata
- [x] Verify all seeded games are correctly tagged with their region

View File

@@ -0,0 +1,27 @@
---
# nuzlocke-tracker-gvom
title: Boss Battles, Level Caps & Badges
status: completed
type: feature
priority: normal
created_at: 2026-02-08T10:09:33Z
updated_at: 2026-02-08T10:15:38Z
---
Add boss battle data models, API endpoints, and UI for gym leaders, elite four, champion, etc. Includes:
- Backend models (BossBattle, BossPokemon, BossResult)
- Database migration
- API endpoints for CRUD and run tracking
- Frontend types, API client, hooks
- Sticky level cap bar on run page
- Boss battle cards interleaved in encounter list
- Admin panel for managing boss battles
## Checklist
- [x] Phase 1: Backend models & migration
- [x] Phase 2: Backend schemas
- [x] Phase 3: Backend API endpoints
- [x] Phase 4: Frontend types, API & hooks
- [x] Phase 5: Frontend run page (level cap bar + boss cards)
- [x] Phase 6: Frontend admin panel

View File

@@ -0,0 +1,18 @@
---
# nuzlocke-tracker-h0dr
title: Fix route deletion failing due to missing cascade on route_encounters
status: completed
type: bug
priority: normal
created_at: 2026-02-14T14:19:56Z
updated_at: 2026-02-14T14:23:10Z
---
Deleting a route returns 500 due to two FK constraint issues:
1. `route_encounters.route_id` — missing cascade on the relationship (SQLAlchemy tried to NULL a NOT NULL column)
2. `boss_battles.after_route_id` — references the route being deleted
## Fix
- Added `cascade="all, delete-orphan"` to `Route.route_encounters` relationship
- Added `update(BossBattle).where(...).values(after_route_id=None)` before deleting the route in the delete endpoint

View File

@@ -0,0 +1,40 @@
---
# nuzlocke-tracker-h3fw
title: Use HoF team for genlocke retirement instead of all alive Pokemon
status: completed
type: task
priority: normal
created_at: 2026-02-09T09:15:00Z
updated_at: 2026-02-09T09:26:54Z
parent: nuzlocke-tracker-8w9s
blocking:
- nuzlocke-tracker-25mh
---
The current retireHoF implementation in `advance_leg()` retires ALL alive, non-shiny, caught Pokemon from the completed run. This is incorrect — only the Hall of Fame team (up to 6 Pokemon selected by the player) should be retired.
## Current behavior
```python
# genlockes.py — retires everything alive
select(Encounter.pokemon_id).where(
Encounter.run_id == current_leg.run_id,
Encounter.status == "caught",
Encounter.faint_level.is_(None),
Encounter.is_shiny.is_(False),
)
```
## Desired behavior
- If the run has `hof_encounter_ids` set, use those encounter IDs to determine which Pokemon to retire
- If `hof_encounter_ids` is not set (legacy/skipped), fall back to the current "all alive" behavior for backwards compatibility
- Only the HoF team members and their evolutionary families get added to the retired list
## Changes needed
- Update `advance_leg()` in `backend/src/app/api/genlockes.py` to check `current_run.hof_encounter_ids` first
- If present, query only those encounters for retirement
- If absent, keep the current fallback query
- Update the frontend `RunEncounters.tsx` to also scope `retiredPokemonIds` correctly (no change needed — it reads from the backend response)
## Checklist
- [x] Update `advance_leg()` to prefer `hof_encounter_ids` over all-alive query
- [x] Verify backwards compatibility when `hof_encounter_ids` is null

View File

@@ -0,0 +1,19 @@
---
# nuzlocke-tracker-hit0
title: Group parent/child routes in admin route table
status: completed
type: feature
priority: normal
created_at: 2026-02-13T13:33:36Z
updated_at: 2026-02-13T13:34:42Z
---
Visually indent child routes under their parent in the admin route table. Dragging a parent route moves all its children with it. Children cannot be independently dragged to a new position.
## Checklist
- [x] Add organizeRoutes() function to AdminGameDetail.tsx
- [x] Replace SortableRouteRow with SortableRouteGroup using multiple tbody elements
- [x] Update SortableContext to only track group IDs
- [x] Update handleDragEnd for group-aware reordering
- [x] Handle edge cases (standalone routes, orphan children)
- [x] Verify frontend build passes

View File

@@ -0,0 +1,28 @@
---
# nuzlocke-tracker-hjkk
title: Unit tests for Pydantic schemas and model validation
status: draft
type: task
created_at: 2026-02-10T09:33:03Z
updated_at: 2026-02-10T09:33:03Z
parent: nuzlocke-tracker-yzpb
---
Write unit tests for the Pydantic schemas in `backend/src/app/schemas/`. These are pure validation logic and can be tested without a database.
## Checklist
- [ ] Test `CamelModel` base class (snake_case → camelCase alias generation)
- [ ] Test run schemas — creation validation, required fields, optional fields, serialization
- [ ] Test game schemas — validation rules, field constraints
- [ ] Test encounter schemas — status enum validation, field dependencies
- [ ] Test boss schemas — nested model validation
- [ ] Test genlocke schemas — complex nested structures
- [ ] Test stats schemas — response model structure
- [ ] Test evolution schemas — validation of evolution chain data
## Notes
- Focus on: valid input acceptance, invalid input rejection, serialization output format
- The `CamelModel` base class does alias generation — verify both input (camelCase) and output (camelCase) work
- Test edge cases like empty strings, negative numbers, missing required fields

View File

@@ -0,0 +1,39 @@
---
# nuzlocke-tracker-hm6t
title: Pokemon Status Management
status: completed
type: task
priority: normal
created_at: 2026-02-04T15:44:37Z
updated_at: 2026-02-05T16:47:18Z
parent: nuzlocke-tracker-f5ob
---
Implement the system for tracking Pokémon status (alive, dead, boxed).
## Checklist
- [x] Create Pokémon card/tile component showing:
- [x] Sprite, name, nickname
- [x] Current status with visual indicator (green/red dot)
- [x] Location caught
- [x] Implement status transitions:
- [x] Alive → Dead (fainted in battle) via StatusChangeModal with confirmation
- [ ] Alive → Boxed (stored in PC) — deferred, no boxed tracking yet
- [ ] Boxed → Alive (added to party) — deferred, no boxed tracking yet
- [x] Add death recording:
- [x] Optional: record cause of death (free text, max 100 chars)
- [x] Optional: record level at death
- [x] Create "Graveyard" view for fallen Pokémon (on RunDashboard)
- [ ] Create "Box" view for stored Pokémon — deferred, no boxed tracking yet
## Implementation (death_cause feature)
- Backend: Alembic migration adds `death_cause` VARCHAR(100) to encounters
- Backend: Model + schemas updated with `death_cause` field
- Frontend: `StatusChangeModal` for recording death with confirmation from RunDashboard
- Frontend: `PokemonCard` now clickable with status indicator dot and death cause display
- Frontend: `EncounterModal` includes death cause input alongside faint level
- Frontend: `RunEncounters` shows death cause in route list
## Notes
- Status changes should be confirmable (prevent accidental deaths) ✓
- Consider undo functionality for misclicks — not implemented (Nuzlocke rules: death is permanent)

View File

@@ -0,0 +1,17 @@
---
# nuzlocke-tracker-hwyk
title: Set up Portainer on Unraid
status: completed
type: task
priority: normal
created_at: 2026-02-09T15:30:44Z
updated_at: 2026-02-09T16:53:41Z
parent: nuzlocke-tracker-ahza
---
Install Portainer CE on the Unraid server for container/stack management.
- Run Portainer CE as a Docker container on Unraid
- Configure it to manage the local Docker environment
- Import/create a stack from the production docker-compose file
- Verify the stack can be deployed and managed through the Portainer UI

View File

@@ -0,0 +1,43 @@
---
# nuzlocke-tracker-hy41
title: Admin Panel
status: completed
type: task
priority: normal
created_at: 2026-02-04T15:47:05Z
updated_at: 2026-02-05T18:22:09Z
parent: nuzlocke-tracker-f5ob
---
Build an admin interface for managing reference data.
## Checklist
- [x] Create admin routes/pages separate from tracker
- [x] Game Management:
- [x] List all games
- [x] Add new game
- [x] Edit game details
- [x] Delete game (with cascade warning)
- [x] Route Management:
- [x] List routes for a game
- [x] Add new route
- [x] Edit route details (name, order)
- [x] Delete route
- [x] Reorder routes via drag-and-drop (implemented as up/down buttons)
- [x] Route Pokémon Assignment:
- [x] View Pokémon available on a route
- [x] Add Pokémon to route
- [x] Remove Pokémon from route
- [x] Set encounter rates/methods
- [x] Pokémon Management:
- [x] List all Pokémon
- [x] Add new Pokémon
- [x] Edit Pokémon details
- [x] Bulk import from CSV/JSON
- [x] Admin API endpoints:
- [x] POST/PUT/DELETE for games, routes, pokemon, route_pokemon
## Notes
- Can be a simple CRUD interface
- Consider using a UI library for tables/forms
- No auth required for MVP (assume local/trusted use)

View File

@@ -0,0 +1,25 @@
---
# nuzlocke-tracker-i08l
title: Implement Pinwheel Clause support
status: completed
type: feature
priority: normal
created_at: 2026-02-07T19:18:34Z
updated_at: 2026-02-07T19:21:45Z
---
Add pinwheel_zone column to routes, pinwheelClause toggle to NuzlockeRules, zone-aware encounter locking on frontend and backend.
## Checklist
- [x] Alembic migration for pinwheel_zone column
- [x] SQLAlchemy model update
- [x] Pydantic schema updates
- [x] Route list API helper update
- [x] Encounter creation API zone-aware sibling check
- [x] Seed loader update
- [x] Seed data for Pinwheel Forest zones
- [x] NuzlockeRules per-run toggle
- [x] Frontend types (game.ts, admin.ts)
- [x] Admin route form pinwheelZone input
- [x] Encounter page zone-aware locking, counts, and filtering
- [x] getZoneEncounters helper

View File

@@ -0,0 +1,24 @@
---
# nuzlocke-tracker-iam7
title: Unit tests for services layer
status: draft
type: task
created_at: 2026-02-10T09:33:08Z
updated_at: 2026-02-10T09:33:08Z
parent: nuzlocke-tracker-yzpb
---
Write unit tests for the business logic in `backend/src/app/services/`. Currently this is the `families.py` service which handles Pokemon evolution family resolution.
## Checklist
- [ ] Test family resolution with simple linear evolution chains (e.g. A → B → C)
- [ ] Test family resolution with branching evolutions (e.g. Eevee)
- [ ] Test family resolution with region-specific evolutions
- [ ] Test edge cases: single-stage Pokemon, circular references (if possible), missing data
## Notes
- `services/families.py` contains the core logic for resolving Pokemon evolution families
- These tests may need mock database sessions or in-memory data depending on how the service queries data
- If the service methods take a DB session, mock it; if they operate on data objects, pass test data directly

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-idh2
title: Add PokeDB.org data attribution
status: completed
type: task
priority: normal
created_at: 2026-02-10T14:52:22Z
updated_at: 2026-02-10T14:56:25Z
---
PokeDB.org requires attribution when their data is used. Implement visible attribution in the application UI. This is both a requirement of their terms of use and good practice.

View File

@@ -0,0 +1,34 @@
---
# nuzlocke-tracker-igl3
title: Name Generation
status: completed
type: epic
priority: normal
created_at: 2026-02-05T13:45:15Z
updated_at: 2026-02-11T20:48:02Z
---
Implement a dictionary-based nickname generation system for Nuzlocke runs. Instead of using an LLM API to generate names on the fly, provide a static dictionary of words categorised by theme. A word can belong to multiple categories, making it usable across different naming schemes.
## Architecture Decisions
- **Dictionary storage**: Static JSON file in `backend/src/app/seeds/data/`, alongside other seed data. Not exposed to frontend directly.
- **Dictionary format**: Category-keyed structure (`{ "mythology": ["Apollo", ...], "space": ["Nova", ...] }`) for fast lookup by naming scheme. Words may appear in multiple categories.
- **Suggestion logic**: Backend service with API endpoint. Frontend calls the backend to get suggestions.
- **Used-name tracking**: No new storage needed. The existing `Encounter.nickname` field already tracks assigned names. The suggestion engine queries encounter nicknames for the current run and excludes them.
- **Naming scheme per run**: Dedicated nullable `naming_scheme` column on `NuzlockeRun` (not in the `rules` JSONB).
## Approach
- **Static dictionary**: A local data file (JSON) containing words organised by category (e.g. mythology, food, space, nature, warriors, music, etc.)
- **~150-200 words per category**: A typical Nuzlocke has ~100 encounters, so this provides ample variety without repetition.
- **Name suggestion UX**: When registering a new encounter, the user is shown 5-10 suggested names from their chosen naming scheme. They can click one to select it, or regenerate for a fresh batch.
- **Naming scheme selection**: Users pick a naming scheme (category) per run, either at run creation or in run settings.
## Success Criteria
- [x] Word dictionary data file exists with multiple categories, each containing 150-200 words
- [x] Name suggestion engine picks random names from the selected category, avoiding duplicates already used in the run
- [x] Encounter registration UI shows 5-10 clickable name suggestions
- [x] User can regenerate suggestions if none fit
- [x] User can select a naming scheme per run

View File

@@ -0,0 +1,18 @@
---
# nuzlocke-tracker-iu5b
title: Admin UX improvement round
status: completed
type: epic
priority: normal
created_at: 2026-02-08T12:32:43Z
updated_at: 2026-02-08T19:32:28Z
---
A round of UX improvements to the admin panel to make data editing more intuitive and efficient. The admin panel is the primary tool for populating game data (routes, encounters, bosses, evolutions), so friction here directly slows down adding support for new games.
## Key themes
- **Consistency**: Unify interaction patterns across all admin pages (click-to-edit, reordering, selectors)
- **Efficiency**: Reduce clicks and navigation depth for common workflows
- **Discoverability**: Surface related data (where a pokemon appears, its evolution chain) directly in context
- **Bulk operations**: Enable importing all entity types, not just Pokemon

View File

@@ -0,0 +1,20 @@
---
# nuzlocke-tracker-izf6
title: Configure Gitea container registry
status: completed
type: task
priority: normal
created_at: 2026-02-09T15:30:40Z
updated_at: 2026-02-09T16:53:09Z
parent: nuzlocke-tracker-ahza
---
Set up and verify the Gitea container registry for hosting Docker images as user-level packages.
## Checklist
- [ ] Create a Gitea access token with `read:package` and `write:package` scopes
- [ ] Verify `docker login gitea.nerdboden.de` works from the dev machine
- [ ] Test pushing a Docker image as a user-level package (e.g., `gitea.nerdboden.de/thefurya/nuzlocke-tracker-api:latest`)
- [ ] Verify the image appears under the user's Packages tab in Gitea
- [ ] Test pulling the image back (from Unraid or dev machine)

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-j02g
title: Fix duplicate Alembic migration revision IDs
status: completed
type: bug
priority: normal
created_at: 2026-02-14T12:13:08Z
updated_at: 2026-02-14T12:14:34Z
---
Two migration files share revision ID f7a8b9c0d1e2: add_game_id_to_boss_battles and add_naming_scheme_to_genlockes. Fix by giving one a new unique ID and chaining them sequentially.

View File

@@ -0,0 +1,53 @@
---
# nuzlocke-tracker-j28y
title: Curate route ordering to match game progression
status: completed
type: task
priority: normal
created_at: 2026-02-05T13:37:39Z
updated_at: 2026-02-07T12:30:17Z
parent: nuzlocke-tracker-f5ob
---
Routes are currently in alphabetical order from PokeAPI. Update the order field in each game's JSON seed file to reflect actual game progression (e.g., Pallet Town → Route 1 → Viridian City → Route 2 → ...).
## Automated Approach: Bulbapedia Walkthrough Scraping
We already have all location/encounter data from PokeAPI. The missing piece is progression order, which can be extracted from Bulbapedia walkthroughs.
### Data Source
Every game has a Bulbapedia walkthrough with routes listed in progression order:
- https://bulbapedia.bulbagarden.net/wiki/Walkthrough:Pokémon_FireRed_and_LeafGreen
- https://bulbapedia.bulbagarden.net/wiki/Walkthrough:Pokémon_Emerald
- https://bulbapedia.bulbagarden.net/wiki/Walkthrough:Pokémon_HeartGold_and_SoulSilver
- (and so on for all games through Gen 8)
### Implementation Plan
1. **Scrape walkthrough TOCs** - Parse the section headings from each game's walkthrough page to get route order
2. **Normalize names** - Map Bulbapedia location names to PokeAPI location names (handle differences like "Route 1" vs "Kanto Route 1")
3. **Generate ordering** - Create a JSON mapping of `{game: {location_name: order_number}}`
4. **Update fetch_pokeapi.py** - Apply ordering when generating seed data
### Benefits
- Automatable for all games (Gen 1-8)
- Bulbapedia walkthroughs are community-maintained and accurate
- Scales as we add more games
- Only needs to run once per game (or when walkthroughs update)
### Considerations
- Gen 9 (Scarlet/Violet) is open-world so ordering is less meaningful
- Some games have branching paths - may need to pick a canonical order
- Name matching between Bulbapedia and PokeAPI may need fuzzy matching
## Current Scope
- FireRed and LeafGreen share the same route progression (Kanto)
- HeartGold and SoulSilver share the same route progression (Johto + Kanto)
- Emerald has its own progression (Hoenn)
- So effectively 3 unique orderings to define for current games
## Files
- `backend/src/app/seeds/data/firered.json`
- `backend/src/app/seeds/data/leafgreen.json`
- `backend/src/app/seeds/data/emerald.json`
- `backend/src/app/seeds/data/heartgold.json`
- `backend/src/app/seeds/data/soulsilver.json`

View File

@@ -0,0 +1,25 @@
---
# nuzlocke-tracker-jain
title: Handle Nincada split evolution (Ninjask + Shedinja)
status: completed
type: feature
priority: normal
created_at: 2026-02-08T19:38:55Z
updated_at: 2026-02-08T20:47:50Z
---
Nincada is a special case in Pokemon: when it evolves at level 20, the player gets both Ninjask (the normal evolution) AND Shedinja (if there's an empty party slot and a spare Poke Ball). This creates a unique situation for Nuzlocke tracking since one encounter effectively produces two usable Pokemon.
## Problem
The current evolution system assumes 1:1 evolution (one Pokemon evolves into one Pokemon). The Nincada line breaks this — a single caught Nincada can yield two team members. Nuzlocke rules vary on how to handle this:
- Some players treat Shedinja as a free bonus (allowed to use both)
- Some players must choose one and box/release the other
- Some rulesets ban Shedinja entirely since it wasn't "encountered"
## Considerations
- The evolution data already has a `shed` trigger type for the Nincada → Shedinja evolution, separate from the `level-up` trigger for Nincada → Ninjask
- This may need a rule option in run settings (e.g., "Allow Shedinja from Nincada evolution")
- The encounter tracking may need to support creating a second encounter entry from the same route when a Nincada evolves
- Consider whether this is purely a rules/UI concern or if the data model needs changes

View File

@@ -0,0 +1,29 @@
---
# nuzlocke-tracker-jlzs
title: Implement Gitea Actions CI/CD pipeline
status: completed
type: task
priority: normal
created_at: 2026-02-10T09:38:15Z
updated_at: 2026-02-10T11:34:52Z
parent: nuzlocke-tracker-ahza
---
Set up Gitea Actions as the CI/CD pipeline for the nuzlocke-tracker. Gitea Actions uses the same syntax as GitHub Actions, making it portable if the project goes public on GitHub later.
## Context
- Gitea is already running on Unraid behind Nginx Proxy Manager (`gitea.nerdboden.de`)
- Images are currently built locally and pushed to the Gitea container registry via `deploy.sh`
- A Gitea Actions runner is already deployed on Unraid and connected to the Gitea instance
- The workflow syntax is compatible with GitHub Actions, so the same `.github/workflows/` files work on both platforms
## Checklist
- [x] **Enable Gitea Actions on the Gitea instance** — Actions feature is enabled and runner is connected
- [x] **Set up a Gitea Actions runner**`act_runner` is deployed on Unraid and registered with Gitea
- [x] **Create CI workflow** (`.github/workflows/ci.yml`) — on push to `develop` and PRs: run `ruff check` + `ruff format --check` for backend, `eslint` + `tsc` for frontend. Tests can be added later when they exist.
- [x] **Create deploy workflow** (`.github/workflows/deploy.yml`) — triggered via `workflow_dispatch` on `main`: build Docker images (linux/amd64), push to the Gitea container registry, deploy to Unraid via SSH (`docker compose pull && docker compose up -d`)
- [x] **Configure secrets in Gitea** — generate a new SSH keypair, add the public key to Unraid root user's `authorized_keys`, add the private key as a Gitea repo secret (`DEPLOY_SSH_KEY`). Also add any registry credentials or other sensitive values the workflows need.
- [x] **Test the full pipeline** — push a change through `feature/*``develop` (verify CI runs), then merge `develop``main` and trigger the deploy workflow via `workflow_dispatch` to verify end-to-end
- [x] **Update deployment docs** — document the Gitea Actions setup, how to manage the runner, and how CI/CD fits into the deployment workflow

View File

@@ -0,0 +1,33 @@
---
# nuzlocke-tracker-jq50
title: Add ability to end a run (success/failure)
status: completed
type: task
priority: normal
created_at: 2026-02-06T10:22:00Z
updated_at: 2026-02-07T12:12:42Z
parent: nuzlocke-tracker-f5ob
---
Add functionality to mark a Nuzlocke run as completed (success) or failed.
## Requirements
1. **Run status transitions**:
- Active → Completed (player beat the game)
- Active → Failed (all Pokemon fainted / player gave up)
2. **UI elements needed**:
- "End Run" button on run dashboard
- Confirmation modal with success/failure choice
- Optional: Add notes/summary when ending
- Display completion status prominently on ended runs
3. **Backend**:
- Endpoint already supports status update via PATCH /runs/{id}
- May need to set `completedAt` timestamp when ending
4. **Considerations**:
- Should ended runs be editable? (probably lock encounters)
- Show run duration (started → completed)
- Victory/defeat visual treatment (colors, icons)

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-jrbc
title: Fix doubled encounters in EncounterModal
status: completed
type: bug
priority: normal
created_at: 2026-02-08T11:16:35Z
updated_at: 2026-02-08T11:17:25Z
---
EncounterModal calls useRoutePokemon without gameId, so route encounters for all games in the version group are returned. Pass gameId through from RunEncounters.

View File

@@ -0,0 +1,28 @@
---
# nuzlocke-tracker-jzqz
title: Configure Portainer API for automated redeployment
status: completed
type: task
priority: normal
created_at: 2026-02-09T15:30:45Z
updated_at: 2026-02-09T17:28:22Z
parent: nuzlocke-tracker-ahza
blocking:
- nuzlocke-tracker-hwyk
---
Use the Portainer CE REST API to trigger stack redeployments from the deploy script.
Portainer webhooks are a Business-only feature, so we use the API directly instead.
## Approach
1. Authenticate with the Portainer API to get a JWT token
2. Call the stack update endpoint with `pullImage: true` to pull latest images and recreate containers
## Checklist
- [ ] Identify the stack ID in Portainer (via API or UI)
- [ ] Test API authentication (`POST /api/auth`)
- [ ] Test triggering a stack redeploy via API
- [ ] Integrate into the deploy script

View File

@@ -0,0 +1,12 @@
---
# nuzlocke-tracker-jzw4
title: Switch prod compose to bind mounts for persistent data
status: completed
type: task
priority: normal
created_at: 2026-02-10T08:15:41Z
updated_at: 2026-02-10T08:16:44Z
parent: nuzlocke-tracker-ahza
---
Replace named Docker volume with bind mount to ./data/postgres subfolder. The docker-compose.prod.yml will live at /mnt/user/appdata/nuzlocke-tracker/ on Unraid, so relative paths resolve to subfolders there.

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-k4u8
title: Implement pre-commit hooks for linting
status: completed
type: task
priority: normal
created_at: 2026-02-14T15:37:32Z
updated_at: 2026-02-14T15:40:44Z
---
Set up pre-commit framework with hooks for ruff (backend), ESLint/Prettier/tsc (frontend). Add pre-commit to dev deps, update CI with Prettier check, document in CLAUDE.md.

View File

@@ -0,0 +1,34 @@
---
# nuzlocke-tracker-k5lm
title: Initial Game Data Seeding
status: completed
type: task
priority: normal
created_at: 2026-02-04T15:44:12Z
updated_at: 2026-02-05T13:37:50Z
parent: nuzlocke-tracker-f5ob
---
Create seed data for the database with initial games, routes, and Pokémon.
## Checklist
- [x] Research and compile data for MVP games:
- [x] Pokémon FireRed/LeafGreen (Gen 3 Kanto remakes - popular for Nuzlockes)
- [x] Pokémon Emerald (Gen 3 Hoenn)
- [x] Pokémon HeartGold/SoulSilver (Gen 4 Johto remakes)
- [x] For each game, gather:
- [x] All routes/areas in progression order
- [x] Available wild Pokémon per route
- [x] Encounter methods (grass, surf, fish, etc.)
- [x] Create seed scripts/migrations to populate database
- [x] Include Pokémon base data (national dex, names, types, sprite URLs)
- [x] Document data sources for attribution
- [x] Curate route ordering to match game progression — split to nuzlocke-tracker-j28y
## Notes
- Admin panel allows adding more games later
- Focus on accuracy for the 3 MVP games
## Data Sources
- Game data (routes, encounters, Pokemon): [PokeAPI](https://pokeapi.co/) via [pokebase](https://github.com/PokeAPI/pokebase) Python wrapper
- Sprites: [PokeAPI/sprites](https://github.com/PokeAPI/sprites) on GitHub

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-k60g
title: Rewrite fetch_pokeapi in Go
status: completed
type: feature
priority: normal
created_at: 2026-02-07T15:38:58Z
updated_at: 2026-02-07T15:44:25Z
---
Rewrite the Python PokeAPI fetching tool in Go with custom HTTP client, disk caching, and zero external dependencies. Replace aiopoke dependency that crashes on newer PokeAPI fields.

View File

@@ -0,0 +1,53 @@
---
# nuzlocke-tracker-k7ot
title: Genlocke management in admin panel
status: completed
type: feature
priority: normal
created_at: 2026-02-09T08:38:13Z
updated_at: 2026-02-09T09:51:51Z
parent: nuzlocke-tracker-25mh
---
Add genlocke management to the admin panel, allowing admins to view, edit, and delete genlockes and their legs.
## Admin Pages
### Genlocke List (`/admin/genlockes`)
- Table of all genlockes: name, status, number of legs, created date
- Status badge (active / completed / failed)
- Click to view/edit details
- Delete button with confirmation
### Genlocke Detail (`/admin/genlockes/:genlockeId`)
- Edit genlocke name and status
- View and manage legs: reorder, add, remove
- Change the game assigned to a leg
- View linked runs (with links to admin run detail)
- Delete genlocke with cascade confirmation
## Backend
- `GET /api/v1/genlockes` — List all genlockes with legs (may already exist from overview page bean)
- `GET /api/v1/genlockes/{id}` — Get full genlocke detail
- `PATCH /api/v1/genlockes/{id}` — Update genlocke name, status, rules
- `DELETE /api/v1/genlockes/{id}` — Delete genlocke and cascade to legs
- `POST /api/v1/genlockes/{id}/legs` — Add a leg
- `DELETE /api/v1/genlockes/{id}/legs/{legId}` — Remove a leg
- `PUT /api/v1/genlockes/{id}/legs/reorder` — Reorder legs
## Frontend
- New admin routes: `/admin/genlockes`, `/admin/genlockes/:genlockeId`
- Add "Genlockes" nav item to admin sidebar
- Admin list and detail page components
- API client functions and hooks for admin CRUD operations
## Checklist
- [x] Implement `GET /api/v1/genlockes` list endpoint
- [x] Implement `GET /api/v1/genlockes/{id}` detail endpoint
- [x] Implement `PATCH /api/v1/genlockes/{id}` update endpoint
- [x] Implement `DELETE /api/v1/genlockes/{id}` delete endpoint
- [x] Implement leg management endpoints (add, remove)
- [x] Build admin genlocke list page
- [x] Build admin genlocke detail/edit page
- [x] Add admin routes and sidebar navigation
- [x] Add frontend API client and hooks for genlocke admin

View File

@@ -0,0 +1,26 @@
---
# nuzlocke-tracker-kghn
title: Child route management from route detail
status: completed
type: feature
priority: low
created_at: 2026-02-08T12:33:53Z
updated_at: 2026-02-08T19:31:57Z
parent: nuzlocke-tracker-iu5b
---
Allow adding/editing/deleting child routes (sub-areas) directly from the route detail page, instead of only from the game detail routes tab.
## Current state
- Child routes can only be created from the game detail routes tab
- The route detail page shows encounters but doesn't show or manage its children
- To add a child route, you navigate away from the route detail back to the game
## Desired behavior
- Route detail page shows a 'Sub-areas' section listing child routes (if any)
- Can add new child routes from this view
- Can click a child route to navigate to its encounter detail
- Can delete child routes from this view
## Notes
- This is lower priority since child routes are typically set up once during initial data entry and rarely changed afterward.

Some files were not shown because too many files have changed in this diff Show More