Compare commits

...

166 Commits

Author SHA1 Message Date
Renovate Bot
70aa1156f5 Add renovate.json
All checks were successful
CI / backend-tests (pull_request) Successful in 27s
CI / frontend-tests (pull_request) Successful in 28s
2026-02-22 11:00:54 +00:00
1513bb3658 Split e2e tests into manual workflow_dispatch workflow
All checks were successful
CI / frontend-tests (push) Successful in 27s
CI / backend-tests (push) Successful in 26s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 17:54:25 +01:00
3b63285bd1 Fix FK violations when pruning stale routes
Some checks failed
CI / backend-tests (push) Successful in 26s
CI / frontend-tests (push) Successful in 27s
CI / e2e-tests (push) Has been cancelled
Bulk delete bypasses ORM-level cascades, so manually delete
route_encounters, nullify boss_battle.after_route_id, and skip
routes referenced by user encounters before deleting stale routes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 17:50:54 +01:00
4f0f881736 Update remaining FireRed boss sprites
All checks were successful
CI / backend-tests (push) Successful in 25s
CI / frontend-tests (push) Successful in 27s
CI / e2e-tests (push) Successful in 5m29s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 17:39:14 +01:00
dde20c932b Update Brock and Misty boss sprites
Some checks failed
CI / backend-tests (push) Successful in 26s
CI / frontend-tests (push) Successful in 27s
CI / e2e-tests (push) Has been cancelled
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 17:37:29 +01:00
efa0b5f855 Add --prune flag to seed command to remove stale data
Without --prune, seeds continue to only upsert (add/update).
With --prune, routes, encounters, and bosses not present in the
seed JSON files are deleted from the database.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 17:33:54 +01:00
d535433583 Archive 23 completed beans
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 16:59:54 +01:00
bf4302cdd4 Use host IP for backend test database URL in CI
All checks were successful
CI / backend-tests (push) Successful in 25s
CI / frontend-tests (push) Successful in 26s
CI / e2e-tests (push) Successful in 4m58s
The Postgres service container is not reachable via localhost from
inside the act runner container. Use the Docker host IP instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 16:49:04 +01:00
9a8a4f75f9 Use uv run for backend tests instead of system pip install
Some checks failed
CI / backend-tests (push) Failing after 1m13s
CI / frontend-tests (push) Successful in 27s
CI / e2e-tests (push) Has been cancelled
The uv-managed Python is externally managed and rejects --system pip
installs. Use uv run --extra dev to handle venv creation, dependency
installation, and test execution in a single step.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 16:43:35 +01:00
00734ee233 Use host IP for e2e test API in CI
Some checks failed
CI / backend-tests (push) Failing after 26s
CI / frontend-tests (push) Successful in 29s
CI / e2e-tests (push) Successful in 5m37s
The act runner executes steps inside a container where localhost does
not reach the Docker host. Use E2E_API_URL env var (set to the host IP
192.168.1.10:8100 in CI) so both the global setup and Vite proxy can
reach the test API container.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 16:38:29 +01:00
b50e9160ba Add uv to PATH after install in CI
The uv installer places the binary in ~/.local/bin which isn't on
PATH by default in the act runner. Source the env file for the current
step and append to GITHUB_PATH for subsequent steps.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 16:32:51 +01:00
f6bcb1fbe5 Fix CI failures for backend and e2e test jobs
Some checks failed
CI / backend-tests (push) Failing after 9s
CI / frontend-tests (push) Successful in 27s
CI / e2e-tests (push) Failing after 2m6s
Replace astral-sh/setup-uv action with direct curl install to avoid
Node.js 18 incompatibility (setup-uv v6+ requires Node 20+). Change
e2e test API host port from 8000 to 8100 to avoid conflict with
existing service on the CI runner.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 16:29:04 +01:00
bf3a3d3329 Replace CI lint jobs with backend, frontend, and e2e test jobs
Some checks failed
CI / backend-tests (push) Failing after 37s
CI / frontend-tests (push) Successful in 28s
CI / e2e-tests (push) Failing after 1m42s
Lint, formatting, and type checks are already enforced by prek pre-commit
hooks, so CI now focuses on running the actual test suites instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 14:13:34 +01:00
9aaa95a1c7 Add component tests for EndRunModal, GameGrid, RulesConfiguration, Layout
33 tests covering rendering, user interactions (userEvent clicks), prop
callbacks, filter state, and conditional description text. Adds a
matchMedia stub to the vitest setup file so components importing
useTheme don't throw in jsdom. Also adds actionlint and zizmor
pre-commit hooks for GitHub Actions linting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:57:12 +01:00
0d2f419c6a Add unit tests for frontend utilities and hooks
82 tests covering download.ts and all React Query hooks. API modules are
mocked with vi.mock; mutation tests spy on queryClient.invalidateQueries
to verify cache invalidation. Conditional queries (null id) are verified
to stay idle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:47:55 +01:00
c80d7d0802 Set up frontend test infrastructure
Install @testing-library/react, @testing-library/jest-dom,
@testing-library/user-event, and jsdom. Configure Vitest with globals,
jsdom environment, and a setup file importing jest-dom matchers. Add a
custom render helper wrapping components with QueryClientProvider and
MemoryRouter. Exclude e2e/ from vitest. Smoke test covers
formatEvolutionMethod.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:35:15 +01:00
ee5bf03f19 Add integration tests for Genlockes & Bosses API
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:21:32 +01:00
34835abe0c Add integration tests for Pokemon & Evolutions API
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:15:00 +01:00
ca736e0f39 Add unit tests for services layer
36 tests covering build_families (linear chains, branching, disjoint,
Shedinja case), resolve_base_form, to_roman (parametrized), and
strip_roman_suffix including round-trip verification.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:05:24 +01:00
d6a0b60585 Add integration tests for Runs & Encounters API
28 tests covering run CRUD, rules JSONB storage, encounter creation,
route-lock enforcement, shinyClause and giftClause bypasses, status
transitions (complete/fail), and encounter update/delete.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 12:58:28 +01:00
79eabf4f9f Add integration tests for Games & Routes API
25 tests covering game CRUD (create/list/get/update/delete), slug
uniqueness enforcement, by-region grouping, and route operations
(create/update/delete/reorder). Verifies that list_game_routes
excludes routes with no Pokemon encounters.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 12:51:37 +01:00
4aae12cd72 Add unit tests for Pydantic schemas
46 tests across 12 schema classes covering CamelModel alias generation,
required field validation, optional field defaults, camelCase input/output,
nested model coercion, and from_attributes support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 12:41:22 +01:00
b0ac3714a9 Set up backend test infrastructure
Add pytest fixtures (engine, db_session, client) with session-scoped
event loop to avoid asyncpg loop mismatch errors. Smoke tests verify
all three main API endpoints return empty results on a clean DB.
Test DB provided by docker-compose.test.yml on port 5433.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 12:35:22 +01:00
16f9e68821 Mark Overhaul Nuzlocke Rules System epic as completed
All child features are done.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 12:23:37 +01:00
993ad09d9c Add type restriction rule (monolocke)
All checks were successful
CI / backend-lint (push) Successful in 10s
CI / actions-lint (push) Successful in 14s
CI / frontend-lint (push) Successful in 22s
Adds allowedTypes: string[] to NuzlockeRules. When set, the encounter
selector hides non-matching Pokemon and the routes endpoint filters out
routes with no matching encounters, so only eligible locations appear.

Type picker UI in RulesConfiguration; active restriction shown in
RuleBadges. Backend accepts allowed_types query param and joins through
RouteEncounter.pokemon to filter by type.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 12:22:05 +01:00
85fef68dae Add static clause rule for encounter selector filtering
All checks were successful
CI / backend-lint (push) Successful in 10s
CI / actions-lint (push) Successful in 15s
CI / frontend-lint (push) Successful in 23s
When disabled, static encounters (legendaries, scripted Pokémon) are
grayed out and unselectable in the encounter selector. Enabled by default.
Adds 'static' to METHOD_CONFIG/METHOD_ORDER with a teal badge.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 12:04:39 +01:00
aea5d1d84d Update bean 2026-02-20 22:03:52 +01:00
347c25e8ed Add boss team match playstyle rule
All checks were successful
CI / backend-lint (push) Successful in 9s
CI / actions-lint (push) Successful in 16s
CI / frontend-lint (push) Successful in 21s
When enabled, the sticky boss banner shows the next boss's team size
as a hint for players who voluntarily match the boss's party count.
Handles variant boss teams by using the auto-detected starter variant.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 22:03:11 +01:00
6968d35a33 Fix boss banner sticking behind nav header on scroll
The sticky level cap banner had z-10 and top-0, placing it behind the
nav (z-40) and overlapping it. Use top-14 to clear the nav height and
z-30 to layer correctly below the nav but above page content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 21:59:46 +01:00
18cc116348 Add gift clause rule for free gift encounters
When enabled, in-game gift Pokemon (starters, trades, fossils) do not
count against a location's encounter limit. Both a gift encounter and
a regular encounter can coexist on the same route, in any order.

Persists encounter origin on the Encounter model so the backend can
exclude gift encounters from route-lock checks bidirectionally, and the
frontend can split them into a separate display layer that doesn't lock
the route for regular encounters.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 21:55:16 +01:00
ed1f7ad3d0 Increase encounter method badge sizes for readability
All checks were successful
CI / backend-lint (push) Successful in 9s
CI / actions-lint (push) Successful in 15s
CI / frontend-lint (push) Successful in 21s
Bump xs from 8px to 10px and sm from 9px to 12px so the route-list
badges (Grass, Surfing, Gift, etc.) are legible at a glance.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 21:35:54 +01:00
2298c32691 Add egglocke, wonderlocke, and randomizer variant rules
All checks were successful
CI / backend-lint (push) Successful in 9s
CI / actions-lint (push) Successful in 14s
CI / frontend-lint (push) Successful in 21s
When any variant rule is enabled, the encounter modal switches from
the game's regional dex to an all-Pokemon search (same debounced
API pattern as EggEncounterModal). A new "Run Variant" section in
rules configuration groups these rules, and badges render in amber.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 21:33:01 +01:00
e25d1cf24c Remove unused nuzlocke rules, reorganize into core and playstyle
All checks were successful
CI / backend-lint (push) Successful in 9s
CI / actions-lint (push) Successful in 15s
CI / frontend-lint (push) Successful in 21s
Remove firstEncounterOnly, permadeath, nicknameRequired, and
postGameCompletion from the rules system — they are either implicit
(it's a nuzlocke tracker) or not enforced. Move levelCaps to core
(it's displayed in the sticky bar). Create a new "playstyle" category
for hardcoreMode and setModeOnly — informational rules useful for
stats but not enforced by the tracker. Remove the completion category
entirely. Add sub-task beans for the rules overhaul epic.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 21:20:23 +01:00
4fbfcf9b29 Fix WCAG AA color contrast violations across all pages
All checks were successful
CI / backend-lint (push) Successful in 9s
CI / actions-lint (push) Successful in 15s
CI / frontend-lint (push) Successful in 21s
Replace incorrect perceived-brightness formula in Stats progress bars
with proper WCAG relative luminance calculation, and convert type bar
colors to hex values for reliable contrast detection. Add light: variant
classes to status badges, yellow/purple text, and admin nav links across
17 files. Darken light-mode status-active token and text-tertiary/muted
tokens. Add aria-labels to admin filter selects and flex-wrap for mobile
overflow on AdminEvolutions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 20:48:16 +01:00
a12478f24b Fix e2e tests for ESM and podman-compose compatibility
All checks were successful
CI / backend-lint (push) Successful in 9s
CI / actions-lint (push) Successful in 14s
CI / frontend-lint (push) Successful in 21s
Replace __dirname with import.meta.url (required by "type": "module").
Replace --wait flag with manual health polling (unsupported by
podman-compose). Use explicit -p project name to isolate test
containers from dev environment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 20:19:17 +01:00
a7ec49fcad Add Playwright accessibility and mobile layout e2e tests
All checks were successful
CI / backend-lint (push) Successful in 49s
CI / actions-lint (push) Successful in 15s
CI / frontend-lint (push) Successful in 1m2s
Set up end-to-end test infrastructure with Docker Compose test
environment, Playwright config, and automated global setup/teardown
that seeds a test database and creates fixtures via the API.

Tests cover 11 pages across both dark/light themes for WCAG 2.0 AA
accessibility (axe-core), and across 3 viewports (mobile, tablet,
desktop) for horizontal overflow and touch target validation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 20:08:17 +01:00
a381633413 Add dark/light mode toggle with adaptive badge colors
Implement theme switching via sun/moon toggle in nav bar. Dark
remains the default; light mode overrides surface, text, border,
accent, and status color tokens. Preference persists in localStorage
and falls back to prefers-color-scheme. An inline script in
index.html prevents flash of wrong theme on load.

Define a Tailwind v4 @custom-variant for light mode and update all
badge components (encounter method, rule, condition) to use
light:bg-{color}-100 / light:text-{color}-700 for readable contrast
on light surfaces.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 19:45:12 +01:00
cb35bf161e Update bean 2026-02-20 19:27:46 +01:00
Julian Tabel
7ec43431e5 Add epic: Overhaul Nuzlocke Rules System
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 14:28:50 +01:00
Julian Tabel
4d097158bd Add new epic 2026-02-19 08:44:05 +01:00
92dad22981 Simplify modal, badge, and component styles to dark-first (#29)
All checks were successful
CI / backend-lint (push) Successful in 9s
CI / actions-lint (push) Successful in 16s
CI / frontend-lint (push) Successful in 20s
Co-authored-by: Julian Tabel <juliantabel.jt@gmail.com>
Co-committed-by: Julian Tabel <juliantabel.jt@gmail.com>
2026-02-17 21:08:53 +01:00
42b66ee9a2 Implement dark-first design system with Geist typography (#28)
All checks were successful
CI / backend-lint (push) Successful in 10s
CI / actions-lint (push) Successful in 16s
CI / frontend-lint (push) Successful in 21s
Co-authored-by: Julian Tabel <juliantabel.jt@gmail.com>
Co-committed-by: Julian Tabel <juliantabel.jt@gmail.com>
2026-02-17 20:48:42 +01:00
e3b3dc5317 Rebrand to Another Nuzlocke Tracker (ANT) (#27)
All checks were successful
CI / backend-lint (push) Successful in 9s
CI / actions-lint (push) Successful in 14s
CI / frontend-lint (push) Successful in 21s
Co-authored-by: Julian Tabel <juliantabel.jt@gmail.com>
Co-committed-by: Julian Tabel <juliantabel.jt@gmail.com>
2026-02-17 20:17:07 +01:00
ecc3d0c6b9 Archive 172 completed and scrapped beans
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 19:40:41 +01:00
7df56325a8 Add per-condition encounter rates to seed data (#26)
All checks were successful
CI / backend-lint (push) Successful in 9s
CI / actions-lint (push) Successful in 15s
CI / frontend-lint (push) Successful in 20s
Co-authored-by: Julian Tabel <juliantabel.jt@gmail.com>
Co-committed-by: Julian Tabel <juliantabel.jt@gmail.com>
2026-02-17 19:38:29 +01:00
d0fff248fe Scrap bean in favor of 4ni4 2026-02-17 18:27:15 +01:00
459b3b0829 Add missing files to gitignore 2026-02-17 18:23:31 +01:00
c8dd4414b5 Mark bean rb0p as completed
Some checks failed
CI / backend-lint (push) Successful in 14s
CI / actions-lint (push) Failing after 6s
CI / frontend-lint (push) Successful in 22s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 18:17:54 +01:00
8cfa074ea6 Migrate pre-commit hooks from pre-commit to prek
Replace the Python-based pre-commit framework with prek (Rust) for
faster hook execution. Convert .pre-commit-config.yaml to prek.toml,
remove pre-commit from dev dependencies, and apply ruff auto-fixes
(UP037: remove unnecessary string quotes in type annotations).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 18:17:23 +01:00
Julian Tabel
bbc054c02f Add bean for encounter conditions seed data work
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 08:40:42 +01:00
8f4ee8f239 Add condition badges for boss Pokemon mechanics
Some checks failed
CI / backend-lint (push) Failing after 9s
CI / actions-lint (push) Failing after 7s
CI / frontend-lint (push) Successful in 21s
Show colored pill badges (Mega, G-Max, D-Max, Tera) on boss Pokemon
in BossDefeatModal and BossTeamPreview. Starter-dependent condition
labels are ignored. Follows EncounterMethodBadge pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 21:17:32 +01:00
7aeddd61da Populate boss Pokemon teams in seed data
Add Pokemon teams (pokeapi_id, level, order) to all 327 boss entries
across 21 seed files, sourced from Bulbapedia. Includes starter-dependent
teams via condition_label, Mega Evolution, Dynamax/Gigantamax,
Terastallize, and single-Pokemon entries for Totems/Nobles/Titans.
Also fix _export_bosses to include condition_label in exported data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 21:07:48 +01:00
3a64661760 Align repo config with global development standards
Some checks failed
CI / backend-lint (push) Failing after 1m4s
CI / actions-lint (push) Failing after 6s
CI / frontend-lint (push) Successful in 59s
- Add missing tsconfig strictness flags (noUncheckedIndexedAccess,
  exactOptionalPropertyTypes, noImplicitOverride,
  noPropertyAccessFromIndexSignature) and fix all resulting type errors
- Replace ESLint/Prettier with oxlint 1.48.0 and oxfmt 0.33.0
- Pin all frontend and backend dependencies to exact versions
- Pin GitHub Actions to SHA hashes with persist-credentials: false
- Fix CI Python version mismatch (3.12 -> 3.14) and ruff target-version
- Add vitest 4.0.18 with jsdom environment for frontend testing
- Add ty 0.0.17 for Python type checking (non-blocking in CI)
- Add actionlint and zizmor CI job for workflow linting and security audit
- Add Dependabot config for npm, pip, and github-actions
- Update CLAUDE.md and pre-commit hooks to reflect new tooling
- Ignore Claude Code sandbox artifacts in gitignore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 20:39:41 +01:00
e4814250db Update checklist of completed bean 2026-02-14 22:50:04 +01:00
9b9b189735 Update seed data
All checks were successful
CI / backend-lint (push) Successful in 9s
CI / frontend-lint (push) Successful in 33s
2026-02-14 22:43:44 +01:00
a482b27bca Refine bean oqfo: encounter rate display for time/weather variants
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 22:17:57 +01:00
eff67a0ad5 Add new Boss sprites
All checks were successful
CI / backend-lint (push) Successful in 9s
CI / frontend-lint (push) Successful in 33s
2026-02-14 22:15:57 +01:00
5eae1331db Mark bean cdmx as completed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 22:15:20 +01:00
00ed0a1cbd Remove erroneous gift encounters from Sword/Shield seed data
Wild Pokemon on 6 locations were incorrectly duplicated as gift encounters
by the PokeDB export. Removed 39 from Sword and 40 from Shield, preserving
legitimate gifts (starters, fossils, Type Null, Kubfu, etc.).

Resolves beans-cdmx.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 22:15:01 +01:00
129b1aff83 Add bean cdmx for Sword/Shield encounter data cleanup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 22:13:08 +01:00
0faa3d3a85 Mark bean qvww as completed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 22:12:35 +01:00
06d0c4504d Mark bean r48e as completed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 22:11:14 +01:00
50da4b9c56 Normalise route naming scheme to 'Route X (Region)' format
Standardise 426 inconsistent route names across 33 seed data files
(game data + boss files). Converts 'Region Route X' prefix style and
'Route X - Region' dash style to the consistent 'Route X (Region)' format.

Resolves beans-r48e.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 22:10:09 +01:00
2963f16aa4 Add pre-commit hooks for linting and formatting
All checks were successful
CI / backend-lint (push) Successful in 9s
CI / frontend-lint (push) Successful in 33s
Set up pre-commit framework with ruff (backend) and ESLint/Prettier/tsc
(frontend) hooks to catch issues locally before CI. Auto-format all
frontend files with Prettier to comply with the new check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 16:41:24 +01:00
b05a75f7f2 Update bean 2026-02-14 16:30:18 +01:00
c4ed232996 Refine seed data: route ordering and boss configs up to gen 8 (WIP)
All checks were successful
CI / backend-lint (push) Successful in 9s
CI / frontend-lint (push) Successful in 31s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 16:28:27 +01:00
a691fb94c4 Fix route filtering to keep parent routes with encountered children
In flat mode, parent routes with no direct encounters were being
filtered out even when their children had encounters. Now we pre-compute
which parents have encountered children so they're retained in both
flat and hierarchical modes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 16:09:50 +01:00
76fe0ca270 Filter out routes with no encounters for the active game
Routes are shared per version group, so game-exclusive locations (e.g.,
Black City, White Forest) appeared for both games. Now the /games/{id}/routes
endpoint excludes routes that have no encounters for the requested game,
in both flat and hierarchical modes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 15:40:28 +01:00
d1503553ea Fix route deletion failing due to FK constraint violations
All checks were successful
CI / backend-lint (push) Successful in 8s
CI / frontend-lint (push) Successful in 31s
Route deletion failed with two integrity errors:
1. route_encounters had no cascade, so SQLAlchemy tried to NULL
   the non-nullable route_id instead of deleting the rows
2. boss_battles.after_route_id referenced the route being deleted

Added cascade="all, delete-orphan" to Route.route_encounters and
nulled out boss battle after_route_id references before deletion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 15:24:02 +01:00
a31e8bf174 Remove route order aliases so each version group has standalone ordering
Originals and remakes previously shared route orderings via aliases
(e.g. red-blue → firered-leafgreen). This prevented customizing route
progression independently. Each version group now has its own list that
can be fine-tuned for game-specific locations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 13:50:02 +01:00
56d5fb4800 Fix duplicate Alembic migration revision ID f7a8b9c0d1e2
All checks were successful
CI / backend-lint (push) Successful in 9s
CI / frontend-lint (push) Successful in 30s
Two migrations (add_game_id_to_boss_battles and add_naming_scheme_to_genlockes)
shared the same revision ID, causing multiple heads. Gave boss_battles migration
a new unique ID (g8b9c0d1e2f3) and chained it after the naming_scheme migration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 13:14:40 +01:00
bb3794a276 Update Cilan/Chill/Cress sprite
All checks were successful
CI / backend-lint (push) Successful in 8s
CI / frontend-lint (push) Successful in 30s
2026-02-14 13:11:06 +01:00
68c480e2c3 feature/genlocke-naming-scheme (#23)
Reviewed-on: TheFurya/nuzlocke-tracker#23
Co-authored-by: Julian Tabel <juliantabel.jt@gmail.com>
Co-committed-by: Julian Tabel <juliantabel.jt@gmail.com>
2026-02-14 11:04:41 +01:00
ebdc9b2f28 feature/boss-sprites-and-badges (#22)
All checks were successful
CI / backend-lint (push) Successful in 8s
CI / frontend-lint (push) Successful in 32s
Reviewed-on: TheFurya/nuzlocke-tracker#22
Co-authored-by: Julian Tabel <juliantabel.jt@gmail.com>
Co-committed-by: Julian Tabel <juliantabel.jt@gmail.com>
2026-02-14 11:04:08 +01:00
3412d6c6fd Add naming scheme support for genlockes with lineage-aware suggestions (#20)
All checks were successful
CI / backend-lint (push) Successful in 8s
CI / frontend-lint (push) Successful in 33s
Genlockes can now select a naming scheme at creation time, which is
automatically applied to every leg's run. When catching a pokemon whose
evolution family appeared in a previous leg, the system suggests the
original nickname with a roman numeral suffix (e.g., "Heracles II").

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Reviewed-on: TheFurya/nuzlocke-tracker#20
Co-authored-by: Julian Tabel <juliantabel.jt@gmail.com>
Co-committed-by: Julian Tabel <juliantabel.jt@gmail.com>
2026-02-14 10:00:36 +01:00
c01c504519 Add new bean 2026-02-13 17:10:23 +01:00
Julian Tabel
b7d1c88d5e Change Dockerfile ordering
All checks were successful
CI / backend-lint (push) Successful in 8s
CI / frontend-lint (push) Successful in 29s
2026-02-13 15:53:22 +01:00
Julian Tabel
7a4d5d26b5 Update Seed data (Gen1-3)
All checks were successful
CI / backend-lint (push) Successful in 8s
CI / frontend-lint (push) Successful in 32s
2026-02-13 15:41:15 +01:00
Julian Tabel
b62e0db6a0 Reorder Crystal routes to match Gold ordering
Crystal shares the same route progression as Gold, so align its route
order values to match. Only order fields changed; encounters preserved.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 15:24:06 +01:00
Julian Tabel
1b6970a982 Group parent/child routes in admin route table
Visually indent child routes under their parent with tree connectors,
and make dragging a parent move all its children as a unit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 14:37:35 +01:00
Julian Tabel
867ded8fa2 Add pinwheel, encounters link, and boss position columns to admin tables
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 14:10:28 +01:00
Julian Tabel
29a5c84651 Fix footer floating mid-page on short content pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 13:59:18 +01:00
f676bee400 Merge pull request 'feature/filter-swsh-den-routes' (#18) from feature/filter-swsh-den-routes into develop
All checks were successful
CI / backend-lint (push) Successful in 7s
CI / frontend-lint (push) Successful in 32s
Reviewed-on: TheFurya/nuzlocke-tracker#18
2026-02-13 09:31:20 +01:00
Julian Tabel
b7be099aee Filter out Max Raid den routes from Sword/Shield game data
All checks were successful
CI / backend-lint (pull_request) Successful in 8s
CI / frontend-lint (pull_request) Successful in 29s
Den child routes (~561 per game) bloated the route list without being
useful for Nuzlocke tracking. Adds filter_den_routes() to strip children
matching "(Den " from the route hierarchy, reducing Sw/Sh from ~1,007
to 446 routes each.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 09:18:29 +01:00
Julian Tabel
659dcf2252 Remove artificial Starter route, use real PokeDB starter locations
Replace the synthetic "Starter" route with actual in-game locations
(e.g. Professor Oak's Laboratory, Iki Town, Littleroot Town). Starters
now appear at their real locations with method "starter" by remapping
PokeDB's "gift" method during import. Split ruby-sapphire and
black-2-white-2 out of special_encounters aliases since their starter
locations differ from the aliased version groups.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 09:08:35 +01:00
Julian Tabel
2655c0d64f Add bean for sticky footer bug
All checks were successful
CI / backend-lint (push) Successful in 7s
CI / frontend-lint (push) Successful in 31s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 08:48:20 +01:00
Julian Tabel
000658b4cd Remove stale duplicate routes and fix ordering in seed data
The DB accumulated stale routes from previous imports with different
naming (e.g. "Route 1" alongside "Alola Route 1"). These were exported
back to JSON, causing duplicate entries with conflicting order values.

Removed 597 stale routes across 17 game files and re-sorted all 22
game files to match the canonical progression in route_order.json.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 08:41:48 +01:00
24e4c41f88 Delete superfluous seed files
All checks were successful
CI / backend-lint (push) Successful in 8s
CI / frontend-lint (push) Successful in 30s
2026-02-11 22:13:05 +01:00
65220b46ed Merge pull request 'Add Boss list for all games and more boss types' (#17) from feature/add-boss-data into develop
All checks were successful
CI / backend-lint (push) Successful in 8s
CI / frontend-lint (push) Successful in 32s
Reviewed-on: TheFurya/nuzlocke-tracker#17
2026-02-11 21:59:50 +01:00
b55a82117e fix format in backend
All checks were successful
CI / backend-lint (pull_request) Successful in 8s
CI / frontend-lint (pull_request) Successful in 30s
2026-02-11 21:58:46 +01:00
40bce99c0b fix backend linting
Some checks failed
CI / backend-lint (pull_request) Failing after 8s
CI / frontend-lint (pull_request) Successful in 31s
2026-02-11 21:57:45 +01:00
dbddee4d92 Merge branch 'develop' into feature/add-boss-data
Some checks failed
CI / backend-lint (pull_request) Failing after 8s
CI / frontend-lint (pull_request) Successful in 31s
2026-02-11 21:52:41 +01:00
734fb50f0a Add merge migration; COmmit bean changes
Some checks failed
CI / backend-lint (push) Failing after 8s
CI / frontend-lint (push) Successful in 32s
2026-02-11 21:51:35 +01:00
39d18c241e Integrate name suggestions into encounter registration UI
Add clickable suggestion chips below the nickname input in the encounter
modal. Chips are fetched from GET /runs/{id}/name-suggestions via React
Query, shown only when a naming scheme is set. Clicking a chip fills in
the nickname; a regenerate button fetches a fresh random batch. Completes
the Name Generation epic.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 21:48:29 +01:00
2ac6c23577 Add name suggestion engine with API endpoint and tests
Expand services/naming.py with suggest_names() that picks random words
from a category while excluding nicknames already used in the run. Add
GET /runs/{run_id}/name-suggestions?count=10 endpoint that reads the
run's naming_scheme and returns filtered suggestions. Includes 12 unit
tests covering selection, exclusion, exhaustion, and cross-category
independence.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 21:45:04 +01:00
15283ede91 Add name dictionary with 10 themed categories
Create name_dictionary.json with 175 words each across mythology, food,
space, nature, warriors, music, literature, gems, ocean, and weather
categories. Words are short (<= 12 chars), title-cased, and suitable as
Pokemon nicknames. No intra-category duplicates; cross-category overlap
is intentional.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 21:42:33 +01:00
e324559476 Add naming scheme selection to run configuration
Add a nullable naming_scheme column to NuzlockeRun so users can pick a
themed word category for nickname suggestions. Includes Alembic migration,
updated Pydantic schemas, a GET /runs/naming-categories endpoint backed by
a cached dictionary loader, and frontend dropdowns in both the NewRun
creation flow and the RunDashboard for mid-run changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 21:36:50 +01:00
f71db65642 Add Boss list for all games and more boss types
All checks were successful
CI / backend-lint (pull_request) Successful in 8s
CI / frontend-lint (pull_request) Successful in 30s
2026-02-11 21:33:55 +01:00
Julian Tabel
e61fce5f72 Refine Naming Generator Epic 2026-02-11 17:00:16 +01:00
Julian Tabel
5582d9028f Complete Game Data Cleanup epic 2026-02-11 15:34:02 +01:00
Julian Tabel
1683b60a5e Bean completed 2026-02-11 15:22:59 +01:00
Julian Tabel
d0b0f08665 Fix and complete route ordering for all games
All checks were successful
CI / backend-lint (push) Successful in 7s
CI / frontend-lint (push) Successful in 29s
Rewrote route_order.json with correct progression ordering for all 15
version groups (Gen 1-9), validated against encounter data files. Added
generate_route_order.py script for reproducible generation and validation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 15:21:18 +01:00
Julian Tabel
157e9ed987 Add starters for all games to special_encounters.json
All checks were successful
CI / backend-lint (push) Successful in 7s
CI / frontend-lint (push) Successful in 30s
Added starter data for Gen 4-9, Legends Arceus, and Legends Z-A.
Fixed Yellow and Let's Go which were incorrectly aliased to the
firered-leafgreen Gen 1 trio — they now have their own entries.
Added aliases for Platinum, BD/SP, B2/W2, and USUM.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 14:52:38 +01:00
Julian Tabel
9a0cf7a552 Remove redundant gift/fossil entries from special_encounters.json
Gifts, trades, and fossils are already in the per-game encounter data.
Only starters need to remain in special_encounters.json. Updated the
corresponding bean to reflect the narrowed scope.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 14:48:23 +01:00
Julian Tabel
c81a697879 Mark encounter data beans as completed
Encounter data is now complete for Gen 8+ stub games and ORAS/Let's Go titles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 14:41:45 +01:00
63bb3a0394 Remove old Go fetch-pokeapi tool, update README for import-pokedb (#13)
All checks were successful
CI / backend-lint (push) Successful in 7s
CI / frontend-lint (push) Successful in 29s
The Go tool in tools/fetch-pokeapi/ has been fully replaced by the
Python import-pokedb tool. Removes all Go source files, updates the
README seed regeneration docs, and cleans up the .gitignore entry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Co-authored-by: Julian Tabel <julian.tabel@synvert.com>
Reviewed-on: TheFurya/nuzlocke-tracker#13
2026-02-11 13:55:38 +01:00
f42cee7f7a Update README.md 2026-02-11 13:48:37 +01:00
Julian Tabel
dfa49e62fe Update bean 2026-02-11 13:42:44 +01:00
Julian Tabel
174b145e84 Fix webp sprites not loading in production nginx
All checks were successful
CI / backend-lint (push) Successful in 7s
CI / frontend-lint (push) Successful in 30s
Include mime.types at the server block level to ensure .webp files
are served with the correct Content-Type (image/webp).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 13:23:58 +01:00
Julian Tabel
02367a8e3a Merge branch 'develop' of ssh://192.168.1.10:2222/TheFurya/nuzlocke-tracker into develop
All checks were successful
CI / backend-lint (push) Successful in 7s
CI / frontend-lint (push) Successful in 31s
2026-02-11 13:03:49 +01:00
Julian Tabel
42764b2485 Add sprites 2026-02-11 13:02:18 +01:00
90399f41b7 Merge branch 'develop' into main 2026-02-11 12:00:31 +01:00
Julian Tabel
aadd730002 Mark PokeDB import feature and subtasks as completed
All checks were successful
CI / backend-lint (push) Successful in 11s
CI / frontend-lint (push) Successful in 30s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 11:56:25 +01:00
Julian Tabel
872d7872ce Validate and regenerate all seed data from PokeDB
- Regenerate seed JSON for all 37 games with more complete PokeDB data
- Add category field to games.json (original/enhanced/remake/sequel/spinoff)
- Include all 1350 pokemon in pokemon.json with types and local sprites
- Build reverse index for PokeDB form lookups (types/sprites for evolutions)
- Move sprites to frontend/public/sprites, reference as /sprites/{id}.webp
- Truncate Sw/Sh den names to fit DB VARCHAR(100) limit
- Deduplicate route names and merge unnamed child areas into parent routes
- Populate 7 previously empty games (Sw/Sh, BDSP, PLA, Sc/Vi)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 11:52:51 +01:00
Julian Tabel
df55233c62 Add seed JSON output (per-game, games.json, pokemon.json)
Wire output module into CLI pipeline: route ordering, special encounter
merging, and JSON writing for per-game encounters, global games list,
and pokemon list with types and sprite paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 10:59:56 +01:00
Julian Tabel
29b954726a Add PokeDB sprite downloading (100x100 WebP)
Download pokemon sprites from PokeDB CDN during import, cached locally
as {pokeapi_id}.webp. Replaces PokeAPI GitHub sprite URLs. ~4.6MB for
all 1119 unique sprites.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 10:24:43 +01:00
Julian Tabel
d80c59047c Add core encounter processing pipeline
Filter by game version, parse levels and rate variants across all
generations, aggregate encounters by pokemon+method, and build
parent/child route hierarchy. Also completes encounter method coverage
(73/73) and pokemon form mapping (1180/1181) with manual overrides.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 10:12:55 +01:00
Julian Tabel
df7ea64b9e Add reference data mappings and auto-download for PokeDB import tool
Add mappings module with pokemon form, location area, encounter method,
and version mappings. Auto-download PokeDB JSON exports from CDN on
first run, caching in .pokedb_cache/.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 10:02:57 +01:00
Julian Tabel
1aa67665ff Add Python tool scaffold for PokeDB data import
Set up tools/import-pokedb/ with CLI, JSON loader, and output models.
Replaces the Go/PokeAPI approach with local PokeDB.org JSON processing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 09:49:51 +01:00
e686cd5d54 Merge pull request 'develop' (#6) from develop into main
Reviewed-on: TheFurya/nuzlocke-tracker#6
2026-02-10 16:02:20 +01:00
5151be785b feature/pokedb-attribution (#5)
All checks were successful
CI / backend-lint (push) Successful in 7s
CI / frontend-lint (push) Successful in 29s
Co-authored-by: Julian Tabel <julian.tabel@synvert.com>
Reviewed-on: TheFurya/nuzlocke-tracker#5
2026-02-10 16:01:14 +01:00
Julian Tabel
45a34ecf31 Add rebrand to Another Nuzlocke Tracker (ANT) bean
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 15:57:55 +01:00
Julian Tabel
27ec0194bc Add seed container evaluation bean, blocked on PokeDB import
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 15:31:36 +01:00
6e5ba94e98 Merge pull request 'Update some beans' (#4) from develop into main
Reviewed-on: TheFurya/nuzlocke-tracker#4
2026-02-10 15:19:54 +01:00
Julian Tabel
00dead68f7 Add PokeDB.org data import bean, encounter display bean, complete data source research
- Complete exploration of automated data sources (q5vd): PokeDB.org
  identified as ideal single source of truth with JSON data export
- Add bean for PokeDB.org data import tool (bs05)
- Add bean for improving encounter rate display with time/weather
  variants (oqfo)
- Mark branding cleanup bean (xvaw) as completed

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 15:16:26 +01:00
Julian Tabel
597ad91629 Prioritize beans and add pre-commit hooks task
Game Data Cleanup → critical, Tests → high, pre-commit hooks → high,
boss battles → low, remaining epics → deferred.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 13:06:13 +01:00
Julian Tabel
617f92a7ea Mark branding cleanup bean as completed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 13:02:30 +01:00
Julian Tabel
1842aa947b Add pull-before-merge rule to CLAUDE.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 12:58:52 +01:00
99b969ab5e Merge pull request 'Release frontend branding and metadata' (#3) from develop into main
Reviewed-on: TheFurya/nuzlocke-tracker#3
2026-02-10 12:55:18 +01:00
9ea03c598a Merge pull request 'Clean up frontend branding and metadata' (#2) from feature/branding-cleanup into develop
All checks were successful
CI / backend-lint (push) Successful in 7s
CI / frontend-lint (push) Successful in 28s
Reviewed-on: TheFurya/nuzlocke-tracker#2
2026-02-10 12:53:15 +01:00
Julian Tabel
03b5572429 Clean up frontend branding and metadata
All checks were successful
CI / backend-lint (pull_request) Successful in 7s
CI / frontend-lint (pull_request) Successful in 31s
Replace Vite defaults with Nuzlocke Tracker branding: custom pokeball-
skull favicon (SVG + PNG + ICO), page title, meta description, Open
Graph tags, theme-color, web manifest, and package.json name.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 12:44:09 +01:00
Julian Tabel
66bd1a421f Update deployment docs, complete Deployment Strategy epic
Rewrite DEPLOYMENT.md to reflect current state (CI/CD, backups, merge
strategy). Expand CI paths-ignore to skip docs, license, gitignore,
and deploy workflow changes. Add merge strategy to CLAUDE.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 12:38:34 +01:00
Julian Tabel
132dac0a2e Update deployment docs, complete Deployment Strategy epic
All checks were successful
CI / backend-lint (push) Successful in 7s
CI / frontend-lint (push) Successful in 29s
Rewrite DEPLOYMENT.md to reflect current state (CI/CD, backups, merge
strategy). Expand CI paths-ignore to skip docs, license, gitignore,
and deploy workflow changes. Add merge strategy to CLAUDE.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 12:37:43 +01:00
87e4bb8941 Merge pull request 'develop' (#1) from develop into main
Reviewed-on: TheFurya/nuzlocke-tracker#1
2026-02-10 12:31:19 +01:00
Julian Tabel
7e8d55ec06 Skip CI on bean-only changes
All checks were successful
CI / backend-lint (push) Successful in 7s
CI / frontend-lint (push) Successful in 29s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 12:29:52 +01:00
Julian Tabel
29f0b930f8 Mark lint cleanup bean as completed
All checks were successful
CI / backend-lint (push) Successful in 7s
CI / frontend-lint (push) Successful in 28s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 12:28:45 +01:00
Julian Tabel
e4111c67bc Fix linting errors across backend and frontend
All checks were successful
CI / backend-lint (push) Successful in 7s
CI / frontend-lint (push) Successful in 29s
Backend: auto-fix and format all ruff issues, manually fix B904/B023/
SIM117/B007/E741/F841 errors, suppress B008 (FastAPI Depends) and F821
(SQLAlchemy forward refs) in config. Frontend: allow constant exports,
disable React compiler-specific rules (set-state-in-effect,
preserve-manual-memoization).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 12:26:57 +01:00
Julian Tabel
7f8890086f Add CI and deploy workflows for Gitea Actions
Some checks failed
CI / backend-lint (push) Failing after 1m43s
CI / frontend-lint (push) Failing after 1m6s
CI runs ruff and eslint/tsc on push to develop and PRs. Deploy
workflow is manual (workflow_dispatch) and builds, pushes, and
deploys images to Unraid via SSH.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 12:17:20 +01:00
Julian Tabel
0c4cc815be Remove cron job setup from deploy script
Backup scheduling will be handled via the Unraid User Scripts plugin
instead, which persists across reboots.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 12:02:35 +01:00
Julian Tabel
58475d9cba Add database backup script with daily cron and 7-day retention
pg_dump-based backup script deployed alongside compose file. Deploy
script now installs a daily cron job (03:00) on Unraid automatically.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 11:55:27 +01:00
Julian Tabel
7b383dd982 Set up branching structure and add branching rules to CLAUDE.md
Create develop branch from main and document the branching strategy
(main/develop/feature/*) in CLAUDE.md to enforce the workflow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 11:50:11 +01:00
Julian Tabel
bd267499b8 Add Gitea Actions CI/CD pipeline task to deployment epic
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 10:38:59 +01:00
Julian Tabel
3254103cf6 Add frontend branding and metadata cleanup task
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 10:36:37 +01:00
Julian Tabel
6f4ed3460b Add Unit & Integration Tests epic with subtasks
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 10:34:45 +01:00
Julian Tabel
fae6532b8a Add Game Data Cleanup epic with subtasks
Track the work needed to audit and complete encounter data and route
ordering across all supported games. Covers automated source exploration,
Gen 8+ stub population, ORAS/Let's Go completion, route ordering for
Gen 5+, Gen 1-4 ordering audit, and special encounters review.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 10:00:14 +01:00
Julian Tabel
31355975e1 Update deployment beans to reflect SSH-based approach
Remove Portainer references, mark NPM and env management as
completed, update epic checklist and decided approach.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 09:45:58 +01:00
Julian Tabel
83a17c8f15 Build images for linux/amd64 to run on Unraid
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 09:43:18 +01:00
Julian Tabel
7ea6b30396 Rework deploy script to SSH directly into Unraid
Replace Portainer-based redeployment with direct SSH approach:
- Auto-detect podman/docker for local builds
- SCP compose file to Unraid
- Generate Postgres password in .env if missing
- Pull images and (re)start containers via SSH

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 09:32:41 +01:00
Julian Tabel
3f39b5f0cb Use bind mount for prod database storage instead of named volume
Store PostgreSQL data at ./data/postgres relative to the compose file
so persistent data lives on the Unraid disk at
/mnt/user/appdata/nuzlocke-tracker/data/postgres.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 09:17:14 +01:00
61a7f57f1f Update beans and deployment docs
Update epic checklist, mark completed tasks, fix Gitea username/domain
references, and update DEPLOYMENT.md with correct registry paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 18:28:56 +01:00
03f07ebee5 Add deploy script and update prod compose
Deploy script builds and pushes images to Gitea registry, then triggers
Portainer stack redeployment via API. Includes preflight checks for
branch and uncommitted changes. Also renames prod DB volume to avoid
conflicts with dev and changes frontend port to 9080.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 18:28:17 +01:00
972137acfb Fix TypeScript errors in frontend build
Cast boss type select value to union type and remove unused
AdvanceLegInput import.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 18:10:38 +01:00
fd23d89e71 Add production Dockerfiles and nginx config
Backend: installs non-editable, runs uvicorn without reload.
Frontend: multi-stage build, serves static files via nginx with
API proxy to the backend service and SPA fallback routing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 18:00:28 +01:00
d9d547ef53 Add production docker-compose file
Uses pre-built images from the Gitea container registry, runs Alembic
migrations before API startup, and keeps the database password configurable
via environment variable. No source mounts or debug mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 17:58:55 +01:00
349a0cb821 Add DEPLOYMENT.md as living deployment documentation
Covers architecture overview, Gitea container registry setup, branching
strategy, and deployment workflow. Sections not yet implemented are marked
with TODO to be filled in as the deployment epic progresses.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 17:56:06 +01:00
ad4ac6cf8c Update deployment strategy to use Gitea instead of plain Docker registry
Gitea provides source hosting, container registry, and CI/CD in one package.
Images are pushed as user-level packages to the Gitea registry over SSL.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 17:45:43 +01:00
Julian Tabel
6a86c56e3b Add deployment strategy child task beans
Split the deployment strategy epic into 11 individual task beans
with blocking dependencies.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 16:32:04 +01:00
Julian Tabel
e6646fc3e0 Add deployment strategy epic bean
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 16:29:28 +01:00
Julian Tabel
f9f94e5e9c Add post-game completion rule option
Add postGameCompletion toggle to nuzlocke rules so players can indicate
whether a run ends after the Champion or continues into post-game. Adds
a new "Completion" category section in rules configuration with a green
badge color.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 12:24:06 +01:00
Julian Tabel
6d955439eb Fix team sort: add to RunEncounters and fix hook ordering
Add sort dropdown to RunEncounters (the encounters page with the
expandable team section) and move all useMemo hooks before early
returns in both RunDashboard and RunEncounters to fix React hook
ordering violations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 12:21:07 +01:00
Julian Tabel
bc9bcf4c4b Add sort options to run team overview
Add a dropdown to sort Active Team and Graveyard by route order,
catch level, species name, or national dex number.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 12:11:54 +01:00
Julian Tabel
c67621295a Mark genlocke tracking epic and edge cases bean as completed
All 14 success criteria met, all 10 child tasks completed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 12:08:18 +01:00
Julian Tabel
924efa9073 Show error feedback when run deletion is blocked
Add optional error prop to DeleteConfirmModal and wire it into AdminRuns
so the backend's rejection message is displayed to the user.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 12:07:09 +01:00
Julian Tabel
f0307f0625 Guard genlocke data integrity edge cases
Block deletion of runs linked to a genlocke leg, prevent reactivating
completed/failed genlocke-linked runs, and guard encounter deletion
against genlocke transfer references with clear 400 errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 12:03:58 +01:00
Julian Tabel
d3b65e3c79 Add genlocke lineage tracking with aligned timeline view
Implement read-only lineage view that traces Pokemon across genlocke legs
via existing transfer records. Backend walks transfer chains to build
lineage entries; frontend renders them as cards with a column-aligned
timeline grid so leg dots line up vertically across all lineages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 11:58:38 +01:00
Julian Tabel
4e00e3cad8 Fix HoF display for transfers/shinies and hook ordering
Move alive and hofTeam into useMemo hooks above early returns to fix
React hook ordering violation. Include transfer and shiny encounters
in alive so they appear in the team section and can be selected for
the Hall of Fame.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 11:45:29 +01:00
2047 changed files with 401448 additions and 119442 deletions

View File

@@ -1,19 +0,0 @@
---
# 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

@@ -3,8 +3,9 @@
title: Soullink tracking title: Soullink tracking
status: draft status: draft
type: epic type: epic
priority: deferred
created_at: 2026-02-09T07:56:50Z created_at: 2026-02-09T07:56:50Z
updated_at: 2026-02-09T07:56:50Z updated_at: 2026-02-10T12:05:43Z
--- ---
Track a **soullink** — a multiplayer nuzlocke variant where two (or more) players play through the same game simultaneously. Each player's Pokemon are **linked** in pairs: if one partner's Pokemon dies, the linked Pokemon on the other player's side dies too. Track a **soullink** — a multiplayer nuzlocke variant where two (or more) players play through the same game simultaneously. Each player's Pokemon are **linked** in pairs: if one partner's Pokemon dies, the linked Pokemon on the other player's side dies too.

View File

@@ -1,11 +0,0 @@
---
# 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

@@ -1,28 +0,0 @@
---
# 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

@@ -1,34 +0,0 @@
---
# 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

@@ -1,89 +0,0 @@
---
# nuzlocke-tracker-25mh
title: Genlocke tracking
status: todo
type: epic
priority: normal
created_at: 2026-02-08T12:17:19Z
updated_at: 2026-02-09T07:45:10Z
---
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
- [ ] Each leg is a full nuzlocke run, tracked identically to standalone runs
- [ ] 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
- [ ] A genlocke overview page shows progress, configuration, cumulative stats, lineage, and graveyard
- [ ] Transferred Pokemon appear as eggs (base form, level 1) in the next leg
- [ ] Pokemon lineage is trackable across multiple legs
- [ ] A cumulative graveyard shows all deaths across the entire genlocke
- [ ] The Retire HoF / Gauntlet rule correctly retires HoF Pokemon and adds their families to the dupe list

View File

@@ -1,19 +0,0 @@
---
# 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

@@ -1,23 +0,0 @@
---
# 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

@@ -1,11 +0,0 @@
---
# 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

@@ -1,29 +0,0 @@
---
# 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

@@ -1,30 +0,0 @@
---
# 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

@@ -1,26 +0,0 @@
---
# 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

@@ -1,31 +0,0 @@
---
# 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

@@ -1,28 +0,0 @@
---
# 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

@@ -1,11 +0,0 @@
---
# 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

@@ -1,37 +0,0 @@
---
# 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

@@ -1,30 +0,0 @@
---
# 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

@@ -1,11 +0,0 @@
---
# 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

@@ -1,11 +0,0 @@
---
# 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

@@ -1,37 +0,0 @@
---
# 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

@@ -1,28 +0,0 @@
---
# 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

@@ -1,40 +0,0 @@
---
# 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

@@ -1,11 +0,0 @@
---
# 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

@@ -1,25 +0,0 @@
---
# 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

@@ -1,67 +0,0 @@
---
# 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

@@ -1,11 +0,0 @@
---
# 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

@@ -1,19 +0,0 @@
---
# 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

@@ -1,24 +0,0 @@
---
# 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

@@ -1,40 +0,0 @@
---
# 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

@@ -1,29 +0,0 @@
---
# 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

@@ -3,9 +3,9 @@
title: User Account integration title: User Account integration
status: draft status: draft
type: epic type: epic
priority: normal priority: deferred
created_at: 2026-02-04T16:17:01Z created_at: 2026-02-04T16:17:01Z
updated_at: 2026-02-09T07:56:53Z updated_at: 2026-02-10T12:05:43Z
blocking: blocking:
- nuzlocke-tracker-0jec - nuzlocke-tracker-0jec
--- ---

View File

@@ -1,30 +0,0 @@
---
# 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

@@ -1,40 +0,0 @@
---
# 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

@@ -0,0 +1,19 @@
---
# 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

@@ -1,13 +0,0 @@
---
# 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

@@ -1,28 +0,0 @@
---
# 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

@@ -3,8 +3,9 @@
title: Romhack Integration title: Romhack Integration
status: draft status: draft
type: epic type: epic
priority: deferred
created_at: 2026-02-04T15:48:34Z created_at: 2026-02-04T15:48:34Z
updated_at: 2026-02-04T15:48:34Z updated_at: 2026-02-10T12:05:43Z
--- ---
Support for tracking Nuzlocke runs in popular Pokémon romhacks, which often feature custom routes, modified Pokémon, new regional forms, and altered encounter tables. Support for tracking Nuzlocke runs in popular Pokémon romhacks, which often feature custom routes, modified Pokémon, new regional forms, and altered encounter tables.

View File

@@ -1,32 +0,0 @@
---
# 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

@@ -1,35 +0,0 @@
---
# 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

@@ -1,43 +0,0 @@
---
# 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

@@ -1,11 +0,0 @@
---
# 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

@@ -1,49 +0,0 @@
---
# 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

@@ -1,43 +0,0 @@
---
# 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

@@ -1,27 +0,0 @@
---
# 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

@@ -1,40 +0,0 @@
---
# 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

@@ -1,39 +0,0 @@
---
# 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

@@ -1,43 +0,0 @@
---
# 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

@@ -1,25 +0,0 @@
---
# 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

@@ -1,11 +0,0 @@
---
# nuzlocke-tracker-igl3
title: Name Generation
status: draft
type: epic
priority: normal
created_at: 2026-02-05T13:45:15Z
updated_at: 2026-02-08T20:33:36Z
---
For nuzlockes I want to implement name generation. The user should be able to provide a naming scheme or a list of nick names that can then be selected when a new encounter is registered.

View File

@@ -1,18 +0,0 @@
---
# 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

@@ -1,53 +0,0 @@
---
# 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

@@ -1,25 +0,0 @@
---
# 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

@@ -1,33 +0,0 @@
---
# 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

@@ -1,11 +0,0 @@
---
# 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

@@ -1,34 +0,0 @@
---
# 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

@@ -1,11 +0,0 @@
---
# 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

@@ -1,53 +0,0 @@
---
# 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

@@ -1,26 +0,0 @@
---
# 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.

View File

@@ -1,65 +0,0 @@
---
# nuzlocke-tracker-kvmd
title: Boss Battles, Level Caps & Badges
status: completed
type: feature
priority: normal
created_at: 2026-02-07T20:16:14Z
updated_at: 2026-02-08T11:23:58Z
---
Add boss battle tracking (Gym Leaders, Elite Four, Champion, rivals), badge progression, and level cap enforcement to the nuzlocke tracker.
## Context
The `levelCaps` rule toggle exists but has no data or enforcement behind it. Boss battles are core progression milestones in any nuzlocke run — defeating them earns badges, unlocks level cap increases, and marks key story moments. This feature adds the data model, import tooling, and UI to support all of this.
## Data Model
### `BossBattle` (new model, per-game)
- `id`, `game_id` (FK)
- `name` (e.g. "Brock", "Cynthia", "Rival 1")
- `boss_type``gym_leader`, `elite_four`, `champion`, `rival`, `evil_team`, `other`
- `badge_name` (nullable, e.g. "Boulder Badge" — only for gym leaders)
- `level_cap` (SmallInteger — highest level on their team, used for level caps rule)
- `order` (SmallInteger — progression order within the game)
- `location` (string — where the fight happens, e.g. "Pewter City Gym")
- `sprite_url` (nullable — trainer sprite)
### `BossPokemon` (new model, pokemon on a boss's team)
- `id`, `boss_battle_id` (FK)
- `pokemon_id` (FK)
- `level` (SmallInteger)
- `order` (SmallInteger — slot order)
### `BossResult` (new model, per-run tracking of boss outcomes)
- `id`, `run_id` (FK), `boss_battle_id` (FK)
- `result``won`, `lost`
- `attempts` (int, default 1)
- `deaths` — list of encounter IDs that died during this fight (optional JSON or relation)
- `completed_at` (datetime)
## Checklist
### Backend
- [x] Migration: Create `boss_battles`, `boss_pokemon`, and `boss_results` tables
- [x] Models: `BossBattle`, `BossPokemon`, `BossResult`
- [x] Schemas: Create/Response schemas for all three models
- [x] API: CRUD endpoints for `boss_battles` (admin — per game)
- [x] API: `GET /games/{game_id}/bosses` — list all bosses for a game with their pokemon teams
- [x] API: `POST /runs/{run_id}/boss-results` — log a boss fight result
- [x] API: `GET /runs/{run_id}/boss-results` — get all boss results for a run
- [x] API: `GET /runs/{run_id}/level-cap` — level cap calculated client-side from bosses list
- [x] Bulk import endpoint or script for boss data — managed via admin UI + export endpoint
### Frontend
- [x] Types: `BossBattle`, `BossPokemon`, `BossResult` interfaces
- [x] API + hooks: Fetch bosses, log results, get level cap
- [x] Boss progression section on RunEncounters page — show next boss, badges earned, level cap
- [x] Badge display: row of earned/unearned badge icons (greyed out until defeated)
- [x] Level cap indicator: show current cap prominently when `levelCaps` rule is on, highlight team members over the cap
- [x] Boss battle log modal: record fight result, mark deaths that occurred during the fight
- [x] Boss detail view: show boss's team with pokemon sprites and levels
### Data
- [x] Seed boss data for at least one game — managed via admin UI

View File

@@ -1,65 +0,0 @@
---
# nuzlocke-tracker-kz5g
title: Genlocke creation wizard
status: completed
type: feature
priority: normal
created_at: 2026-02-09T07:42:10Z
updated_at: 2026-02-09T08:23:53Z
parent: nuzlocke-tracker-25mh
blocking:
- nuzlocke-tracker-x4p6
- nuzlocke-tracker-thbz
---
Multi-step wizard UI for creating a new genlocke. This is the entry point for the entire genlocke feature.
## Steps
### Step 1: Name
- User enters a name for the genlocke (e.g., "My First Genlocke")
### Step 2: Game Selection
- Offer preset templates:
- **True Genlocke** — slots for each region using original releases only
- **Normal Genlocke** — slots for each region using the latest remake/enhanced version as the default pick
- **Custom** — start with an empty list, add games freely
- For preset templates, show one slot per region (Kanto, Johto, Hoenn, Sinnoh, Unova, Kalos, Alola, Galar, Paldea). Each slot shows available games for that region and lets the user pick one.
- The user can add/remove/reorder legs after selecting a template.
- Games are grouped by region (FireRed is a "Kanto" option, not "Gen 3").
### Step 3: Rules
- **Nuzlocke rules** — standard rules configuration (reuse existing `RulesConfiguration` component). Set once, applied to all legs.
- **Genlocke rules** — Keep HoF (default) vs Retire HoF. Radio select.
### Step 4: Confirm & Start
- Summary of the genlocke: name, legs in order, rules.
- "Start Genlocke" button creates the Genlocke entity, all GenlockeLeg records, and auto-creates + starts the first NuzlockeRun.
## Backend
- `POST /api/v1/genlockes` — Create a genlocke with all legs and rules in one request. Should create the Genlocke, GenlockeLeg records, and the first NuzlockeRun.
- Needs the `Genlocke` and `GenlockeLeg` database models + migration.
## Frontend
- New route: `/genlockes/new`
- Multi-step form component with back/next navigation
- Reuse `GameCard`/`GameGrid` components for game selection
- Reuse `RulesConfiguration` for nuzlocke rules step
## Dependencies
- Needs generation/region metadata to power the preset templates (see nuzlocke-tracker-glh8)
## Checklist
- [x] Create `Genlocke` SQLAlchemy model (name, status, genlocke_rules JSONB, nuzlocke_rules JSONB, created_at)
- [x] Create `GenlockeLeg` SQLAlchemy model (genlocke_id FK, run_id FK nullable, leg_order, game_id FK)
- [x] Create Alembic migration for both new tables
- [x] Create Pydantic schemas for genlocke creation request/response
- [x] Implement `POST /api/v1/genlockes` endpoint (creates genlocke, legs, and first run)
- [x] Build the multi-step wizard shell component with back/next navigation and step indicator
- [x] Build Step 1: Name input
- [x] Build Step 2: Preset template selector (True / Normal / Custom) with region-grouped game picker
- [x] Build Step 3: Rules configuration (reuse `RulesConfiguration` + genlocke rules radio)
- [x] Build Step 4: Confirmation summary with "Start Genlocke" action
- [x] Add `/genlockes/new` route to the React Router config
- [x] Add TypeScript types for genlocke API responses
- [x] Wire up the wizard to call the create endpoint and redirect to the genlocke overview on success

View File

@@ -1,16 +0,0 @@
---
# nuzlocke-tracker-kzd9
title: Add option to randomize encounters
status: completed
type: feature
priority: normal
created_at: 2026-02-07T21:08:27Z
updated_at: 2026-02-08T19:07:52Z
---
Add an option to randomly select 1 Pokemon per location/encounter. This is primarily for open-world games (like Legends: Arceus, Legends: Z-A) where Pokemon are visible in the overworld rather than found through random encounters, but could also be used for other games.
## Checklist
- [ ] Add UI toggle or button to randomize encounters when starting or managing a run
- [ ] Implement random selection logic: pick 1 Pokemon per location from the available encounter list
- [ ] Ensure the randomized selection respects existing Nuzlocke rules (dupes clause, etc.)

View File

@@ -1,41 +0,0 @@
---
# nuzlocke-tracker-l7e3
title: Database Schema Design
status: completed
type: task
priority: normal
created_at: 2026-02-04T15:46:54Z
updated_at: 2026-02-05T12:29:19Z
parent: nuzlocke-tracker-f5ob
blocking:
- nuzlocke-tracker-bkhs
- nuzlocke-tracker-k5lm
- nuzlocke-tracker-hy41
---
Design and implement the database schema for persistent storage.
## Decisions
- **Database**: PostgreSQL 16 (already in docker-compose)
- **ORM**: SQLAlchemy 2.0 (async) with asyncpg driver
- **Migrations**: Alembic
- **Async**: Full async — asyncpg + async SQLAlchemy sessions
## Checklist
- [x] Choose database (PostgreSQL)
- [x] Set up database connection and ORM/query builder (SQLAlchemy 2.0 async + asyncpg)
- [x] Design and create tables/collections:
- [x] Games (id, name, slug, generation, region, box_art_url, release_year)
- [x] Routes (id, name, game_id, order)
- [x] Pokemon (id, national_dex, name, types[], sprite_url)
- [x] RouteEncounters (id, route_id, pokemon_id, encounter_method, encounter_rate) — unique(route, pokemon, method)
- [x] NuzlockeRuns (id, game_id, name, status, rules jsonb, started_at, completed_at)
- [x] Encounters (id, run_id, route_id, pokemon_id, nickname, status, catch_level, faint_level, caught_at)
- [x] Set up migrations system (Alembic)
- [ ] Add seed data for initial games/routes/Pokémon
- [x] Create indexes for common queries (FK indexes on routes, route_encounters, nuzlocke_runs, encounters; status index on nuzlocke_runs)
## Notes
- Use foreign keys for referential integrity
- Status fields should be enums
- Use PostgreSQL enums or check constraints for status/type fields

View File

@@ -1,20 +0,0 @@
---
# nuzlocke-tracker-lab1
title: Add version_groups table, share routes & boss battles across version groups
status: completed
type: feature
priority: normal
created_at: 2026-02-08T10:39:00Z
updated_at: 2026-02-08T10:46:43Z
---
Introduce version_groups table and re-parent routes and boss_battles from game_id to version_group_id. Add game_id to route_encounters for per-game encounter data.
## Checklist
- [x] Phase 1: Backend models (VersionGroup, Game, Route, RouteEncounter, BossBattle)
- [x] Phase 2: Alembic migration
- [x] Phase 3: Backend schemas
- [x] Phase 4: Backend API updates
- [x] Phase 5: Seed loader updates
- [x] Phase 6: Frontend type/API/hook updates
- [x] Verification: migration runs, TypeScript compiles

View File

@@ -1,11 +0,0 @@
---
# nuzlocke-tracker-le62
title: Add run management to admin panel
status: completed
type: feature
priority: normal
created_at: 2026-02-07T21:09:13Z
updated_at: 2026-02-08T09:54:13Z
---
Add a runs screen to the admin panel that lists all runs and allows deletion. This provides a way to clean up test runs or remove unwanted runs without needing direct database access.

View File

@@ -1,21 +0,0 @@
---
# nuzlocke-tracker-ljle
title: Route navigation within game detail
status: completed
type: feature
priority: normal
created_at: 2026-02-08T12:33:26Z
updated_at: 2026-02-08T19:00:07Z
parent: nuzlocke-tracker-iu5b
---
Reduce navigation depth when working with route encounters. Currently requires: Games > Game > Routes tab > Click route, and there's no way to jump between sibling routes.
## Desired behavior
- On the route detail page (AdminRouteDetail), add prev/next route navigation buttons to quickly move between routes in the same game
- Consider showing a sidebar or dropdown with all routes for quick jumping
- Breadcrumbs should be clickable to go back to the game detail
## Notes
- The route order is already available — sort by order to determine prev/next
- This is particularly useful when populating encounter data for a new game, going route by route

View File

@@ -1,11 +0,0 @@
---
# nuzlocke-tracker-lqf2
title: Fix hooks order violation in RunEncounters
status: completed
type: bug
priority: critical
created_at: 2026-02-09T09:22:14Z
updated_at: 2026-02-09T09:22:58Z
---
The hofTeam useMemo was placed after early returns, causing a 'Rendered more hooks than during the previous render' error and blank page.

View File

@@ -1,43 +0,0 @@
---
# nuzlocke-tracker-lsc2
title: Genlocke lineage tracking
status: todo
type: feature
priority: normal
created_at: 2026-02-09T07:42:41Z
updated_at: 2026-02-09T07:46:15Z
parent: nuzlocke-tracker-25mh
---
Track and display a Pokemon's journey across multiple genlocke legs. When a Pokemon is transferred between legs, its lineage (history across legs) should be visible.
## Concept
A "lineage" is the chain of transfers for a Pokemon across legs. For example:
- Leg 1: Caught Charmander on Route 1 → evolved to Charizard → entered HoF → transferred
- Leg 2: Received Charmander egg → evolved to Charmeleon → died on Route 7
The lineage view connects these into one story, showing the Pokemon's journey through the entire genlocke.
## Display
- On the genlocke overview page, show a "Lineage" section or tab
- Each lineage entry shows:
- The Pokemon's name/nickname
- Which legs it appeared in
- Key events per leg (caught, evolved, entered HoF, transferred, died)
- Final status (still alive, died in leg X, retired via Gauntlet rule)
- Visual: a horizontal timeline per Pokemon showing its presence across legs
## Data
- Lineage is derived from `GenlockeTransfer` records — follow the chain of from_encounter → to_encounter across legs
- No additional database tables needed; this is a read-only view computed from existing transfer + encounter data
## Dependencies
- Requires Transfer UI to be implemented first (needs GenlockeTransfer records to exist)
## Checklist
- [ ] Implement `GET /api/v1/genlockes/{id}/lineages` — build lineage chains by walking GenlockeTransfer records from first leg to last, grouping encounters that share a transfer chain
- [ ] Each lineage entry should include: origin encounter, all subsequent transferred encounters, per-leg status (alive/fainted/transferred), current status (alive/dead/retired)
- [ ] Build the lineage display component: one row per lineage with a horizontal timeline across legs
- [ ] Show Pokemon sprite, nickname, and key events (caught, evolved, HoF, transferred, died) per leg
- [ ] Integrate the lineage view as a tab or section on the genlocke overview page
- [ ] Handle edge cases: Pokemon that were never transferred (single-leg only), broken chains if a leg was skipped

View File

@@ -1,41 +0,0 @@
---
# nuzlocke-tracker-lsdy
title: Genlocke cumulative graveyard
status: completed
type: feature
priority: normal
created_at: 2026-02-09T07:42:46Z
updated_at: 2026-02-09T10:00:43Z
parent: nuzlocke-tracker-25mh
---
Display all deaths across all legs of a genlocke in a single unified graveyard view.
## Display
- Accessible from the genlocke overview page
- Shows all fainted Pokemon from every leg in one list
- Each entry shows:
- Pokemon sprite, nickname, species
- Which leg/game it died in
- Death cause (if recorded)
- Level at death
- Whether it was a transferred Pokemon (part of a lineage) or caught fresh in that leg
- Sortable/filterable by leg, species, level, etc.
- Summary stats: total deaths, deaths per leg, deadliest leg
## Backend
- `GET /api/v1/genlockes/{id}/graveyard` — Return all fainted encounters across all legs of the genlocke
- Aggregates encounters with status "fainted" from all runs belonging to the genlocke's legs
## Frontend
- Could be a tab on the genlocke overview page or a separate sub-page (`/genlockes/:id/graveyard`)
- Reuse existing graveyard/encounter display components where possible
## Checklist
- [x] Implement `GET /api/v1/genlockes/{id}/graveyard` — query all encounters with status "fainted" across all runs linked to the genlocke's legs, include leg/game context per entry
- [x] Add summary stats to the response: total deaths, deaths per leg, deadliest leg
- [ ] Indicate whether each dead Pokemon was a transferred Pokemon or caught fresh (join with GenlockeTransfer) — deferred until GenlockeTransfer model exists (nuzlocke-tracker-lsc2)
- [x] Build the cumulative graveyard component: list of dead Pokemon with sprite, nickname, species, leg/game, death cause, level
- [x] Add sorting (by leg, level, species) and filtering (by leg/game)
- [x] Integrate as a tab on the genlocke overview page or as a sub-route
- [x] Reuse existing graveyard display components where applicable

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-m8ki
title: Split e2e tests into manual workflow
status: completed
type: task
priority: normal
created_at: 2026-02-21T16:53:37Z
updated_at: 2026-02-21T16:54:04Z
---
Remove e2e-tests job from ci.yml and create a new e2e.yml workflow with workflow_dispatch trigger only.

View File

@@ -1,24 +0,0 @@
---
# nuzlocke-tracker-mg46
title: Use PokemonSelector autocomplete for route encounters
status: completed
type: feature
priority: normal
created_at: 2026-02-08T12:33:11Z
updated_at: 2026-02-08T19:04:07Z
parent: nuzlocke-tracker-iu5b
---
Replace the basic <select> dropdown in the route encounter form (AdminRouteDetail) with the PokemonSelector autocomplete component already used in the boss team editor.
## Current behavior
- Route encounter form has a plain HTML select dropdown listing all pokemon
- Difficult to find a specific pokemon in a list of 1000+
## Desired behavior
- Use the existing PokemonSelector component (autocomplete with search, sprite preview, dex number)
- Same UX as the boss team editor pokemon selection
## Files
- frontend/src/pages/admin/AdminRouteDetail.tsx — update the form
- frontend/src/components/admin/RouteEncounterFormModal.tsx — replace select with PokemonSelector

View File

@@ -0,0 +1,32 @@
---
# nuzlocke-tracker-mz16
title: Session Journal / Blog Posts
status: draft
type: epic
created_at: 2026-02-19T07:43:05Z
updated_at: 2026-02-19T07:43:05Z
---
Let users tell the story of their nuzlocke run through session journal entries (blog posts).
Nuzlockes are inherently story-driven — encounters you first think are weak become the star of the show, a needed sacrifice lets the run survive, one crit in a boss battle means defeat. Users should be able to capture those moments.
## Concept
For each play session, users can write a short post to document what happened. Posts can:
- Include rich text / markdown content
- Embed screenshots and images
- Automatically link to their current team (or a subset of it)
- Reference deaths, new encounters, and other run events
- Be tied to a specific run
The journal becomes a chronological narrative of the nuzlocke run, with game data woven in automatically.
## Open Questions
- [ ] What editor experience? (Markdown, rich text, block editor?)
- [ ] How are images stored? (Local uploads, external links, cloud storage?)
- [ ] What run events can be linked/embedded? (Team snapshots, deaths, catches, badge progress?)
- [ ] Should posts be publishable/shareable, or private by default?
- [ ] How does the journal UI look? Timeline view? Blog-style list?

View File

@@ -3,8 +3,9 @@
title: Add detailed boss battle information title: Add detailed boss battle information
status: todo status: todo
type: feature type: feature
priority: low
created_at: 2026-02-08T11:21:22Z created_at: 2026-02-08T11:21:22Z
updated_at: 2026-02-08T11:21:22Z updated_at: 2026-02-10T12:05:43Z
--- ---
Enhance boss battles with more detailed information for each boss pokemon and the player's team. Enhance boss battles with more detailed information for each boss pokemon and the player's team.

View File

@@ -1,11 +0,0 @@
---
# nuzlocke-tracker-o18w
title: Add region field to evolutions
status: completed
type: feature
priority: normal
created_at: 2026-02-07T18:55:07Z
updated_at: 2026-02-07T18:57:25Z
---
Add nullable region field to evolutions for regional form evolution filtering (e.g., Pikachu → Alolan Raichu only in Alola). Full-stack: DB migration, model, schemas, API, seeder, Go tool, frontend types/API/hook/components.

View File

@@ -1,21 +0,0 @@
---
# nuzlocke-tracker-o7il
title: Improve run creation workflow UX
status: completed
type: feature
priority: normal
created_at: 2026-02-07T20:26:26Z
updated_at: 2026-02-07T20:27:46Z
---
Box art from local files, capitalize regions everywhere, add region filter + run-status filters to GameGrid, sticky top bar with selected game summary + Next button in NewRun step 1.
## Checklist
- [ ] GameCard: box art from /boxart/{slug}.png with color fallback, capitalize region
- [ ] GameGrid: add runs prop, region filter pills, run-status checkboxes, capitalize regions
- [ ] NewRun: add useRuns(), pass runs to GameGrid, sticky top bar with game summary + Next button
- [ ] RunEncounters: capitalize region display
- [ ] RunDashboard: capitalize region display
- [ ] AdminGameDetail: capitalize region display
- [ ] NewRun step 3 summary: capitalize region display
- [ ] Verify: npx tsc --noEmit clean compile

View File

@@ -1,29 +0,0 @@
---
# nuzlocke-tracker-ok1t
title: Bulk import for evolutions, routes, and bosses
status: completed
type: feature
priority: normal
created_at: 2026-02-08T12:33:39Z
updated_at: 2026-02-08T19:13:27Z
parent: nuzlocke-tracker-iu5b
---
Extend the bulk import capability (currently Pokemon-only) to cover evolutions, routes, and boss battles.
## Current state
- Pokemon has a bulk import modal that accepts JSON and reports created/updated/errors
- Evolutions, routes, and bosses can only be created one at a time
- All entities can be exported to JSON
## Desired behavior
- Add bulk import modals to:
- AdminEvolutions — import evolutions JSON
- AdminGameDetail routes tab — import routes JSON (with children/encounters)
- AdminGameDetail bosses tab — import bosses JSON (with pokemon teams)
- Import format should match the export format for round-trip compatibility
- Show progress/results summary (created, updated, errors) like the Pokemon import
## Backend
- May need new bulk-import endpoints for evolutions, routes, and bosses
- Or extend existing seed loader functions to be callable via API

View File

@@ -1,58 +0,0 @@
---
# nuzlocke-tracker-p74f
title: Genlocke transfer UI
status: completed
type: feature
priority: normal
created_at: 2026-02-09T07:42:33Z
updated_at: 2026-02-09T10:20:53Z
parent: nuzlocke-tracker-25mh
blocking:
- nuzlocke-tracker-lsc2
---
After completing a genlocke leg, the user selects which surviving Pokemon to carry forward to the next leg. Transferred Pokemon appear as egg encounters in the next run.
## Flow
### Transfer Step (between legs)
1. User completes a leg (beats the Champion / enters Hall of Fame)
2. A transfer screen is shown, displaying all surviving Pokemon from the completed leg
3. User selects which Pokemon to transfer (typically up to 6, the HoF team)
4. Selected Pokemon are "bred" — they'll appear as level 1 eggs/starters in the next leg
5. The transfer is recorded and the next leg's run is started
### Transfer Records
- Each transfer links a source encounter (from the completed leg) to a new egg encounter (in the next leg)
- The new encounter in the next leg should:
- Be the base form of the evolutionary line (e.g., Charizard → Charmander egg)
- Have a special status/flag indicating it's a genlocke transfer (not a wild encounter)
- Optionally keep the same nickname
- Not count against any route's first-encounter rule
### UI Components
- Transfer selection screen: grid of surviving Pokemon with checkboxes
- Show each Pokemon's sprite, nickname, species, and level
- "Transfer Selected" button to confirm
- Option to skip transferring (transfer none) for added challenge
## Backend
- `POST /api/v1/genlockes/{id}/legs/{leg_id}/transfer` — Accept list of encounter IDs to transfer
- Creates `GenlockeTransfer` records linking source encounters to new egg encounters
- Auto-creates the egg encounters in the next leg's run
## Data Model
- `GenlockeTransfer` table: from_leg_id, to_leg_id, from_encounter_id, to_encounter_id
- Egg encounters need a way to be distinguished from regular encounters (possibly a flag or encounter method)
## Checklist
- [ ] Create `GenlockeTransfer` SQLAlchemy model (from_leg_id, to_leg_id, from_encounter_id, to_encounter_id)
- [ ] Create Alembic migration for the GenlockeTransfer table
- [ ] Add logic to resolve a Pokemon's base form from its evolutionary chain (e.g., Charizard → Charmander)
- [ ] Implement `GET /api/v1/genlockes/{id}/legs/{leg_order}/survivors` — return surviving (non-fainted) encounters from a completed leg
- [ ] Implement `POST /api/v1/genlockes/{id}/legs/{leg_order}/transfer` — accept encounter IDs, create GenlockeTransfer records, create egg encounters in the next leg's run
- [ ] Build the transfer selection screen: grid of surviving Pokemon with checkboxes, sprites, nicknames, and levels
- [ ] Add a "Transfer Selected" confirmation action and a "Skip" option
- [ ] Wire up the transfer screen to appear after leg completion (integrate with leg progression flow)
- [ ] Ensure transferred egg encounters don't count against route first-encounter rules
- [ ] Add TypeScript types for transfer API request/response

View File

@@ -1,14 +0,0 @@
---
# nuzlocke-tracker-p940
title: gitignore-setup
status: completed
type: task
priority: high
created_at: 2026-02-04T15:58:22Z
updated_at: 2026-02-04T16:01:15Z
parent: nuzlocke-tracker-f5ob
---
Create an overarching gitignore, taking into account that there are gitignore files in the individual component folders.
- [x] Git should ignore anything that could leak credentials
- [x] Git should ignore anything specific to my local environment

View File

@@ -1,11 +0,0 @@
---
# nuzlocke-tracker-pbzd
title: Add export to all admin panel screens
status: completed
type: feature
priority: normal
created_at: 2026-02-07T21:08:27Z
updated_at: 2026-02-08T09:49:09Z
---
Add an export button to all screens in the admin panel so that data edited in the UI can be exported and added back to the seed data files. This allows editing game data, routes, and encounters through the admin UI and then persisting those changes to the JSON seed files.

View File

@@ -1,17 +0,0 @@
---
# nuzlocke-tracker-pm9f
title: Genlocke edge cases
status: draft
type: task
created_at: 2026-02-09T08:48:46Z
updated_at: 2026-02-09T08:48:46Z
parent: nuzlocke-tracker-25mh
---
Collect and evaluate edge cases for genlocke tracking. Review periodically to decide if any need dedicated handling.
## Edge Cases
- [ ] Prevent run deletion if the run is linked to a genlocke leg. The `DELETE /runs/{id}` endpoint should check for a `GenlockeLeg` with matching `run_id` and return 400 if found, telling the user to remove the run from the genlocke first.
- [ ] What happens if a user tries to advance a leg twice? (Currently guarded by "next leg already has a run" check)
- [ ] What if the user edits a completed run back to active after the genlocke has already been marked completed/failed?

View File

@@ -1,11 +0,0 @@
---
# nuzlocke-tracker-qars
title: 'Boss battle card: collapsible team + hardcore mode cleanup'
status: completed
type: feature
priority: normal
created_at: 2026-02-08T11:01:17Z
updated_at: 2026-02-08T11:02:45Z
---
Make boss battle cards collapsible (team hidden by default), larger sprites with Lvl prefix, and hide attempts/lost button in hardcore mode

View File

@@ -1,147 +0,0 @@
---
# nuzlocke-tracker-qeim
title: UX improvements pass
status: completed
type: task
priority: normal
created_at: 2026-02-05T14:27:17Z
updated_at: 2026-02-07T13:05:14Z
---
The current encounter tracking and run dashboard UX is clunky. Do a holistic UX review and propose improvements.
Areas to evaluate:
- Encounter logging flow (too many clicks? modal vs inline?)
- Encounter logging should be the default view for runs
- Team overview is not really needed
- Logging encounters should show the type of encounter (grass, surfing, fishing, ...)
- Route list readability and navigation (long lists)
- Route grouping UX polish (auto-expand unvisited groups, remember expand state, visual hierarchy for parent vs child)
- Run dashboard information density
- Mobile usability
- Navigation between run dashboard and encounters
- Empty states and onboarding flow
- Visual feedback for actions (success/error toasts, optimistic updates)
- It is unintuitive to not be able to deselect a game on the new run page
Produce a concrete plan with specific UI/UX changes to implement.
---
## Concrete UX Improvement Plan
### 1. Make encounters the default run view — merge dashboard into encounters
**Problem:** The run dashboard (`/runs/:runId`) and encounter log (`/runs/:runId/encounters`) are separate pages. Users must click "Log Encounter" to get to the actual tracker. The dashboard shows team/graveyard but that's secondary to the encounter flow.
**Change:** Merge the dashboard into the encounters page as a unified view:
- `/runs/:runId` shows the encounter list directly (current RunEncounters content)
- Move stats + team/graveyard into a collapsible sidebar or header summary on the same page
- Specifically: put the 4 stat cards in a compact row at the top, above the route list
- Team and graveyard move to a slide-out panel or collapsible section below the stats
- Remove the separate RunDashboard page; redirect `/runs/:runId` to the merged view
- Keep "End Run" as a button in the header area
**Files:** `RunDashboard.tsx`, `RunEncounters.tsx`, `App.tsx` (routing)
### 2. Show encounter method in the route list (not just the modal)
**Problem:** Users can't see what encounter methods are available on a route until they click it. For Nuzlocke tracking, knowing whether a route has grass, surf, fishing, etc. is important for planning.
**Change:** Show small method badges on each route row in the encounters list:
- Fetch route encounter data summary (distinct methods) and show as tiny icons or text badges
- e.g. "Route 1" shows 🌿 walk | "Pallet Town" shows 🏄 surf 🎣 fishing ⭐ starter
- Use the same EncounterMethodBadge component from the modal, but also add badges for wild methods (walk, surf, old-rod, good-rod, super-rod, rock-smash, headbutt)
- Show badges in a row below the route name
**Files:** `RunEncounters.tsx`, `EncounterModal.tsx` (extract shared badge component)
### 2b. Group Pokemon by encounter method in the EncounterModal
**Problem:** The Pokemon selection grid in the EncounterModal shows all Pokemon in a flat list. On routes with many encounter methods (walk, surf, old-rod, good-rod, super-rod, etc.) it's a jumbled mess — the user can't tell which Pokemon come from grass vs. fishing.
**Change:** Group the Pokemon grid by encounter method with labeled sections and spacers:
- Group `routePokemon` by `encounterMethod` before rendering
- Render each group with a header label (e.g. "Grass", "Surfing", "Old Rod", "Good Rod", "Super Rod") and the Pokemon grid underneath
- Add a visual spacer/divider between groups (e.g. a thin horizontal line or margin gap)
- Method display order: starter, gift, fossil, trade, walk, headbutt, surf, rock-smash, old-rod, good-rod, super-rod
- Use friendly labels: walk → "Grass", surf → "Surfing", old-rod → "Old Rod", etc.
- If a route only has one method, skip the grouping header (no visual noise)
- Time-of-day differences: these are already aggregated in our encounter data (same "walk" method, rates summed). If time-based filtering is added later, use tabs above the grid to switch day/morning/night rather than creating separate groups.
**Files:** `EncounterModal.tsx`
### 3. Route grouping polish
**Problem:** All route groups start collapsed. Users have to manually expand each one. No visual distinction between visited and unvisited groups.
**Changes:**
- Auto-expand the first unvisited group on page load (guides the player to the next location)
- Persist expand/collapse state in localStorage keyed by runId
- Add a subtle left border color to groups based on status (green = caught, red = fainted, etc.)
- Show route count badges: "3/5 areas" for groups
**Files:** `RunEncounters.tsx`
### 4. Allow game deselection in NewRun wizard
**Problem:** Once you select a game, you can't deselect it — clicking the same game again does nothing. This is unintuitive.
**Change:** Toggle selection — clicking an already-selected game deselects it:
```tsx
const handleGameSelect = (game: Game) => {
if (selectedGame?.id === game.id) {
setSelectedGame(null)
return
}
// ... existing logic
}
```
**Files:** `NewRun.tsx`
### 5. Improve Home page with recent runs + clear CTA
**Problem:** Home page is just a title and tagline. No way to quickly resume a run or start one.
**Change:**
- Show "Continue Run" card for the most recent active run (if any)
- Show "Start New Run" prominent CTA button
- Show recent runs list (last 3-5) with quick links
- If no runs exist, show onboarding message
**Files:** `Home.tsx`, `useRuns.ts`
### 6. Mobile nav improvements
**Problem:** Nav links crowd on small screens. No hamburger menu.
**Change:**
- Add hamburger menu on small screens (< sm breakpoint)
- Collapse nav links into dropdown
- Ensure all touch targets are minimum 44px
**Files:** `Layout.tsx`
### 7. Better empty states
**Problem:** Several pages have minimal empty states ("No pokemon caught yet", etc.) without guiding the user.
**Changes:**
- RunEncounters with no encounters: "Click a route to log your first encounter"
- RunDashboard/merged view with no alive pokemon: "Catch your first Pokemon to build your team!"
- RunList with no runs: Already has CTA, but add illustration or more welcoming text
**Files:** Various page components
## Checklist
- [x] Merge dashboard into encounters page (unified run view)
- [x] Show encounter method badges on route rows
- [x] Group Pokemon by encounter method in EncounterModal with headers and spacers
- [x] Auto-expand first unvisited route group
- [x] Persist route group expand/collapse state in localStorage
- [x] Allow game deselection in NewRun wizard
- [x] Improve Home page with recent runs + CTA
- [x] Add mobile hamburger nav menu
- [x] Improve empty states with helpful guidance text

View File

@@ -1,52 +0,0 @@
---
# nuzlocke-tracker-rkyc
title: Dupes Clause & Shiny Clause enforcement
status: completed
type: feature
priority: low
created_at: 2026-02-05T12:25:19Z
updated_at: 2026-02-07T20:11:59Z
---
Implement active enforcement for Dupes Clause and Shiny Clause in the encounter flow.
## Dupes Clause
When enabled, Pokemon from an already-caught evolution chain are **greyed out** in the encounter modal. This prevents catching duplicates within the same evolutionary family.
- If you catch a Rattata, both Rattata and Raticate become unavailable
- If you catch an Eevee (or any Eeveelution), the entire Eevee family is blocked
- "Already caught" includes both alive and dead Pokemon from the current run
- Greyed-out Pokemon should still be visible in the encounter list but clearly marked as ineligible (reduced opacity, strikethrough, or similar)
- This requires knowing the full evolution chain for each Pokemon — use the existing evolution data to build family groups
### Implementation notes
- Build a lookup from pokemon_id → set of all pokemon in the same evolution family (walk the evolution tree in both directions)
- On the encounter modal, cross-reference available route Pokemon against caught families
- Grey out / mark as "duped" any Pokemon whose family already has a catch in the current run
- Backend validation is optional (frontend-only is fine since this is a self-enforced rule)
## Shiny Clause
When enabled, shiny Pokemon may be caught regardless of the first-encounter-only rule. Rather than allowing multiple regular encounters per route, add a **dedicated Shiny Box** container.
- Add a "Shiny Box" section on the run page (separate from the team/graveyard)
- Shiny catches are not tied to a route — they're bonus catches stored in the shiny container
- Shiny Box entries need: pokemon, nickname, catch level, and the route where found
- Shinies in the box do NOT count against the one-encounter-per-route rule
- The shiny box should be visually distinct (sparkle icon, gold/yellow accent)
### Implementation notes
- Add an `is_shiny` boolean field to the Encounter model (or a separate shiny encounters table)
- Shiny encounters bypass the route-lock check on the backend
- Frontend: add a "Log Shiny" button or a shiny toggle in the encounter modal
- Display shiny box as a collapsible section similar to the graveyard
## Checklist
- [ ] Build evolution family lookup (pokemon_id → family set)
- [ ] Grey out duped Pokemon in encounter modal when dupes clause is active
- [ ] Add `is_shiny` field to encounter model + migration
- [ ] Backend: allow shiny encounters to bypass route lock
- [ ] Frontend: shiny toggle/button in encounter flow
- [ ] Frontend: shiny box section on run page
- [ ] Test with evolution chains (Eevee family, branching evolutions)

View File

@@ -1,11 +0,0 @@
---
# nuzlocke-tracker-rxrt
title: Support gift/static encounter marking
status: completed
type: feature
priority: normal
created_at: 2026-02-05T14:21:47Z
updated_at: 2026-02-07T12:53:43Z
---
Add ability to distinguish gift/static encounters in the encounter tracking interface. Currently all encounters are treated the same regardless of encounter method. The backend RouteEncounter model already has an encounterMethod field from PokeAPI (gift, walk, etc.) — surface this in the UI and potentially allow logging encounters on routes that don't have PokeAPI encounter data (e.g. starter pokemon, in-game trades).

View File

@@ -1,20 +0,0 @@
---
# nuzlocke-tracker-sgp4
title: Fetch and store badge images locally
status: completed
type: task
priority: normal
created_at: 2026-02-08T20:57:15Z
updated_at: 2026-02-08T21:13:34Z
---
Badge images are currently loaded via remote URLs, which can lead to missing images if the remote source is unavailable. Download all badge images and store them locally as part of the seed script's export function.
The seed script already fetches badge URLs when exporting boss battle data — extend this to also download the actual badge image files and save them to a local assets directory. Update badge image references to point to the local copies.
## Checklist
- [ ] Extend the seed script export function to download badge images from the URLs found in boss battle data
- [ ] Store downloaded badge images in a local assets directory (e.g. `frontend/public/badges/` or similar)
- [ ] Update badge image URL references to use the local paths instead of remote URLs
- [ ] Handle edge cases (missing URLs, download failures, duplicate filenames)

View File

@@ -1,31 +0,0 @@
---
# nuzlocke-tracker-sm1b
title: Game Data Models & Types
status: completed
type: task
priority: normal
created_at: 2026-02-04T15:44:08Z
updated_at: 2026-02-05T12:33:38Z
parent: nuzlocke-tracker-f5ob
blocking:
- nuzlocke-tracker-k5lm
- nuzlocke-tracker-0q8f
- nuzlocke-tracker-hm6t
- nuzlocke-tracker-8fcj
---
Define the core data structures and TypeScript types for the application.
## Checklist
- [x] Define Game type (id, name, slug, generation, region, boxArtUrl, releaseYear)
- [x] Define Route/Area type (id, name, gameId, order)
- [x] Define Pokemon type (id, nationalDex, name, types, spriteUrl)
- [x] Define Encounter type (id, runId, routeId, pokemonId, nickname, status, catchLevel, faintLevel, caughtAt)
- [x] Define NuzlockeRun type (id, gameId, name, status, rules, startedAt, completedAt)
- [x] Define RuleSettings type (already existed in rules.ts)
- [x] Define RouteEncounter type (id, routeId, pokemonId, encounterMethod, encounterRate)
- [x] Define EncounterStatus and RunStatus discriminated union types
## Notes
- Keep types flexible for future expansion
- Consider using discriminated unions for status types

View File

@@ -1,56 +0,0 @@
---
# nuzlocke-tracker-thbz
title: Genlocke leg progression
status: completed
type: feature
priority: normal
created_at: 2026-02-09T07:42:33Z
updated_at: 2026-02-09T08:47:35Z
parent: nuzlocke-tracker-25mh
blocking:
- nuzlocke-tracker-p74f
- nuzlocke-tracker-8w9s
---
Handle the sequential progression of legs within a genlocke. When one leg is completed, the next leg should be started (with a transfer step in between).
## Behavior
### Leg Completion
- When a nuzlocke run that belongs to a genlocke is marked as **completed**:
1. The leg is marked as completed
2. If there is a next leg, trigger the **transfer step** (see Transfer UI feature)
3. After the transfer step, auto-create and start the next leg's NuzlockeRun
4. If this was the final leg, mark the entire genlocke as **completed**
### Leg Failure
- When a nuzlocke run that belongs to a genlocke is marked as **failed** (total party wipe):
- The genlocke itself is marked as **failed**
- No further legs are started
- The overview page reflects the failure
### Run Status Integration
- The existing run completion/failure flow needs to check if the run belongs to a genlocke
- If it does, trigger the genlocke-specific progression logic
- The run page should show context about which genlocke/leg this run belongs to (e.g., "Leg 3 of My Genlocke")
## Backend
- Extend run status update endpoint to trigger genlocke progression when applicable
- `POST /api/v1/genlockes/{id}/legs/{leg_id}/advance` — or handle automatically when run status changes
- Need to track genlocke status: active (a leg is in progress), completed (all legs done), failed (a leg was failed)
## Frontend
- When completing a run that belongs to a genlocke, show a genlocke-aware completion modal instead of the standard one
- Show "Leg X of Y" context on the run page header when the run is part of a genlocke
- After completion, redirect to the transfer step (or to the genlocke overview if it was the final leg)
## Checklist
- [x] Add backend logic to detect when a completed/failed run belongs to a genlocke (query GenlockeLeg by run_id)
- [x] On run completion: update GenlockeLeg status, determine if there's a next leg
- [x] On run failure: mark the genlocke as failed, prevent further leg creation
- [x] On final leg completion: mark the genlocke as completed
- [x] Implement `POST /api/v1/genlockes/{id}/legs/{leg_order}/advance` endpoint to create the next leg's run
- [x] Add genlocke context to the run detail API response (genlocke name, leg number, total legs) when the run belongs to a genlocke
- [x] Update the frontend run page header to show "Leg X of Y — {Genlocke Name}" when applicable
- [x] Update the run completion flow on the frontend to detect genlocke membership and redirect to transfer step instead of the standard completion screen
- [ ] Handle edge case: what happens if a genlocke run is manually deleted?

View File

@@ -1,11 +0,0 @@
---
# nuzlocke-tracker-tqoq
title: Rewrite fetch_pokeapi.py to use local submodule data
status: completed
type: task
priority: normal
created_at: 2026-02-05T18:14:38Z
updated_at: 2026-02-05T18:16:34Z
---
Replace all pokebase API calls with local JSON file reads from the PokeAPI/api-data git submodule. Remove pokebase dependency from pyproject.toml.

View File

@@ -1,21 +0,0 @@
---
# nuzlocke-tracker-tyvc
title: Add end-of-run condition rule
status: todo
type: feature
created_at: 2026-02-09T08:35:39Z
updated_at: 2026-02-09T08:35:39Z
---
Add a new nuzlocke rule: **End of Run Condition**. This is a toggle/switch that lets the player decide when a run is considered complete:
- **Main Story** (default) — The run ends after beating the Champion / completing the main storyline
- **Post Game** — The run continues into the post-game content (Battle Frontier, rematches, etc.)
This affects when the player is expected to mark a run as "completed" and could influence level caps and boss tracking in the future.
## Checklist
- [ ] Add `postGameCompletion` (boolean, default false) to the `NuzlockeRules` TypeScript interface and `DEFAULT_RULES`
- [ ] Add a rule definition to `RULE_DEFINITIONS` in `frontend/src/types/rules.ts`
- [ ] Verify the rule appears in the `RulesConfiguration` component (should work automatically via RULE_DEFINITIONS)
- [ ] Verify the rule is stored correctly via the existing run/genlocke creation flows (JSONB, no backend schema change needed)

View File

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

View File

@@ -1,30 +0,0 @@
---
# nuzlocke-tracker-uw2j
title: Game Selection Screen
status: completed
type: task
priority: normal
created_at: 2026-02-04T15:44:16Z
updated_at: 2026-02-05T14:02:43Z
parent: nuzlocke-tracker-f5ob
---
Build the initial screen where users select which Pokémon game they want to track.
## Checklist
- [x] Create game selection component
- [x] Display games grouped by generation
- [x] Show game artwork/logo for each option
- [x] Add search/filter functionality for games
- [x] Navigate to rule settings after selection
- [x] Allow returning to change game selection
## Implementation Notes
- Game selection is step 1 of a 3-step new run wizard at `/runs/new`
- `GameCard` component: slug-based gradient backgrounds as fallback for missing box art
- `GameGrid` component: responsive grid with generation filter tabs
- `StepIndicator` component: clickable progress bar for navigating wizard steps
- `NewRun` page: wizard flow — select game → configure rules → name & create run
- Reuses existing `RulesConfiguration` component for step 2
- `GameSelect` page at `/games` shows a browseable game grid with "Start New Run" CTA
- "New Run" link added to nav bar

View File

@@ -1,11 +0,0 @@
---
# nuzlocke-tracker-v04g
title: Hide Pinwheel Clause when game has no pinwheel zones
status: completed
type: bug
priority: normal
created_at: 2026-02-07T21:08:27Z
updated_at: 2026-02-08T09:37:48Z
---
The Pinwheel Clause rule option is currently shown for all games, even those that have no locations using pinwheel zones (i.e. no routes with pinwheel_zone IDs). It should only be displayed when the selected game actually has routes with pinwheel zone data.

View File

@@ -1,42 +0,0 @@
---
# nuzlocke-tracker-w7o6
title: Improve Run Creation Workflow
status: completed
type: feature
priority: normal
created_at: 2026-02-07T20:20:51Z
updated_at: 2026-02-08T09:54:24Z
---
Improve the run creation flow with better game filtering, box art display, and UX fixes.
## Context
The current run creation workflow has several pain points:
- The game selection grid has no filters, making it hard to find games in a large list
- Box art images exist in the data model but aren't being used — only the game color is shown
- The "Next" button sits below the game grid, so users with many games may never scroll far enough to see it exists
## Changes
### Game Selection Filters
- [ ] Add region filter (dropdown or pill tabs) to narrow games by region
- [ ] Add filter for games with no active run (hide games that already have an in-progress run)
- [ ] Add filter for games not yet completed (no completed run)
- [ ] Consider additional filter criteria as needs emerge (generation, etc.)
### Box Art Display
- [ ] Use `boxArtUrl` as the primary visual for game cards in the selection grid
- [ ] Fall back to the `color` field as background when no box art is available
- [ ] Ensure box art looks good at card size (proper aspect ratio, object-fit)
### UX Fixes
- [ ] Move the "Next" / continue button to the top of the game selection step (sticky or above the grid)
- [ ] Make it clear a game is selected before the user has to scroll
- [ ] Consider showing the selected game summary near the top button
## Files likely affected
- `frontend/src/pages/NewRun.tsx` (or wherever the run creation wizard lives)
- `frontend/src/components/GameCard.tsx`
- `frontend/src/components/GameGrid.tsx`
- Possibly new filter component(s)

View File

@@ -1,63 +0,0 @@
---
# nuzlocke-tracker-x4p6
title: Genlocke overview page
status: completed
type: feature
priority: normal
created_at: 2026-02-09T07:42:19Z
updated_at: 2026-02-09T09:40:02Z
parent: nuzlocke-tracker-25mh
blocking:
- nuzlocke-tracker-lsc2
- nuzlocke-tracker-lsdy
---
A dedicated dashboard page for a genlocke, showing progress, configuration, and cumulative stats across all legs.
## Page Layout
### Progress Section
- Visual timeline or step indicator showing all legs in order
- Each leg shows: game icon/color, game name, leg status (upcoming / active / completed / failed)
- The active leg is highlighted and links to its run page
- Completed legs show key stats (encounters, deaths, HoF team)
### Configuration Section
- Display the selected genlocke rules (Keep HoF / Retire HoF)
- Display the nuzlocke rules applied to all legs
- List of all games in leg order
### Cumulative Stats Section
- Total encounters across all legs
- Total deaths across all legs
- Total unique Pokemon caught
- Current surviving team count
- Legs completed / total legs
### Quick Actions
- Link to active leg's run page
- Link to genlocke-wide graveyard (if implemented)
- Link to lineage view (if implemented)
## Backend
- `GET /api/v1/genlockes` — List all genlockes (for a genlocke list page)
- `GET /api/v1/genlockes/{id}` — Get genlocke with legs, runs, and aggregated stats
## Frontend
- New route: `/genlockes/:genlockeId`
- Also need a genlocke list page at `/genlockes` (or integrate into the existing runs list)
- Consider adding a "Genlockes" nav item alongside "Runs"
## Checklist
- [ ] Implement `GET /api/v1/genlockes` endpoint (list all genlockes with basic info and leg count)
- [ ] Implement `GET /api/v1/genlockes/{id}` endpoint (full genlocke with legs, runs, and aggregated stats)
- [ ] Add TypeScript types for genlocke detail/list API responses
- [ ] Build the genlocke list page at `/genlockes` showing all genlockes with status and progress
- [ ] Build the genlocke detail page at `/genlockes/:genlockeId`
- [ ] Build the progress section: visual leg timeline with game colors, statuses, and links to runs
- [ ] Build the configuration section: display genlocke rules and nuzlocke rules
- [ ] Build the cumulative stats section: aggregate encounters, deaths, and completions across legs
- [ ] Add quick action links (active leg, graveyard, lineage — placeholder links for unimplemented features)
- [ ] Build "Retired Families" section: when retireHoF is enabled, display cumulative retired Pokemon with sprites grouped by leg (data available via `GET /api/v1/genlockes/{id}/retired-families`)
- [ ] Add "Genlockes" navigation item to the app nav bar
- [ ] Add `/genlockes` and `/genlockes/:genlockeId` routes to the React Router config

View File

@@ -1,31 +0,0 @@
---
# nuzlocke-tracker-x8ol
title: Conditional boss battle teams
status: completed
type: feature
priority: normal
created_at: 2026-02-08T13:23:00Z
updated_at: 2026-02-08T20:21:50Z
---
Some boss battles have teams that vary based on conditions in the player's run. The most common case is starter choice (e.g., Blue's team in Gen 1 depends on whether you picked Bulbasaur, Charmander, or Squirtle), but other conditions exist too — in Pokemon Yellow, the rival's team changes based on the outcomes of two early-game fights, not the starter. This feature adds support for defining multiple team variants per boss battle, each associated with a named condition.
## Context
Currently each boss battle has a single fixed team (`boss_pokemon` table). This doesn't account for games where the rival/champion adapts their team based on player decisions or battle outcomes. To accurately model these encounters, boss battles need to support variant teams keyed by a general condition system — not just starter choice.
## Scope
- **Variant conditions**: Support a general condition system for team variants. Starter choice is the most common condition, but the design must also handle arbitrary conditions (e.g., "won/lost early rival fight" in Yellow). Each variant should have a human-readable label describing the condition.
- **Admin side**: Allow defining multiple team variants per boss battle, each with a condition label and a team composition
- **Run side**: When viewing a boss battle during a run, allow the player to select which variant applies (or auto-resolve when possible, e.g., from the run's recorded starter)
- **Fallback**: If no variant teams are defined, the boss uses the existing single team as today
## Checklist
- [ ] Design database schema for conditional team variants (e.g., a `boss_team_variant` table grouping pokemon by a condition label, rather than tying directly to starter)
- [ ] Add backend models and migrations
- [ ] Add API endpoints for managing team variants per boss battle
- [ ] Update admin UI (BossTeamEditor) to support defining teams per condition/variant
- [ ] Update run-side boss display to let the player pick or auto-resolve the correct variant
- [ ] Handle edge cases: boss battles with no variants (use default team), unknown conditions

View File

@@ -1,25 +0,0 @@
---
# nuzlocke-tracker-xa5k
title: Add egg encounter logging
status: completed
type: feature
priority: normal
created_at: 2026-02-08T14:49:50Z
updated_at: 2026-02-08T21:26:24Z
---
Allow players to log egg hatches at any location, similar to how shiny encounters work. A "Log Egg" button (next to "Log Shiny") opens a modal that shows all locations — including those without wild encounters — so the player can record where an egg hatched.
Egg encounters should:
- Bypass route-locking (same pattern as shiny clause / shed evolution)
- Be available at all locations, including those that have no wild encounter data
- Use a dedicated modal similar to ShinyEncounterModal
- Otherwise behave like normal caught encounters (appear in team, can evolve, can die, etc.)
## Checklist
- [ ] Data: Seed locations without wild encounters into the routes table via PokeAPI (so they appear in the route list)
- [x] Backend: Bypass route-lock for egg encounters (extend `skip_route_lock` with an egg origin)
- [x] Frontend: Add "Log Egg" button to the run encounters page header (next to "Log Shiny")
- [x] Frontend: Create `EggEncounterModal` — similar to `ShinyEncounterModal` but shows all routes (including encounter-less ones) and uses `origin: "egg"`
- [x] Frontend: Ensure egg encounters display normally in team view and route list

View File

@@ -1,46 +0,0 @@
---
# nuzlocke-tracker-xbxv
title: Hall of Fame team selection
status: completed
type: feature
priority: normal
created_at: 2026-02-09T09:14:44Z
updated_at: 2026-02-09T09:20:01Z
blocking:
- nuzlocke-tracker-25mh
- nuzlocke-tracker-h3fw
---
When a nuzlocke run is completed (status → completed), prompt the player to select which Pokemon were in their Hall of Fame team — the party of up to 6 that beat the Elite Four and Champion.
This is a general nuzlocke feature (not genlocke-specific) and provides value on its own:
- Interesting stats: which Pokemon enter the HoF most often across runs
- Run summary: display the HoF team prominently on the completed run page
- Foundation for genlocke retireHoF logic (only retire HoF team, not all alive Pokemon)
## Behavior
- After marking a run as completed, show a modal/step asking the player to pick their HoF team from all alive Pokemon
- Max 6 Pokemon can be selected
- Store the selection as a list of encounter IDs on the run (or a join table)
- The HoF team should be displayed prominently on the completed run page (e.g. in the victory banner)
- Selection is optional — if skipped, all alive Pokemon are assumed to be in the HoF (backwards-compatible)
## Backend
- Add `hof_team` JSONB column (array of encounter IDs) to `nuzlocke_runs`, or a `hof_encounters` join table
- New endpoint or extend `PATCH /runs/{id}` to accept HoF team selection
- Include HoF team data in `GET /runs/{id}` response
## Frontend
- After the EndRunModal confirms "completed", show a HoF team selection step
- Display alive Pokemon as selectable cards (max 6)
- Show the selected HoF team in the victory banner on the completed run page
- Allow editing the HoF team after the fact (in case the player forgot or made a mistake)
## Checklist
- [x] Add `hof_encounter_ids` JSONB column to `nuzlocke_runs` (nullable array of ints)
- [x] Migration for the new column
- [x] Update `RunResponse` / `RunDetailResponse` schemas to include `hofEncounterIds`
- [x] Extend `PATCH /runs/{id}` to accept `hofEncounterIds` (validate they belong to the run and are alive)
- [x] Build HoF team selection modal (shown after completing a run)
- [x] Display HoF team in the victory banner on completed run pages
- [x] Allow editing HoF team selection on completed runs

View File

@@ -1,38 +0,0 @@
---
# nuzlocke-tracker-ycfs
title: Inject test data into dev environment
status: completed
type: task
priority: normal
created_at: 2026-02-06T09:48:38Z
updated_at: 2026-02-07T19:35:11Z
---
Create a script to populate the development database with realistic test data for manual testing.
## Requirements
- Multiple runs across different games with varied statuses:
- 2 failed runs (different games, progressed partway)
- 2 completed runs (different games, most routes visited)
- 2 active/in-progress runs (different games, early-to-mid progress)
- Each run should have a mix of encounter states:
- Caught (alive): with nicknames, catch levels
- Caught (dead): with faint_level, death_cause
- Fainted (failed to catch)
- Missed (ran away / KOd)
- Some caught Pokemon should be evolved (current_pokemon_id set via the evolutions table)
- Runs should use varied rule configurations (some with pinwheel clause off, some with hardcore mode, etc.)
- Respects the one-encounter-per-group constraint (only one child route per parent group gets an encounter, unless pinwheel zones apply)
## Implementation
- Add inject_test_data.py to backend/src/app/seeds/
- Follows the same async session pattern as run.py
- Queries DB for real game_ids, route_ids, pokemon_ids, and evolution chains so data is always valid
- Invocable via python -m app.seeds.inject_test_data (standalone entry block)
- Clears existing runs+encounters before injecting (idempotent)
- Prints summary of what was created
## Checklist
- [x] Create inject_test_data.py with test data injection logic
- [x] Wire up as standalone script (python -m app.seeds.inject_test_data)
- [x] Verify it runs cleanly against a seeded database

View File

@@ -1,24 +0,0 @@
---
# nuzlocke-tracker-ymbd
title: Implement randomize encounters
status: completed
type: feature
priority: normal
created_at: 2026-02-08T12:12:09Z
updated_at: 2026-02-08T12:13:47Z
---
Add per-route Randomize button in EncounterModal and bulk Randomize All on RunEncounters page.
## Checklist
- [ ] Phase 1: Per-route randomize in EncounterModal.tsx
- [ ] Add pickRandomPokemon helper function
- [ ] Add Randomize/Re-roll button in Pokemon selection header
- [ ] Phase 2: Bulk randomize backend
- [ ] Add BulkRandomizeResponse schema in encounter.py
- [ ] Add POST /runs/{run_id}/encounters/bulk-randomize endpoint
- [ ] Phase 3: Bulk randomize frontend
- [ ] Add bulkRandomizeEncounters() API function
- [ ] Add useBulkRandomize() hook
- [ ] Add Randomize All button on RunEncounters page

View File

@@ -1,19 +0,0 @@
---
# nuzlocke-tracker-ytzv
title: 'Add Legends: Z-A to game list'
status: completed
type: feature
priority: normal
created_at: 2026-02-07T20:54:07Z
updated_at: 2026-02-07T20:55:05Z
---
Add Pokemon Legends: Z-A as a game. Uses region 'lumiose', region_id 0 (no PokeAPI region). Go fetch tool skips route fetching for region_id 0. Manual data file for routes/encounters.
## Checklist
- [ ] Add to version_groups.json with region_id 0
- [ ] Modify Go fetch tool to skip route processing when region_id is 0
- [ ] Add to GAME_FILES in run.py
- [ ] Create placeholder data/legends-z-a.json
- [ ] Download box art
- [ ] Verify tsc --noEmit and Go build

View File

@@ -1,11 +0,0 @@
---
# nuzlocke-tracker-z511
title: Click-to-edit pattern across admin tables
status: completed
type: feature
priority: normal
created_at: 2026-02-08T12:39:48Z
updated_at: 2026-02-08T12:44:09Z
---
Remove Actions columns from all admin tables. Row click opens edit modal. Delete moves into edit modal footer with inline two-step confirm. See plan for full details.

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