Add is_admin field to UserResponse schema and update AuthContext to
fetch user profile after login, storing and exposing isAdmin boolean.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add require_admin FastAPI dependency that checks is_admin column on users
table. Apply it to all admin-facing write endpoints (games, pokemon,
evolutions, bosses, routes CRUD). Run-scoped endpoints remain protected
by require_auth only since they manage user's own data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add `is_admin` boolean column (default false) via Alembic migration
for role-based access control.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add user authentication with login/signup/protected routes, boss pokemon
detail fields and result team tracking, moves and abilities selector
components and API, run ownership and visibility controls, and various
UI improvements across encounters, run list, and journal pages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove hardcoreMode, setModeOnly, and bossTeamMatch toggles which had
no mechanical impact on the tracker. Replace them with a customRules
markdown field so users can document their own rules (especially useful
for genlockes). Add react-markdown + remark-gfm for rendering and
@tailwindcss/typography for prose styling. The custom rules display is
collapsible and hidden by default.
Also simplifies the BossDefeatModal by removing the Lost result and
attempts counter, and always shows boss team size in the level cap bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
- 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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>