Commit Graph

125 Commits

Author SHA1 Message Date
a4fa5bf1e4 feat: infer genlocke visibility from first leg's run
Genlockes now inherit visibility from their first leg's run:
- Private runs make genlockes hidden from public listings
- All genlocke read endpoints now accept optional auth
- Returns 404 for private genlockes to non-owners

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 13:47:05 +01:00
a3f332f82b feat: show owner info in admin pages
All checks were successful
CI / backend-tests (pull_request) Successful in 29s
CI / frontend-tests (pull_request) Successful in 29s
- Add Owner column to AdminRuns.tsx and AdminGenlockes.tsx
- Add owner filter dropdown to both admin pages
- Add owner field to GenlockeListItem schema (resolved from first leg's run)
- Update frontend types for GenlockeListItem

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 13:38:08 +01:00
eeb1609452 fix: enforce run ownership on all mutation endpoints
Add require_run_owner helper in auth.py that enforces ownership on
mutation endpoints. Unowned (legacy) runs are now read-only.

Applied ownership checks to:
- All 4 encounter mutation endpoints
- Both boss result mutation endpoints
- Run update/delete endpoints
- All 5 genlocke mutation endpoints (via first leg's run owner)

Also sets owner_id on run creation in genlockes.py (create_genlocke,
advance_leg) and adds 22 comprehensive ownership enforcement tests.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-21 13:28:47 +01:00
e8ded9184b feat: auth-aware UI and role-based access control (#67)
All checks were successful
CI / backend-tests (push) Successful in 32s
CI / frontend-tests (push) Successful in 29s
## Summary

- Add `is_admin` column to users table with Alembic migration and a `require_admin` FastAPI dependency that protects all admin-facing write endpoints (games, pokemon, evolutions, bosses, routes CRUD)
- Expose admin status to frontend via user API and update AuthContext to fetch/store `isAdmin` after login
- Make navigation menu auth-aware (different links for logged-out, logged-in, and admin users) and protect frontend routes with `ProtectedRoute` and `AdminRoute` components, preserving deep-linking through redirects
- Fix test reliability: `drop_all` before `create_all` to clear stale PostgreSQL enums from interrupted test runs
- Fix test auth: add `admin_client` fixture and use valid UUID for mock user so tests pass with new admin-protected endpoints

## Test plan

- [x] All 252 backend tests pass
- [ ] Verify non-admin users cannot access admin write endpoints (games, pokemon, evolutions, bosses CRUD)
- [ ] Verify admin users can access admin endpoints normally
- [ ] Verify navigation shows correct links for logged-out, logged-in, and admin states
- [ ] Verify `/admin/*` routes redirect non-admin users with a toast
- [ ] Verify `/runs/new` and `/genlockes/new` redirect unauthenticated users to login, then back after auth

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed-on: #67
Co-authored-by: Julian Tabel <juliantabel.jt@gmail.com>
Co-committed-by: Julian Tabel <juliantabel.jt@gmail.com>
2026-03-21 11:44:05 +01:00
f7731b0497 Fix local login flow, add new auth epic
Some checks failed
CI / backend-tests (push) Failing after 31s
CI / frontend-tests (push) Successful in 29s
2026-03-21 11:06:53 +01:00
0a519e356e feat: add auth system, boss pokemon details, moves/abilities API, and run ownership
Some checks failed
CI / backend-tests (push) Failing after 1m16s
CI / frontend-tests (push) Successful in 57s
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>
2026-03-20 21:41:38 +01:00
Julian Tabel
c9d42b091f Daedalus and Talos integration test
All checks were successful
CI / backend-tests (push) Successful in 26s
CI / frontend-tests (push) Successful in 29s
2026-03-20 16:31:19 +01:00
Julian Tabel
1cd1389408 Replace playstyle rules with free-text custom rules markdown field
Some checks failed
CI / backend-tests (push) Successful in 28s
CI / frontend-tests (push) Failing after 28s
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>
2026-03-20 15:09:02 +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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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