210 Commits

Author SHA1 Message Date
Renovate Bot
4d446a73d6 chore(deps): lock file maintenance
All checks were successful
CI / backend-tests (pull_request) Successful in 29s
CI / frontend-tests (pull_request) Successful in 29s
2026-03-23 00:03:10 +00:00
d8fec0e5d7 fix:add debugging endpoint for auth issues
All checks were successful
CI / backend-tests (push) Successful in 30s
CI / frontend-tests (push) Successful in 28s
2026-03-22 12:15:25 +01:00
c9b09b8250 fix: fix supabase auth url
All checks were successful
CI / backend-tests (push) Successful in 30s
CI / frontend-tests (push) Successful in 30s
2026-03-22 12:10:03 +01:00
fde1867863 fix: add logging to debug auth issues
All checks were successful
CI / backend-tests (push) Successful in 29s
CI / frontend-tests (push) Successful in 28s
2026-03-22 12:01:28 +01:00
ce9d08963f Merge pull request 'Fix intermittent 401 errors and add ES256 JWT support' (#86) from feature/fix-intermittent-401-errors into develop
All checks were successful
CI / backend-tests (push) Successful in 30s
CI / frontend-tests (push) Successful in 29s
Reviewed-on: #86
2026-03-22 11:53:48 +01:00
c5959cfd14 chore: mark ES256 JWT support bean as completed
All checks were successful
CI / backend-tests (pull_request) Successful in 33s
CI / frontend-tests (pull_request) Successful in 33s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 11:53:13 +01:00
e935bc4d32 fix: accept ES256 (ECC P-256) JWT keys alongside RS256 in backend auth
Supabase JWT key was switched to ECC P-256, but the JWKS verification
only accepted RS256. Add ES256 to the accepted algorithms list.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 11:52:42 +01:00
79cbb06ec9 Merge pull request 'feat: team sidebar as floating panel on desktop' (#85) from feature/team-sidebar-desktop into develop
All checks were successful
CI / backend-tests (push) Successful in 30s
CI / frontend-tests (push) Successful in 28s
Reviewed-on: #85
2026-03-22 11:35:52 +01:00
d1ede63256 Merge pull request 'fix: proactively refresh Supabase JWT before API calls' (#84) from feature/fix-intermittent-401-errors into develop
Some checks failed
CI / frontend-tests (push) Has been cancelled
CI / backend-tests (push) Has been cancelled
Reviewed-on: #84
2026-03-22 11:35:26 +01:00
80d5d01993 chore: scrap false-positive crash bean nuzlocke-tracker-9rm8
All checks were successful
CI / backend-tests (pull_request) Successful in 30s
CI / frontend-tests (pull_request) Successful in 28s
MFA feature was already completed and merged via PR #76.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 10:46:25 +01:00
fd2020ce50 chore: close false-positive crash bean nuzlocke-tracker-26my
Original bean (nuzlocke-tracker-2fp1) was already completed.
Commit a3f332f merged via PR #74.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 10:45:34 +01:00
4d6e1dc5b2 feat: make level field optional in boss defeat modal
All checks were successful
CI / backend-tests (pull_request) Successful in 29s
CI / frontend-tests (pull_request) Successful in 39s
Remove the level input from the boss defeat modal since the app doesn't
track levels elsewhere. Team selection is now just checkboxes without
requiring level entry.

- Remove level input UI from BossDefeatModal.tsx
- Add alembic migration to make boss_result_team.level nullable
- Update model and schemas to make level optional (defaults to null)
- Conditionally render level in boss result display

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 10:16:15 +01:00
aee28cd7a1 chore: mark bean nuzlocke-tracker-lkro as completed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 10:12:02 +01:00
3dbc3f35ba feat: make team section a floating sidebar on desktop
Add responsive 2-column layout for the encounters page:
- Desktop (lg, ≥1024px): Encounters on left, team in sticky right sidebar
- Mobile/tablet: Keep current stacked layout

The sidebar scrolls independently when team exceeds viewport height.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 10:11:40 +01:00
4ca5f9263c chore: mark owner info in admin pages beans as completed
The implementation was already complete and merged - just needed
the beans marked as done after agent crash.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 10:08:23 +01:00
891c1f6757 chore: mark MFA beans as completed
Crash recovery for nuzlocke-tracker-f2hs: MFA feature was already
implemented and merged via PR #76. Verified code, tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 10:06:38 +01:00
118dbcafd9 chore: mark bean nuzlocke-tracker-i2va as completed
Work was already committed (3bd24fc) and merged to develop.
Crash recovery bean nuzlocke-tracker-ks9c also resolved.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 10:03:22 +01:00
c21d33ad65 chore: mark bean nuzlocke-tracker-tatg as completed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 10:01:48 +01:00
22dd569b75 fix: proactively refresh Supabase JWT before API calls
Adds token expiry checking and automatic refresh to prevent intermittent
401 errors when the cached session token expires between interactions.

- Check token expiry (60s buffer) before each API call
- Add 401 interceptor that retries once with refreshed token
- Explicitly enable autoRefreshToken in Supabase client

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 10:01:38 +01:00
ac0a04e71f fix: catch PyJWKSetError in JWT verification fallback
All checks were successful
CI / backend-tests (push) Successful in 29s
CI / frontend-tests (push) Successful in 28s
PyJWKSetError is not a subclass of PyJWKClientError — they are siblings
under PyJWTError. The empty JWKS key set error was not being caught.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 09:56:58 +01:00
94cc74c0fb Merge pull request 'Fix except clause syntax in JWT verification fallback' (#81) from feature/fix-except-clause-syntax-in-jwt-verification into develop
All checks were successful
CI / backend-tests (push) Successful in 30s
CI / frontend-tests (push) Successful in 28s
Reviewed-on: #81
2026-03-22 09:53:43 +01:00
41a18edb4f fix: use separate except clauses for JWT verification fallback
All checks were successful
CI / backend-tests (pull_request) Successful in 29s
CI / frontend-tests (pull_request) Successful in 29s
ruff format strips parentheses from `except (A, B):`, turning it into
Python 2 comma syntax that only catches the first exception. Use
separate except clauses so PyJWKClientError is actually caught.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 09:52:33 +01:00
291eba63a7 chore: update bean 2026-03-22 09:42:15 +01:00
d98b0da410 Merge pull request 'Fix JWT verification failing in local dev (HS256 fallback)' (#80) from feature/fix-jwt-verification-failing-in-local-dev-hs256-fallback into develop
All checks were successful
CI / backend-tests (push) Successful in 31s
CI / frontend-tests (push) Successful in 29s
Reviewed-on: #80
2026-03-22 09:41:39 +01:00
af55cdd8a6 fix: add HS256 fallback for JWT verification in local dev
All checks were successful
CI / backend-tests (pull_request) Successful in 29s
CI / frontend-tests (pull_request) Successful in 29s
Local GoTrue signs JWTs with HS256, but the JWKS endpoint returns an
empty key set since there are no RSA keys. Fall back to HS256 shared
secret verification when JWKS fails, using SUPABASE_JWT_SECRET.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 09:38:52 +01:00
0ec1beac8f Merge pull request 'Migrate JWT verification from HS256 to JWKS' (#75) from feature/migrate-jwt-verification-to-jwks into develop
All checks were successful
CI / backend-tests (push) Successful in 29s
CI / frontend-tests (push) Successful in 28s
Reviewed-on: #75
2026-03-22 09:26:22 +01:00
d541b92253 Merge pull request 'chore(deps): update dependency @tanstack/react-query to v5.94.5' (#78) from renovate/tanstack-react-query-5.x into develop
Some checks failed
CI / frontend-tests (push) Has been cancelled
CI / backend-tests (push) Has been cancelled
Reviewed-on: #78
2026-03-22 09:25:37 +01:00
d23e24b826 Merge branch 'feature/migrate-jwt-verification-to-jwks' of https://gitea.nerdboden.de/pokemon/nuzlocke-tracker into feature/migrate-jwt-verification-to-jwks
All checks were successful
CI / backend-tests (pull_request) Successful in 31s
CI / frontend-tests (pull_request) Successful in 29s
2026-03-22 09:25:05 +01:00
e9eccc5b21 feat: migrate JWT verification from HS256 shared secret to JWKS
Replace symmetric HS256 JWT verification with asymmetric RS256 using JWKS.
Backend now fetches and caches public keys from Supabase's JWKS endpoint
instead of using a shared secret.

- Add cryptography dependency for RS256 support
- Use PyJWKClient to fetch/cache JWKS from {SUPABASE_URL}/.well-known/jwks.json
- Remove SUPABASE_JWT_SECRET from config, docker-compose, deploy workflow, .env
- Update tests to use RS256 tokens with mocked JWKS client

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 09:24:41 +01:00
79ad7b9133 chore: update bean 2026-03-22 09:23:12 +01:00
50ed370d24 Merge pull request 'Add optional TOTP MFA for email/password accounts' (#76) from feature/optional-totp-mfa into develop
All checks were successful
CI / backend-tests (push) Successful in 31s
CI / frontend-tests (push) Successful in 29s
Reviewed-on: #76
2026-03-22 09:21:33 +01:00
8be9718293 Merge pull request 'Enforce run ownership and show owner info' (#74) from feature/enforce-run-ownership-on-all-mutation-endpoints into develop
All checks were successful
CI / backend-tests (push) Successful in 29s
CI / frontend-tests (push) Successful in 29s
Reviewed-on: #74
2026-03-22 09:16:54 +01:00
38b1156a95 Merge branch 'develop' into feature/enforce-run-ownership-on-all-mutation-endpoints
All checks were successful
CI / backend-tests (pull_request) Successful in 33s
CI / frontend-tests (pull_request) Successful in 29s
2026-03-22 09:16:36 +01:00
596393d5b8 Merge pull request 'Infer genlocke visibility from first leg's run' (#77) from feature/infer-genlocke-visibility-from-first-legs-run into feature/enforce-run-ownership-on-all-mutation-endpoints
All checks were successful
CI / backend-tests (pull_request) Successful in 29s
CI / frontend-tests (pull_request) Successful in 29s
Reviewed-on: #77
2026-03-22 09:15:16 +01:00
c064a1b8d4 chore: bean organisation 2026-03-22 08:56:06 +01:00
f17687d2fa fix: resolve merge conflict in bean t9aj
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 22:50:19 +01:00
Renovate Bot
e279fc76ee chore(deps): update dependency @tanstack/react-query to v5.94.5
All checks were successful
CI / backend-tests (pull_request) Successful in 27s
CI / frontend-tests (pull_request) Successful in 28s
2026-03-21 16:01:57 +00:00
177c02006a feat: migrate JWT verification from HS256 shared secret to JWKS
All checks were successful
CI / backend-tests (pull_request) Successful in 28s
CI / frontend-tests (pull_request) Successful in 28s
Replace symmetric HS256 JWT verification with asymmetric RS256 using JWKS.
Backend now fetches and caches public keys from Supabase's JWKS endpoint
instead of using a shared secret.

- Add cryptography dependency for RS256 support
- Use PyJWKClient to fetch/cache JWKS from {SUPABASE_URL}/.well-known/jwks.json
- Remove SUPABASE_JWT_SECRET from config, docker-compose, deploy workflow, .env
- Update tests to use RS256 tokens with mocked JWKS client

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 14:01:36 +01:00
7a828d7215 feat: add optional TOTP MFA for email/password accounts
All checks were successful
CI / backend-tests (pull_request) Successful in 26s
CI / frontend-tests (pull_request) Successful in 28s
- Add MFA enrollment UI in new Settings page with QR code and backup secret
- Add TOTP challenge step to login flow for enrolled users
- Check AAL after login and show TOTP input when aal2 required
- Add disable MFA option with TOTP re-verification
- Only show MFA options for email/password users (not OAuth)
- Add Settings link to user dropdown menu

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 13:56:48 +01:00
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
3bd24fcdb0 fix: hide edit controls for non-owners in frontend
- Add useAuth and canEdit logic to RunEncounters.tsx
- Guard all mutation triggers (Log Shiny, Log Egg, End Run, Randomize All,
  HoF Edit, Boss Battle, route/team clicks, Advance to Next Leg)
- Update RunDashboard.tsx canEdit to be isOwner only (no unowned fallback)
- Add read-only banner for non-owner viewers in both pages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 13:33:04 +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
a12958ae32 update beans and postgres mount path
All checks were successful
CI / backend-tests (push) Successful in 27s
CI / frontend-tests (push) Successful in 29s
2026-03-21 12:51:35 +01:00
7e7c5e7536 Merge pull request 'fix: TypeScript build errors in RunEncounters.tsx' (#71) from feature/fix-typescript-build-errors-in-runencounterstsx into develop
All checks were successful
CI / backend-tests (push) Successful in 27s
CI / frontend-tests (push) Successful in 29s
Reviewed-on: #71
2026-03-21 12:26:34 +01:00
5c10041b8b fix: TypeScript build errors in RunEncounters.tsx
All checks were successful
CI / backend-tests (pull_request) Successful in 27s
CI / frontend-tests (pull_request) Successful in 29s
Use explicit BossResult type instead of indexing potentially undefined
typeof bossResults. Add BossResultTeamMember type to tm parameter.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 12:25:20 +01:00
7276f05dd2 Merge pull request 'feat: add Supabase auth config to production Docker setup' (#69) from feature/add-supabase-auth-config-to-production-docker-setup into develop
All checks were successful
CI / backend-tests (push) Successful in 29s
CI / frontend-tests (push) Successful in 29s
Reviewed-on: #69
2026-03-21 12:19:29 +01:00
7b0cd16064 feat: write production .env from Gitea secrets during deploy
All checks were successful
CI / backend-tests (pull_request) Successful in 26s
CI / frontend-tests (pull_request) Successful in 28s
Instead of relying on a pre-existing .env file on the server, the
deploy workflow now writes POSTGRES_PASSWORD and SUPABASE_JWT_SECRET
from Gitea secrets. This keeps all secret management in one place.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 12:17:59 +01:00
7cd3372c7e feat: add Supabase auth config to production Docker setup
All checks were successful
CI / backend-tests (pull_request) Successful in 26s
CI / frontend-tests (pull_request) Successful in 29s
- Pass SUPABASE_JWT_SECRET to backend in docker-compose.prod.yml
- Add build args (VITE_API_URL, VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY)
  to Dockerfile.prod so Vite inlines them at build time
- Pass build args from secrets in deploy workflow
- Add build section to frontend service in docker-compose.prod.yml

No GoTrue container needed in prod — Supabase Cloud hosts the auth
service. The backend only needs the JWT secret to verify tokens.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 12:07:53 +01:00
d1d9a60134 Merge pull request 'chore(deps): update dependency jsdom to v29' (#62) from renovate/jsdom-29.x into develop
All checks were successful
CI / backend-tests (push) Successful in 27s
CI / frontend-tests (push) Successful in 28s
Reviewed-on: #62
2026-03-21 12:04:26 +01:00
Renovate Bot
ecff53ef58 chore(deps): update dependency jsdom to v29
All checks were successful
CI / backend-tests (pull_request) Successful in 27s
CI / frontend-tests (pull_request) Successful in 29s
2026-03-21 11:02:05 +00:00
0f1d205176 Merge pull request 'chore(deps): update supabase/gotrue docker tag to v2.188.1' (#68) from renovate/supabase-gotrue-2.x into develop
All checks were successful
CI / backend-tests (push) Successful in 28s
CI / frontend-tests (push) Successful in 28s
2026-03-21 12:02:02 +01:00
e1904b818e Merge pull request 'chore(deps): update postgres docker tag to v18' (#66) from renovate/postgres-18.x into develop
Some checks failed
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
2026-03-21 12:01:35 +01:00
100d2d72d0 Merge pull request 'chore(deps): update node docker tag to v25' (#65) from renovate/node-25.x into develop
Some checks failed
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
2026-03-21 12:01:27 +01:00
0d6d0d512c Merge pull request 'chore(deps): update dependency @vitejs/plugin-react to v6' (#60) from renovate/vitejs-plugin-react-6.x into develop
Some checks failed
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
2026-03-21 12:00:59 +01:00
Renovate Bot
99f2676c15 chore(deps): update dependency @vitejs/plugin-react to v6
All checks were successful
CI / backend-tests (pull_request) Successful in 27s
CI / frontend-tests (pull_request) Successful in 29s
2026-03-21 10:59:05 +00:00
8476f1fa69 Merge pull request 'chore(deps): update dependency vite to v8' (#64) from renovate/vite-8.x into develop
All checks were successful
CI / backend-tests (push) Successful in 30s
CI / frontend-tests (push) Successful in 29s
2026-03-21 11:56:39 +01:00
Renovate Bot
bcc0239f6a chore(deps): update postgres docker tag to v18
All checks were successful
CI / backend-tests (pull_request) Successful in 26s
CI / frontend-tests (pull_request) Successful in 30s
2026-03-21 10:49:30 +00:00
Renovate Bot
e979b875ec chore(deps): update node docker tag to v25
All checks were successful
CI / backend-tests (pull_request) Successful in 28s
CI / frontend-tests (pull_request) Successful in 29s
2026-03-21 10:49:23 +00:00
Renovate Bot
5957ac5558 chore(deps): update dependency vite to v8
All checks were successful
CI / backend-tests (pull_request) Successful in 27s
CI / frontend-tests (pull_request) Successful in 29s
2026-03-21 10:49:08 +00:00
Renovate Bot
f70bebfb26 chore(deps): update supabase/gotrue docker tag to v2.188.1
All checks were successful
CI / backend-tests (pull_request) Successful in 28s
CI / frontend-tests (pull_request) Successful in 29s
2026-03-21 10:48:32 +00:00
993cd25fbb Merge pull request 'chore(deps): update actions/upload-artifact action to v7' (#59) from renovate/actions-upload-artifact-7.x into develop
All checks were successful
CI / backend-tests (push) Successful in 30s
CI / frontend-tests (push) Successful in 30s
2026-03-21 11:46:01 +01:00
7265905866 Merge pull request 'chore(deps): update dependency pyjwt to v2.12.1' (#61) from renovate/pyjwt-2.x into develop
Some checks failed
CI / frontend-tests (push) Has been cancelled
CI / backend-tests (push) Has been cancelled
2026-03-21 11:45:56 +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
0d6174067e feat: enforce feature branch workflow with PreToolUse hook
Add a guard script that blocks git commit/push on protected branches
(develop, main, master) via a PreToolUse hook. Update CLAUDE.md with
stricter branching rules: one commit per task, immediate commits on
feature branches, no direct commits to protected branches.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 10:45:58 +01:00
93a90f4ba7 add docker init folder
Some checks failed
CI / backend-tests (pull_request) Failing after 1m11s
CI / frontend-tests (pull_request) Successful in 28s
2026-03-20 22:13:01 +01:00
3d362a8314 Last weird branch commit
Some checks failed
CI / backend-tests (pull_request) Failing after 1m16s
CI / frontend-tests (pull_request) Successful in 28s
2026-03-20 22:11:39 +01:00
Renovate Bot
5185a251f4 chore(deps): update dependency pyjwt to v2.12.1
Some checks failed
CI / backend-tests (pull_request) Failing after 1m10s
CI / frontend-tests (pull_request) Successful in 28s
2026-03-20 21:02:21 +00:00
2364922b58 beans update 2026-03-20 21:59:43 +01:00
3881971214 chore: add .talos/ to .gitignore
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 21:42:52 +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
a6cb309b8b chore: archive 42 completed/scrapped beans
All checks were successful
CI / backend-tests (push) Successful in 28s
CI / frontend-tests (push) Successful in 28s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 21:31:23 +01:00
Renovate Bot
106156b73d chore(deps): update actions/upload-artifact action to v7
All checks were successful
CI / backend-tests (pull_request) Successful in 26s
CI / frontend-tests (pull_request) Successful in 4m36s
2026-03-20 20:03:14 +00:00
27c89ccf2b Merge pull request 'chore(deps): update dependency oxlint to v1.56.0' (#51) from renovate/oxlint-1.x into develop
All checks were successful
CI / backend-tests (push) Successful in 25s
CI / frontend-tests (push) Successful in 1m21s
Reviewed-on: #51
2026-03-20 20:17:14 +01:00
ccabf3bdf3 Merge pull request 'chore(deps): update actions/checkout action to v6' (#57) from renovate/actions-checkout-6.x into develop
Some checks failed
CI / frontend-tests (push) Has been cancelled
CI / backend-tests (push) Has been cancelled
Reviewed-on: #57
2026-03-20 20:17:00 +01:00
55484a047d Merge pull request 'chore(deps): update actions/setup-node action to v6' (#58) from renovate/actions-setup-node-6.x into develop
Some checks failed
CI / frontend-tests (push) Has been cancelled
CI / backend-tests (push) Has been cancelled
Reviewed-on: #58
2026-03-20 20:16:44 +01:00
Renovate Bot
7c11902613 chore(deps): update actions/setup-node action to v6
All checks were successful
CI / backend-tests (pull_request) Successful in 25s
CI / frontend-tests (pull_request) Successful in 58s
2026-03-20 19:03:48 +00:00
Renovate Bot
24646d30c6 chore(deps): update actions/checkout action to v6
All checks were successful
CI / backend-tests (pull_request) Successful in 37s
CI / frontend-tests (pull_request) Successful in 29s
2026-03-20 19:03:42 +00:00
Renovate Bot
a4f2f52c10 chore(deps): update dependency oxlint to v1.56.0
All checks were successful
CI / backend-tests (pull_request) Successful in 26s
CI / frontend-tests (pull_request) Successful in 27s
2026-03-20 19:03:33 +00:00
9327c068a5 Merge pull request 'chore(deps): update dependency node to v24.14.0' (#50) from renovate/node-24.x into develop
All checks were successful
CI / backend-tests (push) Successful in 26s
CI / frontend-tests (push) Successful in 1m53s
Reviewed-on: #50
2026-03-20 19:59:26 +01:00
9acde89ceb Merge pull request 'chore(deps): update dependency pydantic-settings to v2.13.1' (#52) from renovate/pydantic-settings-2.x into develop
Some checks failed
CI / frontend-tests (push) Has been cancelled
CI / backend-tests (push) Has been cancelled
Reviewed-on: #52
2026-03-20 19:58:53 +01:00
b82e55c8de Merge pull request 'chore(deps): update dependency tailwindcss to v4.2.2' (#53) from renovate/tailwindcss-4.x into develop
Some checks failed
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
Reviewed-on: #53
2026-03-20 19:58:34 +01:00
Renovate Bot
cac675a5c7 chore(deps): update dependency uvicorn to v0.42.0
Some checks failed
CI / backend-tests (pull_request) Successful in 26s
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
CI / frontend-tests (pull_request) Successful in 46s
2026-03-20 19:57:09 +01:00
Renovate Bot
803f5bb8be chore(deps): update dependency vitest to v4.1.0
All checks were successful
CI / backend-tests (pull_request) Successful in 25s
CI / frontend-tests (pull_request) Successful in 27s
CI / backend-tests (push) Successful in 31s
CI / frontend-tests (push) Successful in 28s
2026-03-20 18:02:55 +00:00
Renovate Bot
b9d457d3a1 chore(deps): update dependency tailwindcss to v4.2.2
All checks were successful
CI / backend-tests (pull_request) Successful in 25s
CI / frontend-tests (pull_request) Successful in 27s
2026-03-20 17:02:26 +00:00
Renovate Bot
60e2413b9f chore(deps): update dependency pydantic-settings to v2.13.1
All checks were successful
CI / backend-tests (pull_request) Successful in 26s
CI / frontend-tests (pull_request) Successful in 28s
2026-03-20 17:02:17 +00:00
Renovate Bot
0a803c30d3 chore(deps): update dependency node to v24.14.0
All checks were successful
CI / backend-tests (pull_request) Successful in 25s
CI / frontend-tests (pull_request) Successful in 27s
2026-03-20 16:01:49 +00:00
Julian Tabel
2f8b437c8a stopped talos
All checks were successful
CI / backend-tests (push) Successful in 26s
CI / frontend-tests (push) Successful in 27s
2026-03-20 16:40:15 +01:00
Julian Tabel
088cd35002 add Ko-fi bean
Some checks failed
CI / frontend-tests (push) Has been cancelled
CI / backend-tests (push) Has been cancelled
2026-03-20 16:39:52 +01:00
Julian Tabel
6c36cbfe12 chore(errors): Errors
Container for crash and blocker beans created by Talos.

Bean: nuzlocke-tracker-bw1m
2026-03-20 16:39:28 +01:00
Julian Tabel
5bd4ca7d3e add Ko-fi bean 2026-03-20 16:38:54 +01:00
4132face2a Merge pull request 'Update dependency golang to v1.26.1' (#48) from renovate/golang-1.x into develop
All checks were successful
CI / backend-tests (push) Successful in 25s
CI / frontend-tests (push) Successful in 28s
Reviewed-on: #48
2026-03-20 16:35:37 +01:00
bdb3f45122 Merge pull request 'Update dependency oxfmt to v0.41.0' (#49) from renovate/oxfmt-0.x into develop
Some checks failed
CI / frontend-tests (push) Has been cancelled
CI / backend-tests (push) Has been cancelled
Reviewed-on: #49
2026-03-20 16:35:24 +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
Renovate Bot
634e957bb8 Update dependency oxfmt to v0.41.0
All checks were successful
CI / backend-tests (pull_request) Successful in 24s
CI / frontend-tests (pull_request) Successful in 28s
2026-03-20 15:02:02 +00:00
Renovate Bot
ed75fdd1b0 Update dependency golang to v1.26.1
All checks were successful
CI / backend-tests (pull_request) Successful in 25s
CI / frontend-tests (pull_request) Successful in 28s
2026-03-20 15:01:53 +00:00
Julian Tabel
5106e57685 Enable lockFileMaintenance in Renovate config
All checks were successful
CI / backend-tests (push) Successful in 26s
CI / frontend-tests (push) Successful in 28s
Adds weekly transitive dependency refresh for both npm and uv lockfiles.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 15:53:19 +01:00
Renovate Bot
b413f5e4e4 Update dependency node to v24.14.0
Some checks failed
CI / backend-tests (pull_request) Successful in 24s
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
CI / frontend-tests (pull_request) Successful in 30s
2026-03-20 15:52:17 +01:00
Renovate Bot
5905142981 Update dependency fastapi to v0.135.1
Some checks failed
CI / backend-tests (pull_request) Successful in 24s
CI / frontend-tests (pull_request) Successful in 27s
CI / backend-tests (push) Successful in 26s
CI / frontend-tests (push) Has been cancelled
2026-03-20 14:49:42 +00:00
Julian Tabel
24c60e2e28 Add backend tool-versions and update bean status
All checks were successful
CI / backend-tests (push) Successful in 25s
CI / frontend-tests (push) Successful in 28s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 15:29:22 +01:00
Julian Tabel
77900ba045 Update dependencies from Renovate PRs
All checks were successful
CI / backend-tests (push) Successful in 28s
CI / frontend-tests (push) Successful in 29s
Backend: python-dotenv 1.2.1→1.2.2, sqlalchemy 2.0.46→2.0.48, ty 0.0.17→0.0.24
Frontend: react-router-dom 7.13.0→7.13.1, @tanstack/react-query 5.90.20→5.91.3, @vitejs/plugin-react 5.1.3→5.2.0

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 15:26:08 +01:00
Julian Tabel
869d28ab84 remove playstyle section from test
All checks were successful
CI / backend-tests (push) Successful in 28s
CI / frontend-tests (push) Successful in 27s
2026-03-20 15:13:25 +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
Julian Tabel
535154a056 Allow multiple games per region in Custom genlocke
All checks were successful
CI / backend-tests (push) Successful in 25s
CI / frontend-tests (push) Successful in 27s
In custom mode, the region picker no longer filters out already-used
regions, letting users add multiple legs from the same region (e.g.
Black + Black 2 in Unova). Preset modes keep the one-per-region
behavior. Already-used regions show a subtle dot indicator.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 13:32:42 +01:00
7d1c091432 Merge pull request 'Configure Renovate' (#33) from renovate/configure into develop
All checks were successful
CI / backend-tests (push) Successful in 26s
CI / frontend-tests (push) Successful in 29s
Reviewed-on: #33
2026-03-17 13:29:24 +01:00
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
844 changed files with 343318 additions and 381929 deletions

View File

@@ -0,0 +1,32 @@
---
# nuzlocke-tracker-12cw
title: 'Crash: Crash: User model, run ownership, and visibility migration'
status: completed
type: bug
priority: high
created_at: 2026-03-20T19:13:06Z
updated_at: 2026-03-20T19:21:27Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-gez0
---
Agent crashed while working on nuzlocke-tracker-gez0.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZEs5bfrivterCHgjXoWG"}
```
## Context
- Bean: nuzlocke-tracker-gez0
- Title: Crash: User model, run ownership, and visibility migration
- Type: bug
## Reasons for Scrapping
This crash was caused by an expired OAuth token during agent execution - a transient session management issue, not a code bug. The underlying task (nuzlocke-tracker-bnhh) remains blocked by nuzlocke-tracker-2561 (Supabase setup) and can be resumed once that prerequisite is complete.

View File

@@ -0,0 +1,68 @@
---
# nuzlocke-tracker-1y09
title: Enforce feature branch workflow for agents
status: completed
type: task
priority: high
created_at: 2026-03-20T20:48:21Z
updated_at: 2026-03-20T21:01:47Z
---
## Problem
Agents sometimes commit directly to `develop` instead of creating feature branches. The CLAUDE.md branching strategy documents the intent but isn't enforced — agents can ignore it.
## Solution
Add a Claude Code `PreToolCall` hook that blocks `git commit` when the current branch is `develop` or `main`, forcing agents to always work on `feature/*` branches. Also update CLAUDE.md to document the stricter workflow.
**Scope:** Agent-only enforcement (humans can still commit on `develop` if needed).
## Changes
### 1. Claude Code hook (`.claude/settings.json`)
Add a `PreToolCall` hook that:
- Triggers on `Bash` tool calls containing `git commit`
- Checks the current branch name via `git branch --show-current`
- **Blocks** if branch is `develop` or `main` with a clear error message
- **Allows** if branch matches `feature/*` or any other pattern
```json
{
"hooks": {
"PreToolCall": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash -c 'if echo \"$TOOL_INPUT\" | grep -q \"git commit\"; then BRANCH=$(git branch --show-current); if [ \"$BRANCH\" = \"develop\" ] || [ \"$BRANCH\" = \"main\" ]; then echo \"BLOCK: Cannot commit directly to $BRANCH. Create a feature branch first: git checkout -b feature/<name>\"; exit 2; fi; fi'"
}
]
}
]
}
}
```
> Note: Exit code 2 blocks the tool call. The hook should parse `$TOOL_INPUT` (JSON) to check for git commit commands.
### 2. CLAUDE.md update
Update the "Branching Strategy" section to add:
- **Never commit directly to `develop` or `main`.** Always create a `feature/*` branch first.
- When starting an **epic**, create `feature/<epic-title-slug>` off `develop`
- When starting a **standalone task/bug** (no parent epic), create `feature/<task-title-slug>` off `develop`
- Each task within an epic gets its own commit(s) on the epic's feature branch
- Branch naming: use a kebab-case slug of the bean title (e.g., `feature/add-auth-system`)
- When the epic/task is complete, squash merge into `develop`
## Checklist
- [ ] Add `PreToolCall` hook to `.claude/settings.json` that blocks commits on `develop`/`main`
- [ ] Test hook by verifying it blocks a commit attempt on `develop`
- [ ] Test hook by verifying it allows a commit on a `feature/*` branch
- [ ] Update CLAUDE.md branching strategy with new workflow rules
- [ ] Verify hook handles edge cases (e.g., `git commit --amend`, `git commit -m "..."`)

View File

@@ -0,0 +1,21 @@
---
# nuzlocke-tracker-2561
title: Supabase Auth project setup and provider config
status: completed
type: task
priority: normal
created_at: 2026-03-20T15:28:08Z
updated_at: 2026-03-20T20:04:40Z
parent: nuzlocke-tracker-d98o
---
Set up Supabase project with Auth enabled. Configure Google and Discord as social login providers. Add Supabase URL and keys to backend/frontend environment variables. This is the foundation — nothing else can start until the Supabase project exists.
## Checklist
- [ ] Create Supabase project (or configure existing one)
- [ ] Enable email/password auth
- [ ] Configure Google OAuth provider
- [ ] Configure Discord OAuth provider
- [x] Add SUPABASE_URL, SUPABASE_ANON_KEY, SUPABASE_JWT_SECRET to backend env
- [x] Add VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY to frontend env
- [x] Document setup steps for local development

View File

@@ -0,0 +1,38 @@
---
# nuzlocke-tracker-2zwg
title: Protect frontend routes with ProtectedRoute and AdminRoute
status: completed
type: task
priority: normal
created_at: 2026-03-21T10:06:20Z
updated_at: 2026-03-21T10:19:41Z
parent: nuzlocke-tracker-ce4o
blocked_by:
- nuzlocke-tracker-5svj
---
Use the existing \`ProtectedRoute\` component (currently unused) and create an \`AdminRoute\` component to guard routes in \`App.tsx\`.
## Checklist
- [x] Wrap \`/runs/new\` and \`/genlockes/new\` with \`ProtectedRoute\` (requires login)
- [x] Create \`AdminRoute\` component that checks \`isAdmin\` from \`useAuth()\`, redirects to \`/\` with a toast/message if not admin
- [x] Wrap all \`/admin/*\` routes with \`AdminRoute\`
- [x] Ensure \`/runs\` and \`/runs/:runId\` remain accessible to everyone (public run viewing)
- [x] Verify deep-linking works (e.g., visiting \`/admin/games\` while logged out redirects to login, then back to \`/admin/games\` after auth)
## Files to change
- \`frontend/src/App.tsx\` — wrap routes
- \`frontend/src/components/ProtectedRoute.tsx\` — already exists, verify it works
- \`frontend/src/components/AdminRoute.tsx\` — new file
## Summary of Changes
Implemented frontend route protection:
- **ProtectedRoute**: Wraps `/runs/new` and `/genlockes/new` - redirects unauthenticated users to `/login` with return location preserved
- **AdminRoute**: New component that checks `isAdmin` from `useAuth()`, redirects non-admins to `/` with a toast notification
- **Admin routes**: Wrapped `AdminLayout` with `AdminRoute` to protect all `/admin/*` routes
- **Public routes**: `/runs` and `/runs/:runId` remain accessible to everyone
- **Deep-linking**: Location state preserved so users return to original route after login

View File

@@ -0,0 +1,13 @@
---
# nuzlocke-tracker-3mwb
title: Fix TypeScript build errors in RunEncounters.tsx
status: completed
type: bug
priority: normal
created_at: 2026-03-21T11:24:09Z
updated_at: 2026-03-21T11:25:37Z
---
Two TS errors blocking production build:\n1. Line 693: `(typeof bossResults)[number]` fails because bossResults is `BossResult[] | undefined`\n2. Line 1601: Parameter 'tm' implicitly has 'any' type
## Summary of Changes\n\nFixed two TypeScript errors in RunEncounters.tsx:\n1. Used explicit `BossResult` type instead of `(typeof bossResults)[number]`\n2. Added `BossResultTeamMember` type annotation to `tm` parameter\n\nPR: #71

View File

@@ -0,0 +1,34 @@
---
# nuzlocke-tracker-3psa
title: 'Crash: Bug: TypeScript build fails due to optional property type mismatches in journal components'
status: completed
type: bug
priority: high
tags:
- failed
created_at: 2026-03-20T19:00:37Z
updated_at: 2026-03-20T19:17:34Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-d5ht
---
Agent crashed while working on nuzlocke-tracker-d5ht.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZEr8PbYrEx4DTBz6e1Z7"}
```
## Context
- Bean: nuzlocke-tracker-d5ht
- Title: Bug: TypeScript build fails due to optional property type mismatches in journal components
- Type: bug
## Summary of Changes
Resolved by nuzlocke-tracker-xsdr - TypeScript build errors fixed.

View File

@@ -0,0 +1,50 @@
---
# nuzlocke-tracker-52rw
title: 'Bug: Tailwind typography plugin unresolvable in Docker dev container'
status: completed
type: bug
priority: deferred
created_at: 2026-03-20T19:23:06Z
updated_at: 2026-03-20T20:26:50Z
---
## Problem
After commit 1cd1389 added `@tailwindcss/typography` and the `@plugin '@tailwindcss/typography'` directive in `index.css`, the frontend Docker dev container fails to start with:
```
[plugin:@tailwindcss/vite:generate:serve] Can't resolve '@tailwindcss/typography' in '/app/src'
```
## Root Cause
The `docker-compose.yml` volume mount `./frontend/src:/app/src:cached` overlays the host's `src/` directory into the container. The new `src/index.css` contains `@plugin '@tailwindcss/typography'`, which Tailwind's Vite plugin tries to resolve starting from `/app/src/`.
Two possible causes:
1. **Stale Docker image** — If the image wasn't rebuilt after `@tailwindcss/typography` was added to `package.json`, the container's `node_modules` doesn't have the package. Fix: `docker compose build frontend` or `docker compose up --build`.
2. **Resolution path issue** — Tailwind v4's `@plugin` resolution may not walk up to `/app/node_modules` from `/app/src/index.css`. This would be a persistent issue even after rebuilding.
## Fix
- [x] Rebuild the Docker image and test if the error persists (FIXED - error was due to stale image)
- [~] If it persists after rebuild, add volume mounts (N/A - not needed, rebuild fixed it)
- [~] If resolution is the issue, consider moving the `@plugin` directive (N/A - not needed)
- [x] Verify the frontend starts correctly in Docker with `docker compose up frontend`
## Files
- `docker-compose.yml` (line 27: src volume mount)
- `frontend/src/index.css` (line 2: `@plugin '@tailwindcss/typography'`)
- `frontend/package.json` (line 22: `@tailwindcss/typography` dependency)
- `frontend/Dockerfile`
## Summary of Changes
The issue was caused by a **stale Docker image** that was built before `@tailwindcss/typography` was added to `package.json`. The cached `npm ci` layer didn't include the new dependency.
**Resolution:** Running `docker compose build frontend` rebuilt the image with the updated dependencies. After rebuild:
- The frontend container starts correctly
- The `@plugin '@tailwindcss/typography'` directive resolves successfully
- The `.prose` typography styles are included in the compiled CSS
**No code changes required.** This is a documentation of the root cause for future reference - users experiencing this error should rebuild their Docker images.

View File

@@ -0,0 +1,35 @@
---
# nuzlocke-tracker-5svj
title: Expose admin status to frontend via user API
status: completed
type: task
priority: normal
created_at: 2026-03-21T10:06:20Z
updated_at: 2026-03-21T10:23:04Z
parent: nuzlocke-tracker-ce4o
blocked_by:
- nuzlocke-tracker-dwah
---
The frontend needs to know if the current user is an admin so it can show/hide the Admin nav link and protect admin routes client-side.
## Checklist
- [x] Add `is_admin` field to the user response schema (`/api/users/me` endpoint)
- [x] Update `AuthContext` to fetch `/api/users/me` after login and store `isAdmin` in context
- [x] Expose `isAdmin` boolean from `useAuth()` hook
- [x] Handle edge case: user exists in Supabase but not yet in local DB (first login creates user row with `is_admin=false`)
## Files to change
- `backend/src/app/schemas/user.py` or equivalent — add `is_admin` to response
- `backend/src/app/api/users.py` — ensure `/me` returns `is_admin`
- `frontend/src/contexts/AuthContext.tsx` — fetch and store admin status
## Summary of Changes
Added `isAdmin` field to frontend auth system:
- **Backend**: Added `is_admin: bool = False` to `UserResponse` schema in `backend/src/app/api/users.py`
- **Frontend**: Updated `AuthContext` to fetch `/api/users/me` after login and expose `isAdmin` boolean
- Edge case handled: `syncUserProfile` returns `false` if API call fails (new user auto-created with `is_admin=false` by backend)

View File

@@ -0,0 +1,13 @@
---
# nuzlocke-tracker-7y9z
title: Fix test failures from admin auth changes
status: completed
type: bug
priority: normal
created_at: 2026-03-21T10:33:32Z
updated_at: 2026-03-21T10:39:18Z
---
After adding require_admin to admin endpoints, tests fail:\n1. test_pokemon.py: Write endpoints return 401 because tests use unauthenticated client instead of admin client\n2. test_runs.py: mock_auth_user has id='test-user-123' which is not a valid UUID, causing ValueError in UUID(user.id)\n\nFix: add admin_override fixture, admin_client fixture, use valid UUID for mock user, update test_pokemon.py to use admin_client for write ops.
## Summary of Changes\n\n- Added `admin_override` and `admin_client` fixtures to conftest.py that override both `require_admin` and `get_current_user`\n- Changed mock user ID from `test-user-123` to a valid UUID4\n- Updated test_pokemon.py, test_games.py, and test_genlocke_boss.py to use `admin_client` for admin-protected endpoints\n- All 252 tests pass

View File

@@ -0,0 +1,32 @@
---
# nuzlocke-tracker-8vev
title: 'Crash: Frontend auth flow (login, signup, session management)'
status: completed
type: bug
priority: high
tags:
- failed
created_at: 2026-03-20T19:01:00Z
updated_at: 2026-03-20T19:21:54Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-l9xh
---
Agent crashed while working on nuzlocke-tracker-l9xh.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZErA6rXo6bi18BfjCwD7"}
```
## Context
- Bean: nuzlocke-tracker-l9xh
- Title: Frontend auth flow (login, signup, session management)
- Type: feature
## Resolution\n\nThis was an infrastructure issue (Claude API OAuth token expired), not a code bug. Continuing work on the original feature bean (nuzlocke-tracker-l9xh).

View File

@@ -0,0 +1,34 @@
---
# nuzlocke-tracker-9nmp
title: 'Crash: Crash: User Account integration'
status: completed
type: bug
priority: high
created_at: 2026-03-20T19:12:56Z
updated_at: 2026-03-20T19:18:39Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-ndpz
---
Agent crashed while working on nuzlocke-tracker-ndpz.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZEs4pUWwh8wYoPHzaGmx"}
```
## Context
- Bean: nuzlocke-tracker-ndpz
- Title: Crash: User Account integration
- Type: bug
## Resolution
This crash was caused by Claude's OAuth token expiring during an agent session. This is an environmental/infrastructure issue, not a code bug. The token has been refreshed by starting a new agent session.
No code changes required.

View File

@@ -0,0 +1,50 @@
---
# nuzlocke-tracker-9xac
title: Fix stale PostgreSQL enum causing test failures
status: completed
type: bug
priority: normal
created_at: 2026-03-21T10:27:53Z
updated_at: 2026-03-21T10:29:33Z
---
## Problem
The backend smoke tests fail with:
```
sqlalchemy.exc.DBAPIError: invalid input value for enum run_visibility: "public"
```
This happens during `Base.metadata.create_all` in the `engine` fixture (`backend/tests/conftest.py:27`).
## Root Cause
The `engine` fixture only calls `create_all` during setup and `drop_all` during teardown. If a previous test run was interrupted before teardown, the `run_visibility` PostgreSQL enum type persists in the test database with stale/incorrect values. On the next run, `create_all` (with `checkfirst=True` default) sees the enum exists and skips recreating it, but the existing enum lacks valid values, causing the `DEFAULT 'public'` to fail.
PostgreSQL native enum types are not automatically dropped with `DROP TABLE` — they require explicit `DROP TYPE`.
## Fix
In the `engine` fixture at `backend/tests/conftest.py:23-31`, add `Base.metadata.drop_all` before `create_all` to ensure a clean slate:
```python
@pytest.fixture(scope="session")
async def engine():
eng = create_async_engine(TEST_DATABASE_URL, echo=False)
async with eng.begin() as conn:
await conn.run_sync(Base.metadata.drop_all) # <-- add this
await conn.run_sync(Base.metadata.create_all)
yield eng
async with eng.begin() as conn:
await conn.run_sync(Base.metadata.drop_all)
await eng.dispose()
```
## Checklist
- [x] Add `drop_all` before `create_all` in the `engine` fixture (`backend/tests/conftest.py`)
- [x] Verify tests pass with `pytest backend/tests/test_smoke.py`
## Summary of Changes
Added `drop_all` before `create_all` in the test engine fixture to ensure stale PostgreSQL enum types are cleared before recreating the schema. This prevents test failures when a previous test run was interrupted before cleanup.

View File

@@ -0,0 +1,35 @@
---
# nuzlocke-tracker-9zpm
title: 'Crash: Backend auth middleware and JWT verification'
status: scrapped
type: bug
priority: high
created_at: 2026-03-20T19:00:53Z
updated_at: 2026-03-20T19:20:40Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-b311
---
Agent crashed while working on nuzlocke-tracker-b311.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZEr9WsspBGfYrbAM9JRc"}
```
## Context
- Bean: nuzlocke-tracker-b311
- Title: Backend auth middleware and JWT verification
- Type: task
## Reasons for Scrapping
This is not a code bug. The crash occurred because the agent's OAuth token to the Anthropic API expired during execution. This is an infrastructure/authentication issue, not an actionable bug in the nuzlocke-tracker codebase.
The original task (`nuzlocke-tracker-b311`) can proceed once its actual prerequisite (`nuzlocke-tracker-2561` - Supabase Auth setup) is completed.

View File

@@ -0,0 +1,32 @@
---
# nuzlocke-tracker-a8q0
title: 'Crash: Supabase Auth project setup and provider config'
status: scrapped
type: bug
priority: high
created_at: 2026-03-20T19:00:47Z
updated_at: 2026-03-20T19:19:24Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-2561
---
Agent crashed while working on nuzlocke-tracker-2561.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZEr97WSkvKQrZSFbN2DA"}
```
## Context
- Bean: nuzlocke-tracker-2561
- Title: Supabase Auth project setup and provider config
- Type: task
## Reasons for Scrapping
This crash was caused by an OAuth token expiration (401 authentication error), not a code bug. The agent's API credentials expired while it was running. This is an infrastructure issue that cannot be fixed by code changes - the original task simply needs to be retried with valid credentials.

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-actf
title: Combine Renovate dependency updates into single commit
status: completed
type: task
priority: normal
created_at: 2026-03-20T14:22:33Z
updated_at: 2026-03-20T14:26:38Z
---
Cherry-pick all 10 Renovate dependency update branches into develop as a single combined commit. Branches: alembic, python-dotenv, react types, react-router-dom, ruff, sqlalchemy, tailwindcss-vite, tanstack-react-query, ty, vitejs-plugin-react.

View File

@@ -0,0 +1,47 @@
---
# nuzlocke-tracker-b311
title: Backend auth middleware and JWT verification
status: completed
type: task
priority: normal
created_at: 2026-03-20T15:28:13Z
updated_at: 2026-03-20T20:11:23Z
parent: nuzlocke-tracker-d98o
blocked_by:
- nuzlocke-tracker-2561
---
Add Supabase JWT verification to the FastAPI backend. Create a reusable dependency that extracts and validates the Bearer token, resolves the current user, and provides it to endpoints. Protect all write endpoints (POST/PUT/DELETE) while leaving read endpoints open.
## Checklist
- [x] Add python-jose[cryptography] or PyJWT dependency
- [x] Create auth dependency that extracts Bearer token from Authorization header
- [x] Verify JWT against Supabase JWT secret
- [x] Create `get_current_user` dependency (returns User or None)
- [x] Create `require_auth` dependency (raises 401 if not authenticated)
- [x] Apply `require_auth` to all write endpoints (POST, PUT, DELETE)
- [x] Add tests for auth middleware (valid token, expired token, missing token)
## Summary of Changes
Added JWT authentication middleware to the FastAPI backend:
- Added `PyJWT==2.10.1` dependency to `pyproject.toml`
- Added Supabase config fields (`supabase_url`, `supabase_anon_key`, `supabase_jwt_secret`) to `core/config.py`
- Created `core/auth.py` with:
- `AuthUser` dataclass for authenticated user info
- `_extract_token()` to parse Bearer tokens from Authorization header
- `_verify_jwt()` to validate tokens against Supabase JWT secret (HS256 with "authenticated" audience)
- `get_current_user()` dependency that returns `AuthUser | None`
- `require_auth()` dependency that raises 401 if not authenticated
- Applied `require_auth` to all write endpoints (POST, PUT, PATCH, DELETE) in:
- `runs.py` (3 endpoints)
- `encounters.py` (4 endpoints)
- `genlockes.py` (7 endpoints)
- `bosses.py` (9 endpoints)
- `journal_entries.py` (3 endpoints)
- `games.py` (9 endpoints)
- Added `tests/test_auth.py` with tests for valid/expired/invalid/missing tokens
- Updated `tests/conftest.py` with `auth_client` fixture for tests requiring authentication
- Updated `test_games.py` and `test_runs.py` to use `auth_client` for write operations

View File

@@ -0,0 +1,37 @@
---
# nuzlocke-tracker-bnhh
title: User model, run ownership, and visibility migration
status: completed
type: task
priority: normal
created_at: 2026-03-20T15:28:18Z
updated_at: 2026-03-20T20:16:39Z
parent: nuzlocke-tracker-d98o
blocked_by:
- nuzlocke-tracker-2561
---
Create a User model synced from Supabase Auth. Add owner_id FK to runs table. Add visibility column (public/private) to runs with default public. Existing runs will have NULL owner_id (unowned).
## Checklist
- [x] Create User model (id matches Supabase user UUID, email, display_name, created_at)
- [x] Alembic migration: create users table
- [x] Alembic migration: add owner_id (nullable FK to users) and visibility (enum: public/private, default public) to runs table
- [x] Update Run model with owner relationship and visibility field
- [x] Create user sync endpoint or webhook (on first login, upsert user record from Supabase JWT claims)
- [x] Update RunResponse schema to include owner and visibility
- [x] Add visibility enforcement: private runs return 403 unless requester is owner
## Summary of Changes
- Created `User` model in `backend/src/app/models/user.py` with UUID primary key (matching Supabase), email, display_name, and created_at fields
- Added Alembic migrations: `n5c6d7e8f9a0_create_users_table.py` and `o6d7e8f9a0b1_add_owner_and_visibility_to_runs.py`
- Updated `NuzlockeRun` model with `owner_id` FK, `visibility` enum (public/private), and `owner` relationship
- Created `POST /users/me` endpoint for user sync on first login (upserts from JWT claims)
- Added `GET /users/me` and `PATCH /users/me` for user profile management
- Updated `RunResponse` and `RunDetailResponse` schemas with `owner` and `visibility` fields
- Implemented visibility enforcement in `list_runs`, `get_run`, `update_run`, and `delete_run`
- Private runs return 403 unless requester is owner
- Unowned runs (legacy) remain accessible to all
- Run list filters to show only public runs + user's own private runs

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-bw1m
title: Errors
status: completed
type: epic
priority: normal
created_at: 2026-03-20T15:19:43Z
updated_at: 2026-03-20T15:39:27Z
---
Container for crash and blocker beans created by Talos.

View File

@@ -0,0 +1,28 @@
---
# nuzlocke-tracker-ce4o
title: Auth-aware UI and role-based access control
status: completed
type: epic
priority: normal
created_at: 2026-03-21T10:05:52Z
updated_at: 2026-03-21T10:18:47Z
---
The app currently shows the same navigation menu to all users regardless of auth state. Logged-out users can navigate to protected pages (e.g., /runs/new, /admin) even though the backend rejects their requests. The admin interface has no role restriction — any authenticated user can access it.
## Goals
1. **Auth-aware navigation**: Menu items change based on login state (logged-out users only see public browsing options)
2. **Route protection**: Protected routes redirect to login, admin routes require admin role
3. **Admin role system**: Define which users are admins via a database field, enforce on both frontend and backend
4. **Backend admin enforcement**: Admin API endpoints (games, pokemon, evolutions, bosses, routes) require admin role, not just authentication
## Success Criteria
- [ ] Logged-out users see only: Home, Runs (public list), Genlockes, Stats, Sign In
- [x] Logged-out users cannot navigate to /runs/new, /genlockes/new, or /admin/*
- [ ] Logged-in non-admin users see: New Run, My Runs, Genlockes, Stats (no Admin link)
- [ ] Admin users see the full menu including Admin
- [x] Backend admin endpoints return 403 for non-admin authenticated users
- [ ] Admin role is stored in the `users` table (`is_admin` boolean column)
- [x] Admin status is exposed to the frontend via the user API or auth context

View File

@@ -0,0 +1,32 @@
---
# nuzlocke-tracker-cm1c
title: 'Crash: Crash: Supabase Auth project setup and provider config'
status: completed
type: bug
priority: high
created_at: 2026-03-20T19:12:59Z
updated_at: 2026-03-20T19:19:28Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-a8q0
---
Agent crashed while working on nuzlocke-tracker-a8q0.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZEs55SvwXFYVzyWoU1B9"}
```
## Context
- Bean: nuzlocke-tracker-a8q0
- Title: Crash: Supabase Auth project setup and provider config
- Type: bug
## Reasons for Scrapping
This crash was caused by an OAuth token expiration (401 authentication error), not a code bug. The agent's API credentials expired while it was running. This is an infrastructure issue that cannot be fixed by code changes - the original task simply needs to be retried with valid credentials.

View File

@@ -0,0 +1,38 @@
---
# nuzlocke-tracker-d5ht
title: 'Bug: TypeScript build fails due to optional property type mismatches in journal components'
status: completed
type: bug
priority: high
tags:
- failed
created_at: 2026-03-20T15:39:00Z
updated_at: 2026-03-20T19:17:34Z
parent: nuzlocke-tracker-bw1m
---
The frontend TypeScript build fails with 3 errors due to `exactOptionalPropertyTypes` being enabled.
## Errors
1. `JournalEntryPage.tsx:76` - `bossResults` and `bosses` props passed as `undefined` to `JournalEditor`
2. `JournalEntryPage.tsx:92` - `bossResult` and `boss` props passed as `undefined` to `JournalEntryView`
3. `RunEncounters.tsx:1170` - `bossResults` and `bosses` props passed as `undefined` to `JournalSection`
## Root Cause
Optional props in interfaces are declared as `prop?: Type` but callers pass `undefined` values from React Query hooks. With `exactOptionalPropertyTypes: true`, TypeScript requires `prop?: Type | undefined` to allow explicit `undefined` values.
## Fix
Update the interfaces in these files:
- `JournalEditor.tsx` lines 9-10: change to `bossResults?: BossResult[] | undefined` and `bosses?: BossBattle[] | undefined`
- `JournalEntryView.tsx` lines 8-9: change to `bossResult?: BossResult | null | undefined` and `boss?: BossBattle | null | undefined`
- `JournalSection.tsx` lines 9-10: change to `bossResults?: BossResult[] | undefined` and `bosses?: BossBattle[] | undefined`
## Summary of Changes
TypeScript build errors fixed by adding `| undefined` to optional property types in journal components:
- `JournalEditor.tsx`: `bossResults` and `bosses` props
- `JournalEntryView.tsx`: `bossResult` and `boss` props
- `JournalSection.tsx`: `bossResults` and `bosses` props

View File

@@ -0,0 +1,69 @@
---
# nuzlocke-tracker-d68l
title: 'Frontend: Journal entry editor and list view'
status: completed
type: task
priority: normal
created_at: 2026-03-20T15:15:55Z
updated_at: 2026-03-20T15:37:39Z
parent: nuzlocke-tracker-mz16
blocked_by:
- nuzlocke-tracker-vmto
---
Create the frontend UI for writing and viewing journal entries.
## Design Decisions
- Plain markdown textarea (no WYSIWYG)
- Images via markdown URL syntax (`![alt](url)`)
- Blank slate — no templates
- Private only (no sharing UI)
## Checklist
- [x] Add `JournalEntry` TypeScript types to `frontend/src/types/`
- [x] Create API client functions for journal CRUD
- [x] Create `JournalList` component — chronological list of entries for a run
- Show title, date, preview snippet, and linked boss (if any)
- Link each entry to its detail/edit view
- [x] Create `JournalEditor` component — markdown textarea with title input
- Optional boss result selector dropdown (link entry to a boss battle)
- Preview tab to render markdown
- Save and delete actions
- [x] Create `JournalEntryView` component — rendered markdown display
- [x] Add journal section/tab to the run detail page
- [x] Add route for journal entry detail/edit view
## Summary of Changes
Implemented the frontend journal entry editor and list view with the following components:
**Types created:**
- `frontend/src/types/journal.ts` - TypeScript types for JournalEntry, CreateJournalEntryInput, UpdateJournalEntryInput
**API client created:**
- `frontend/src/api/journal.ts` - CRUD functions for journal entries
- `frontend/src/hooks/useJournal.ts` - React Query hooks for journal data fetching and mutations
**Components created:**
- `frontend/src/components/journal/JournalList.tsx` - Chronological list of entries with title, date, preview snippet, and linked boss display
- `frontend/src/components/journal/JournalEditor.tsx` - Markdown textarea with title input, boss result selector, write/preview tabs, save/delete actions
- `frontend/src/components/journal/JournalEntryView.tsx` - Rendered markdown display with entry metadata
- `frontend/src/components/journal/JournalSection.tsx` - Wrapper component for embedding in RunEncounters page
**Pages created:**
- `frontend/src/pages/JournalEntryPage.tsx` - Standalone page for viewing/editing a single journal entry
**Modified files:**
- `frontend/src/types/index.ts` - Added journal type exports
- `frontend/src/pages/index.ts` - Added JournalEntryPage export
- `frontend/src/App.tsx` - Added route `/runs/:runId/journal/:entryId`
- `frontend/src/pages/RunEncounters.tsx` - Added Encounters/Journal tab navigation with JournalSection integration
**Features:**
- Tab navigation in run detail page to switch between Encounters and Journal views
- Create new journal entries with markdown content and optional boss battle linking
- Edit and delete existing entries
- Write/Preview toggle in editor
- Rendered markdown display with full prose styling

View File

@@ -1,11 +1,11 @@
--- ---
# nuzlocke-tracker-d98o # nuzlocke-tracker-d98o
title: User Account integration title: User Account integration
status: draft status: completed
type: epic type: epic
priority: deferred priority: normal
created_at: 2026-02-04T16:17:01Z created_at: 2026-02-04T16:17:01Z
updated_at: 2026-02-10T12:05:43Z updated_at: 2026-03-20T20:16:30Z
blocking: blocking:
- nuzlocke-tracker-0jec - nuzlocke-tracker-0jec
--- ---
@@ -35,10 +35,10 @@ Enable user accounts so players can track multiple Nuzlocke runs, access them fr
- [ ] Delete account option (with data export) - [ ] Delete account option (with data export)
### Multi-Run Support ### Multi-Run Support
- [ ] Associate runs with user accounts - [x] Associate runs with user accounts
- [ ] Users can have unlimited runs - [ ] Users can have unlimited runs
- [ ] Migrate any existing local/anonymous runs to account - [ ] Migrate any existing local/anonymous runs to account
- [ ] Run visibility settings (private by default) - [x] Run visibility settings (public by default, can be set to private)
### Runs Overview Page ### Runs Overview Page
- [ ] Dashboard showing all user's runs - [ ] Dashboard showing all user's runs
@@ -76,3 +76,17 @@ Enable user accounts so players can track multiple Nuzlocke runs, access them fr
- Social features (sharing runs, leaderboards) - Social features (sharing runs, leaderboards)
- Team collaboration - Team collaboration
- Public run profiles - Public run profiles
## Decisions (resolved 2026-03-20)
- **Auth provider:** Supabase Auth (third-party, self-hostable, AWS-compatible)
- **Social login:** Google + Discord
- **Run migration:** Existing runs stay unowned, admin assigns manually post-signup
- **Auth scope:** Write operations require auth; per-run public/private visibility toggle
- **Editor for journal (related):** Plain markdown
## Execution Order
1. `nuzlocke-tracker-2561` — Supabase project setup (unblocked)
2. `nuzlocke-tracker-b311` + `nuzlocke-tracker-bnhh` + `nuzlocke-tracker-l9xh` — Backend auth, user model, frontend auth (parallel, after setup)
3. `nuzlocke-tracker-k1l1` — Run ownership + visibility (after all above)

View File

@@ -0,0 +1,43 @@
---
# nuzlocke-tracker-dwah
title: Add is_admin column to users table
status: completed
type: task
priority: normal
created_at: 2026-03-21T10:06:19Z
updated_at: 2026-03-21T10:10:38Z
parent: nuzlocke-tracker-ce4o
---
Add an `is_admin` boolean column (default `false`) to the `users` table via an Alembic migration.
## Checklist
- [x] Create Alembic migration adding `is_admin: Mapped[bool]` column with `server_default="false"`
- [x] Update `User` model in `backend/src/app/models/user.py`
- [x] Run migration and verify column exists
- [x] Seed a test admin user (or document how to set `is_admin=true` via SQL)
## Files to change
- `backend/src/app/models/user.py` — add `is_admin` field
- `backend/src/app/alembic/versions/` — new migration
## Summary of Changes
Added `is_admin` boolean column to the `users` table:
- **Migration**: `p7e8f9a0b1c2_add_is_admin_to_users.py` adds the column with `server_default='false'`
- **Model**: Updated `User` model with `is_admin: Mapped[bool]` field
### Setting admin via SQL
To promote a user to admin:
```sql
UPDATE users SET is_admin = true WHERE email = 'admin@example.com';
```
Or by user ID:
```sql
UPDATE users SET is_admin = true WHERE id = '<uuid>';
```

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

@@ -0,0 +1,13 @@
---
# nuzlocke-tracker-elcn
title: Add Supabase auth config to production Docker setup
status: completed
type: task
priority: normal
created_at: 2026-03-21T11:07:01Z
updated_at: 2026-03-21T11:08:19Z
---
Update docker-compose.prod.yml and Dockerfile.prod to support Supabase Cloud auth in production.\n\n- [ ] Add SUPABASE_JWT_SECRET env var to backend in docker-compose.prod.yml\n- [ ] Add build args for VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY, VITE_API_URL to frontend in docker-compose.prod.yml\n- [ ] Add ARG/ENV lines to Dockerfile.prod so Vite can pick up env vars at build time\n- [ ] Update .env.example with production notes
## Summary of Changes\n\nUpdated 3 files to support Supabase Cloud auth in production:\n- `docker-compose.prod.yml`: added SUPABASE_JWT_SECRET to backend, added build args to frontend\n- `frontend/Dockerfile.prod`: added ARG lines so Vite inlines Supabase config at build time\n- `.github/workflows/deploy.yml`: pass build args from secrets when building frontend image\n\nPR: #69

View File

@@ -0,0 +1,35 @@
---
# nuzlocke-tracker-evc8
title: 'Crash: Crash: Backend auth middleware and JWT verification'
status: completed
type: bug
priority: high
created_at: 2026-03-20T19:13:03Z
updated_at: 2026-03-20T19:20:46Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-9zpm
---
Agent crashed while working on nuzlocke-tracker-9zpm.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZEs5LCgi1Zh6MdRencGW"}
```
## Context
- Bean: nuzlocke-tracker-9zpm
- Title: Crash: Backend auth middleware and JWT verification
- Type: bug
## Reasons for Scrapping
This is not a code bug. The crash occurred because the agent's OAuth token to the Anthropic API expired during execution. This is an infrastructure/authentication issue, not an actionable bug in the nuzlocke-tracker codebase.
The original task (`nuzlocke-tracker-b311`) can proceed once its actual prerequisite (`nuzlocke-tracker-2561` - Supabase Auth setup) is completed.

View File

@@ -0,0 +1,49 @@
---
# nuzlocke-tracker-f4d0
title: Add require_admin dependency and protect admin endpoints
status: completed
type: task
priority: normal
created_at: 2026-03-21T10:06:19Z
updated_at: 2026-03-21T10:15:14Z
parent: nuzlocke-tracker-ce4o
blocked_by:
- nuzlocke-tracker-dwah
---
Add a `require_admin` FastAPI dependency that checks the `is_admin` column on the `users` table. Apply it to all admin-facing API endpoints (games CRUD, pokemon CRUD, evolutions CRUD, bosses CRUD, route CRUD).
## Checklist
- [x] Add `require_admin` dependency in `backend/src/app/core/auth.py` that:
- Requires authentication (reuses `require_auth`)
- Looks up the user in the `users` table by `AuthUser.id`
- Returns 403 if `is_admin` is not `True`
- [x] Apply `require_admin` to write endpoints in: `games.py`, `pokemon.py`, `evolutions.py`, `bosses.py` (all POST/PUT/PATCH/DELETE)
- [x] Keep read endpoints (GET) accessible to all authenticated users
- [x] Add tests for 403 response when non-admin user hits admin endpoints
## Files to change
- `backend/src/app/core/auth.py` — add `require_admin`
- `backend/src/app/api/games.py` — replace `require_auth` with `require_admin` on mutations
- `backend/src/app/api/pokemon.py` — same
- `backend/src/app/api/evolutions.py` — same
- `backend/src/app/api/bosses.py` — same
## Summary of Changes
Added `require_admin` FastAPI dependency to `backend/src/app/core/auth.py`:
- Depends on `require_auth` (returns 401 if not authenticated)
- Looks up user in `users` table by UUID
- Returns 403 if user not found or `is_admin` is not True
Applied `require_admin` to all admin-facing write endpoints:
- `games.py`: POST/PUT/DELETE for games and routes
- `pokemon.py`: POST/PUT/DELETE for pokemon and route encounters
- `evolutions.py`: POST/PUT/DELETE for evolutions
- `bosses.py`: POST/PUT/DELETE for game-scoped boss operations (run-scoped endpoints kept with `require_auth`)
Added tests in `test_auth.py`:
- Unit tests for `require_admin` (admin user, non-admin user, user not in DB)
- Integration tests for admin endpoint access (403 for non-admin, 201 for admin)

View File

@@ -0,0 +1,32 @@
---
# nuzlocke-tracker-fbcs
title: 'Crash: Add detailed boss pokemon information (ability, item, nature, moveset)'
status: completed
type: bug
priority: high
tags:
- failed
created_at: 2026-03-20T19:01:15Z
updated_at: 2026-03-20T19:37:36Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-nvd6
---
Agent crashed while working on nuzlocke-tracker-nvd6.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZErBAtQPvCEsAZyGSYmc"}
```
## Context
- Bean: nuzlocke-tracker-nvd6
- Title: Add detailed boss pokemon information (ability, item, nature, moveset)
- Type: feature
## Resolution\n\nThe crash was caused by OAuth token expiration. Work completed via nuzlocke-tracker-n926.

View File

@@ -0,0 +1,34 @@
---
# nuzlocke-tracker-gez0
title: 'Crash: User model, run ownership, and visibility migration'
status: scrapped
type: bug
priority: high
tags:
- failed
created_at: 2026-03-20T19:00:55Z
updated_at: 2026-03-20T19:21:18Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-bnhh
---
Agent crashed while working on nuzlocke-tracker-bnhh.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZEr9igHnUG4eR8RFWUEj"}
```
## Context
- Bean: nuzlocke-tracker-bnhh
- Title: User model, run ownership, and visibility migration
- Type: task
## Reasons for Scrapping
This crash was caused by an expired OAuth token during agent execution - a transient session management issue, not a code bug. The underlying task (nuzlocke-tracker-bnhh) remains blocked by nuzlocke-tracker-2561 (Supabase setup) and can be resumed once that prerequisite is complete.

View File

@@ -0,0 +1,38 @@
---
# nuzlocke-tracker-h205
title: Auth-aware navigation menu
status: completed
type: task
priority: normal
created_at: 2026-03-21T10:06:20Z
updated_at: 2026-03-21T10:22:34Z
parent: nuzlocke-tracker-ce4o
blocked_by:
- nuzlocke-tracker-5svj
---
Update the Layout component to show different nav links based on auth state and admin role.
## Checklist
- [x] Replace static \`navLinks\` array with dynamic links based on \`useAuth()\` state
- [x] **Logged out**: Home, Runs, Genlockes, Stats (no New Run, no Admin)
- [x] **Logged in (non-admin)**: New Run, My Runs, Genlockes, Stats
- [x] **Logged in (admin)**: New Run, My Runs, Genlockes, Stats, Admin
- [x] Update both desktop and mobile nav (they share the same \`navLinks\` array, so this should be automatic)
- [x] Verify menu updates reactively on login/logout
## Files to change
- \`frontend/src/components/Layout.tsx\` — make \`navLinks\` dynamic based on auth state
## Summary of Changes
- Removed static `navLinks` array from module scope
- Added dynamic `navLinks` computation inside `Layout` component using `useMemo`
- Navigation now depends on `user` and `isAdmin` from `useAuth()`:
- Logged out: Home, Runs, Genlockes, Stats
- Logged in (non-admin): New Run, My Runs, Genlockes, Stats
- Logged in (admin): New Run, My Runs, Genlockes, Stats, Admin
- Updated `isActive` function to handle Home route (`/`) correctly
- Both desktop and mobile nav automatically use the same dynamic `navLinks` array

View File

@@ -0,0 +1,28 @@
---
# nuzlocke-tracker-h8zw
title: 'Crash: Hide edit controls for non-owners in frontend'
status: completed
type: bug
priority: high
created_at: 2026-03-21T12:49:42Z
updated_at: 2026-03-21T12:50:37Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-i2va
---
Bean was found in 'in-progress' status on startup but no agent was running.
This likely indicates a crash or unexpected termination.
Manual review required before retrying.
Bean: nuzlocke-tracker-i2va
Title: Hide edit controls for non-owners in frontend
## Summary of Changes
Investigation shows commit `3bd24fc` already implemented all required changes:
- Added `useAuth` and `canEdit = isOwner` to both `RunEncounters.tsx` and `RunDashboard.tsx`
- All mutation UI guarded behind `canEdit` (Log Shiny/Egg, End Run, Randomize All, HoF Edit, Boss Battle, route clicks, visibility, naming scheme)
- Read-only banners displayed for non-owners
- No code changes needed — work was already complete

View File

@@ -0,0 +1,55 @@
---
# nuzlocke-tracker-he1n
title: Add local GoTrue container for dev auth testing
status: completed
type: feature
priority: normal
created_at: 2026-03-20T20:57:04Z
updated_at: 2026-03-21T10:07:40Z
---
## Problem
The current local Docker setup has no auth service — Supabase is only available as a cloud service. This means:
- Auth flows (login, signup, JWT verification) cannot be tested locally
- The frontend's `supabase.ts` falls back to a stub client (`http://localhost:54321`) that doesn't actually exist
- Backend tests mock auth entirely via `conftest.py` fixtures, so integration testing of the full auth flow is impossible
## Approach
Add a **GoTrue** container (Supabase's auth engine) to the local `docker-compose.yml`. GoTrue is a standalone Go service that provides the same auth API that Supabase cloud exposes. This gives us local email/password auth without needing Discord/Google OAuth providers configured.
**Architecture (Option 3):**
- **Local dev**: Own PostgreSQL + GoTrue container → full auth testing
- **Production**: Own PostgreSQL + Supabase cloud for auth (handles Discord/Google OAuth)
GoTrue will use the existing `db` PostgreSQL container, creating its own `auth` schema (separate from the app's tables managed by Alembic).
## Files to modify
- `docker-compose.yml` — add GoTrue service, configure env vars
- `.env.example` — add GoTrue-specific local defaults
- `frontend/src/lib/supabase.ts` — point to local GoTrue when in dev mode
- `backend/src/app/core/config.py` — may need local JWT secret default
- `README.md` or docs — document local auth setup
## Checklist
- [x] Research GoTrue Docker image and required env vars (JWT secret, DB connection, SMTP disabled, etc.)
- [x] Add `gotrue` service to `docker-compose.yml` using the existing `db` container
- [x] Configure GoTrue to use the same PostgreSQL with its own `auth` schema
- [x] Set local JWT secret (e.g. `super-secret-jwt-token-for-local-dev`) shared between GoTrue and the backend
- [x] Update `.env.example` with local GoTrue defaults (`SUPABASE_URL=http://localhost:9999`, local JWT secret, local anon key)
- [x] Update `frontend/src/lib/supabase.ts` to use `http://localhost:9999` in dev (GoTrue's local port)
- [x] Verify backend JWT verification works with GoTrue-issued tokens (same HS256 + shared secret)
- [ ] Test email/password signup and login flow end-to-end locally
- [x] Verify OAuth buttons gracefully handle missing providers in local dev (show disabled state or helpful message)
- [x] Update `docker-compose.yml` healthcheck for GoTrue readiness
- [x] Document the local auth setup in README or contributing guide
## Notes
- GoTrue image: `supabase/gotrue` (official, regularly updated)
- GoTrue needs: `GOTRUE_DB_DATABASE_URL`, `GOTRUE_JWT_SECRET`, `GOTRUE_SITE_URL`, `GOTRUE_EXTERNAL_EMAIL_ENABLED=true`, `GOTRUE_MAILER_AUTOCONFIRM=true` (skip email verification locally)
- The `anon` key for local dev can be a static JWT signed with the local secret (Supabase docs show how to generate this)
- Production docker-compose.prod.yml is NOT modified — it continues using Supabase cloud via env vars

View File

@@ -0,0 +1,34 @@
---
# nuzlocke-tracker-jmkf
title: 'Crash: Run ownership assignment and visibility toggle'
status: completed
type: bug
priority: high
created_at: 2026-03-20T19:01:04Z
updated_at: 2026-03-20T19:28:57Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-k1l1
---
Agent crashed while working on nuzlocke-tracker-k1l1.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZErAP1dbTeqSqRccKWyb"}
```
## Context
- Bean: nuzlocke-tracker-k1l1
- Title: Run ownership assignment and visibility toggle
- Type: feature
## Resolution
This crash was caused by OAuth token expiration during agent execution, not a code bug. The token expired mid-session, causing the API to return a 401 authentication error. No code changes are required.
The original feature (nuzlocke-tracker-k1l1) remains blocked by its dependencies (b311 and bnhh).

View File

@@ -0,0 +1,40 @@
---
# nuzlocke-tracker-k1l1
title: Run ownership assignment and visibility toggle
status: completed
type: feature
priority: normal
created_at: 2026-03-20T15:28:27Z
updated_at: 2026-03-20T20:21:01Z
parent: nuzlocke-tracker-d98o
blocked_by:
- nuzlocke-tracker-b311
- nuzlocke-tracker-bnhh
- nuzlocke-tracker-l9xh
---
Wire up run ownership in the UI. New runs created by logged-in users are automatically assigned to them. Add a visibility toggle (public/private) to run settings. Update run list to show owned runs and public runs separately.
## Checklist
- [x] Auto-assign owner_id when creating a new run (if authenticated)
- [x] Add visibility toggle to run settings/edit page
- [x] Update run list view: show 'My Runs' section for authenticated users
- [x] Show public/private badge on run cards
- [x] Enforce visibility on frontend (don't show edit controls for non-owned runs)
- [x] Admin script/endpoint to assign existing unowned runs to a user by ID
## Summary of Changes
### Frontend
- Updated `NuzlockeRun` type to include `visibility` (public/private) and `owner` fields
- Updated `CreateRunInput` and `UpdateRunInput` to support visibility setting
- **RunList.tsx**: Added "My Runs" and "Public Runs" sections for authenticated users, with private badge on owned runs
- **RunDashboard.tsx**: Added visibility toggle dropdown in settings, restricted edit controls to run owners
- **NewRun.tsx**: Added visibility selector during run creation
### Backend
- Created `scripts/assign_unowned_runs.py` admin script to migrate existing unowned runs to a user
### Notes
- The backend already supported auto-assigning `owner_id` on run creation (from blocking bean)
- Unowned runs (legacy) remain editable by anyone for backwards compatibility

View File

@@ -0,0 +1,60 @@
---
# nuzlocke-tracker-kix5
title: Fix e2e tests after boss feature changes
status: scrapped
type: bug
priority: normal
created_at: 2026-03-20T19:19:31Z
updated_at: 2026-03-20T20:49:19Z
blocked_by:
- nuzlocke-tracker-neqv
---
The e2e tests (accessibility + mobile) are failing because the test infrastructure hasn't been updated since the boss feature, journal, and admin pages were added.
## Problems
### 1. Missing pages in test coverage
Both `accessibility.spec.ts` and `mobile.spec.ts` share a hardcoded page list that is missing several routes added since the tests were written:
**Missing from page list:**
- `runs/:runId/journal/:entryId` — Journal entry page (requires journal fixture)
- `admin/games/:gameId` — Admin game detail page (requires game fixture ID)
- `admin/games/:gameId/routes/:routeId` — Admin route detail page (requires route fixture ID)
- `admin/runs` — Admin runs page
- `admin/genlockes` — Admin genlockes page
- `admin/genlockes/:genlockeId` — Admin genlocke detail page (requires genlocke fixture ID)
### 2. Missing test fixtures/seeding
The global-setup seeds runs, encounters, and genlockes but does **not** seed:
- Boss battles (via `/games/{game_id}/bosses`)
- Boss results (via `/runs/{run_id}/boss-results`)
- Journal entries (via journal API)
- Version groups (required for boss battles to work)
The RunEncounters page now renders a boss battle section, which likely makes API calls that fail or produce unexpected DOM, causing accessibility or layout violations.
### 3. Shared page list duplication
Both spec files duplicate the same page list — should be extracted to a shared constant in `fixtures.ts`.
## Checklist
- [ ] Update `fixtures.ts` to export a shared page list with all current routes
- [ ] Add boss battle seeding to `global-setup.ts` (create boss via API after game seed)
- [ ] Add boss result seeding to `global-setup.ts` (create result for the test run)
- [ ] Add journal entry seeding to `global-setup.ts` (create entry for the test run)
- [ ] Add new fixture IDs to `Fixtures` interface (journalEntryId, routeId, bossId, etc.)
- [ ] Update `accessibility.spec.ts` to use shared page list
- [ ] Update `mobile.spec.ts` to use shared page list
- [ ] Run e2e tests locally and verify they pass
- [ ] Fix any new accessibility or layout violations on boss/journal pages
## Files to modify
- `frontend/e2e/fixtures.ts`
- `frontend/e2e/global-setup.ts`
- `frontend/e2e/accessibility.spec.ts`
- `frontend/e2e/mobile.spec.ts`
## Notes
- The boss feature is still in progress (epic `nuzlocke-tracker-neqv`). This bean should be worked on after the boss feature is finalized to avoid churn.
- Version groups must exist for boss battle API calls to work — check if `app.seeds` already seeds them.

View File

@@ -0,0 +1,41 @@
---
# nuzlocke-tracker-l9xh
title: Frontend auth flow (login, signup, session management)
status: completed
type: feature
priority: normal
tags:
- failed
created_at: 2026-03-20T15:28:24Z
updated_at: 2026-03-20T19:26:16Z
parent: nuzlocke-tracker-d98o
blocked_by:
- nuzlocke-tracker-2561
---
Add Supabase JS client to the frontend. Build login and signup pages with email/password and social login buttons (Google, Discord). Implement auth context/provider for session management, protected route wrapper, and auth-aware API client that attaches Bearer tokens.
## Checklist
- [x] Install @supabase/supabase-js
- [x] Create Supabase client singleton with env vars
- [x] Create AuthContext/AuthProvider with session state, login, logout, signup methods
- [x] Build login page (email/password form + Google/Discord buttons)
- [x] Build signup page (email/password form + Google/Discord buttons)
- [x] Add auth callback route for OAuth redirects
- [x] Create ProtectedRoute wrapper component
- [x] Update API client to attach Authorization header when user is logged in
- [x] Add user menu (avatar/email, logout) to header when authenticated
- [x] Handle token refresh automatically via Supabase client
## Summary of Changes
- Installed @supabase/supabase-js package
- Created Supabase client singleton at `frontend/src/lib/supabase.ts`
- Created AuthContext/AuthProvider at `frontend/src/contexts/AuthContext.tsx` with session state, login, logout, signup, and OAuth methods
- Created Login page (`frontend/src/pages/Login.tsx`) with email/password form and Google/Discord OAuth buttons
- Created Signup page (`frontend/src/pages/Signup.tsx`) with email/password form and Google/Discord OAuth buttons
- Created auth callback route (`frontend/src/pages/AuthCallback.tsx`) for OAuth redirects
- Created ProtectedRoute component (`frontend/src/components/ProtectedRoute.tsx`)
- Updated API client to attach Authorization header automatically when user is logged in
- Added UserMenu component to Layout header showing avatar/email and logout button
- Token refresh is handled automatically by Supabase JS client

View File

@@ -0,0 +1,34 @@
---
# nuzlocke-tracker-ldyi
title: 'Crash: Crash: Run ownership assignment and visibility toggle'
status: completed
type: bug
priority: high
created_at: 2026-03-20T19:13:16Z
updated_at: 2026-03-20T19:29:03Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-jmkf
---
Agent crashed while working on nuzlocke-tracker-jmkf.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZEs6J7hxAdJni9KoTLcJ"}
```
## Context
- Bean: nuzlocke-tracker-jmkf
- Title: Crash: Run ownership assignment and visibility toggle
- Type: bug
## Resolution
This crash was caused by OAuth token expiration during agent execution, not a code bug. The token expired mid-session, causing the API to return a 401 authentication error. No code changes are required.
The original feature (nuzlocke-tracker-k1l1) remains blocked by its dependencies (b311 and bnhh).

View File

@@ -0,0 +1,13 @@
---
# nuzlocke-tracker-liz1
title: Fix frontend Layout tests for auth-aware navigation
status: completed
type: bug
priority: normal
created_at: 2026-03-21T10:41:51Z
updated_at: 2026-03-21T10:42:30Z
---
Layout.test.tsx fails because nav links are now auth-dependent. Tests expect logged-in admin links but render with no user. Fix by mocking useAuth.
## Summary of Changes\n\nMocked `useAuth` in Layout.test.tsx instead of using real AuthProvider. Added separate test groups for logged-out and logged-in-as-admin states, verifying correct nav links appear in each. All 118 frontend tests pass.

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

@@ -0,0 +1,32 @@
---
# nuzlocke-tracker-mg99
title: 'Crash: Add detailed boss battle information'
status: scrapped
type: bug
priority: high
created_at: 2026-03-20T19:01:08Z
updated_at: 2026-03-20T19:29:55Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-neqv
---
Agent crashed while working on nuzlocke-tracker-neqv.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZErAh36SY2uCVFvs6pe8"}
```
## Context
- Bean: nuzlocke-tracker-neqv
- Title: Add detailed boss battle information
- Type: epic
## Reasons for Scrapping
This is a crash report bean created when a previous agent session expired due to OAuth token timeout. This is a transient infrastructure issue, not a code bug. The original work is tracked in the child beans of nuzlocke-tracker-neqv.

View File

@@ -0,0 +1,32 @@
---
# nuzlocke-tracker-mygi
title: 'Crash: Crash: Add detailed boss battle information'
status: completed
type: bug
priority: high
created_at: 2026-03-20T19:13:19Z
updated_at: 2026-03-20T19:30:01Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-mg99
---
Agent crashed while working on nuzlocke-tracker-mg99.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZEs6XKwjZQ4HoyPLXVxp"}
```
## Context
- Bean: nuzlocke-tracker-mg99
- Title: Crash: Add detailed boss battle information
- Type: bug
## Reasons for Scrapping
This is a crash report bean created when a previous agent session expired due to OAuth token timeout. This is a transient infrastructure issue, not a code bug. The original work is tracked in the child beans of nuzlocke-tracker-neqv.

View File

@@ -0,0 +1,38 @@
---
# nuzlocke-tracker-mz16
title: Session Journal / Blog Posts
status: completed
type: epic
priority: normal
created_at: 2026-02-19T07:43:05Z
updated_at: 2026-03-20T15:37:21Z
---
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.
## Decisions
- **Editor:** Plain markdown textarea with preview
- **Images:** Via markdown URL syntax (no uploads)
- **Run linkage:** Entries belong to a run, optionally linked to a boss battle
- **Visibility:** Private only (no sharing — deferred until user accounts exist)
- **Templates:** Blank slate — no templates
## Success Criteria
- [x] Backend: journal entries CRUD API is complete (`nuzlocke-tracker-vmto`)
- [x] Frontend: journal list, editor, and view are functional (`nuzlocke-tracker-d68l`)

View File

@@ -0,0 +1,30 @@
---
# nuzlocke-tracker-n926
title: 'Crash: Crash: Add detailed boss pokemon information (ability, item, nature, moveset)'
status: completed
type: bug
priority: high
created_at: 2026-03-20T19:13:24Z
updated_at: 2026-03-20T19:37:57Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-fbcs
---
Agent crashed while working on nuzlocke-tracker-fbcs.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZEs6sYsQqU6dmmpwcmTM"}
```
## Context
- Bean: nuzlocke-tracker-fbcs
- Title: Crash: Add detailed boss pokemon information (ability, item, nature, moveset)
- Type: bug
## Resolution\n\nThe crash was caused by OAuth token expiration. Resumed work and completed the original feature (nuzlocke-tracker-nvd6).

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-na3s
title: Allow multiple games per region in Custom genlocke
status: completed
type: feature
priority: normal
created_at: 2026-03-17T12:29:57Z
updated_at: 2026-03-17T12:32:05Z
---
Users want to run multiple games from the same region in a genlocke (e.g., Black + Black 2 in Unova). Change availableRegions computation so custom mode shows all regions, and add a subtle indicator for already-used regions in AddLegDropdown.

View File

@@ -0,0 +1,36 @@
---
# nuzlocke-tracker-ndpz
title: 'Crash: User Account integration'
status: completed
type: bug
priority: high
tags:
- failed
created_at: 2026-03-20T19:00:42Z
updated_at: 2026-03-20T19:18:25Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-d98o
---
Agent crashed while working on nuzlocke-tracker-d98o.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZEr8m1A9hiKCVyBgkCJB"}
```
## Context
- Bean: nuzlocke-tracker-d98o
- Title: User Account integration
- Type: epic
## Resolution
This crash was caused by Claude's OAuth token expiring during an agent session. This is an environmental/infrastructure issue, not a code bug. The token has been refreshed by starting a new agent session.
No code changes required.

View File

@@ -0,0 +1,17 @@
---
# nuzlocke-tracker-neqv
title: Add detailed boss battle information
status: completed
type: epic
priority: low
created_at: 2026-02-08T11:21:22Z
updated_at: 2026-03-20T20:25:11Z
---
Enhance boss battles with more detailed information. Split into child beans:
## Success Criteria
- [x] Moves and abilities tables seeded (names + introduced generation)
- [x] Boss pokemon entries support ability, held item, nature, and moveset
- [x] Boss battle results can capture a team snapshot
- [ ] (Future) Moves/abilities enriched with generation-specific stats

View File

@@ -0,0 +1,53 @@
---
# nuzlocke-tracker-nvd6
title: Add detailed boss pokemon information (ability, item, nature, moveset)
status: completed
type: feature
priority: low
tags:
- failed
created_at: 2026-03-20T15:11:50Z
updated_at: 2026-03-20T19:37:18Z
parent: nuzlocke-tracker-neqv
blocked_by:
- nuzlocke-tracker-vc5o
---
Add optional detail fields to boss pokemon entries: ability, held item, nature, and moveset (up to 4 moves).
## Approach
- Ability and moves reference the seeded `moves`/`abilities` tables via FK (hybrid approach — names only, no gen-specific stats yet)
- Held item and nature stored as plain strings (items table can come later; natures are static)
## Checklist
- [x] **Migration**: Add columns to `boss_pokemon``ability_id` (FK|null), `held_item` (str|null), `nature` (str|null), `move1_id``move4_id` (FK|null)
- [x] **Model**: Update `BossPokemon` in `backend/src/app/models/boss_pokemon.py` with relationships
- [x] **Schemas**: Update `BossPokemonResponse` and `BossPokemonInput` in `backend/src/app/schemas/boss.py`
- [x] **Admin UI**: Add fields to `BossTeamEditor.tsx` (ability autocomplete, item input, nature dropdown, 4 move autocomplete inputs)
- [x] **Frontend types**: Update `BossPokemon` in `frontend/src/types/game.ts` and admin input types
- [x] **Frontend display**: Show details on boss cards in `RunEncounters.tsx` and `BossDefeatModal.tsx`
- [~] **Seed data**: (deferred) Update bulk import format to support new fields
## Dependencies
- Requires moves and abilities tables to be seeded first
## Summary of Changes
### Backend
- Created migration `l3a4b5c6d7e8_add_boss_pokemon_details.py` adding `ability_id`, `held_item`, `nature`, `move1_id`-`move4_id` columns
- Updated `BossPokemon` model with relationships to `Ability` and `Move`
- Updated `BossPokemonResponse` and `BossPokemonInput` schemas with detail fields
- Created `/moves` and `/abilities` API endpoints for autocomplete search
- Updated `set_boss_team` endpoint to handle new fields
- Added eager loading for ability/moves in boss queries
### Frontend
- Added `MoveRef` and `AbilityRef` types to game.ts
- Extended `BossPokemon` type with detail fields
- Extended `BossPokemonInput` admin type
- Created `MoveSelector` and `AbilitySelector` autocomplete components
- Updated `BossTeamEditor` with expandable detail section per pokemon
- Updated `BossTeamPreview` and `BossDefeatModal` to display details
### Deferred
- Bulk import format for seed data not updated (optional fields work with existing format)

View File

@@ -0,0 +1,30 @@
---
# nuzlocke-tracker-pl1m
title: 'Crash: Crash: Frontend auth flow (login, signup, session management)'
status: completed
type: bug
priority: high
created_at: 2026-03-20T19:13:10Z
updated_at: 2026-03-20T19:27:57Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-8vev
---
Agent crashed while working on nuzlocke-tracker-8vev.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZEs5tdpug65ZR5M3DSQS"}
```
## Context
- Bean: nuzlocke-tracker-8vev
- Title: Crash: Frontend auth flow (login, signup, session management)
- Type: bug
## Resolution\n\nThis was an infrastructure issue (Claude API OAuth token expired), not a code bug. Continuing work on the original feature bean (nuzlocke-tracker-l9xh).

View File

@@ -0,0 +1,24 @@
---
# nuzlocke-tracker-t90q
title: 'Crash: Backend: Journal entries model, API, and migration'
status: completed
type: bug
priority: high
created_at: 2026-03-20T15:30:02Z
updated_at: 2026-03-20T15:39:13Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-vmto
---
Bean was found in 'in-progress' status on startup but no agent was running.
This likely indicates a crash or unexpected termination.
Manual review required before retrying.
Bean: nuzlocke-tracker-vmto
Title: Backend: Journal entries model, API, and migration
## Resolution
The underlying bean (nuzlocke-tracker-vmto) was already completed before the crash was detected. All backend work for journal entries is implemented and functional. A separate bug bean (nuzlocke-tracker-d5ht) was created for frontend TypeScript errors discovered during review.

View File

@@ -0,0 +1,30 @@
---
# nuzlocke-tracker-ueub
title: 'Crash: Add team snapshot to boss battle results'
status: completed
type: bug
priority: high
tags:
- failed
created_at: 2026-03-20T19:01:23Z
updated_at: 2026-03-20T19:41:51Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-xd9j
---
Agent crashed while working on nuzlocke-tracker-xd9j.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZErBmcConDqezwzK8kaP"}
```
## Context
- Bean: nuzlocke-tracker-xd9j
- Title: Add team snapshot to boss battle results
- Type: feature

View File

@@ -0,0 +1,53 @@
---
# nuzlocke-tracker-vc5o
title: Seed moves and abilities tables (names + introduced generation)
status: completed
type: task
priority: normal
created_at: 2026-03-20T15:11:44Z
updated_at: 2026-03-20T15:25:11Z
parent: nuzlocke-tracker-neqv
---
Create and seed `moves` and `abilities` tables with name and generation data using the hybrid approach.
## Approach
Seed move/ability **names** with `introduced_gen` only. Full generation-specific stats (power, accuracy, type changes, effect text) will be added in a follow-up bean.
This enables FK references and autocomplete from boss pokemon fields without blocking on a full moves database.
## Checklist
- [x] **Migration**: Create `moves` table (`id`, `name`, `introduced_gen`, `type` optional)
- [x] **Migration**: Create `abilities` table (`id`, `name`, `introduced_gen`)
- [x] **Models**: Create `Move` and `Ability` SQLAlchemy models
- [x] **Seed data**: Seed all move names with introduced generation (source: PokeAPI or Bulbapedia)
- [x] **Seed data**: Seed all ability names with introduced generation
- [x] **Seed script**: Add to existing seeding pipeline (`backend/src/app/seed/`)
- [x] **Schemas**: Create basic response schemas for API consumption
## Summary of Changes
### Migration
- Created `j1e2f3a4b5c6_add_moves_and_abilities_tables.py` migration
- `moves` table: `id`, `name` (unique), `introduced_gen`, `type` (optional)
- `abilities` table: `id`, `name` (unique), `introduced_gen`
- Added indexes on `introduced_gen` for both tables
### Models
- `backend/src/app/models/move.py`: `Move` SQLAlchemy model
- `backend/src/app/models/ability.py`: `Ability` SQLAlchemy model
- Updated `models/__init__.py` to export both
### Schemas
- `backend/src/app/schemas/move.py`: `MoveResponse`, `AbilityResponse`, and paginated variants
- Updated `schemas/__init__.py` to export all new schemas
### Seed Data
- Created `backend/scripts/fetch_moves_abilities.py` to fetch data from PokeAPI
- Generated `moves.json` (937 moves) and `abilities.json` (367 abilities)
- Data includes name, introduced generation, and type (for moves)
### Seed Pipeline
- Added `upsert_moves` and `upsert_abilities` functions to `loader.py`
- Updated `run.py` to seed moves and abilities after Pokemon
- Updated `verify()` to include move/ability counts

View File

@@ -0,0 +1,62 @@
---
# nuzlocke-tracker-vmto
title: 'Backend: Journal entries model, API, and migration'
status: completed
type: task
priority: normal
tags:
- failed
created_at: 2026-03-20T15:15:48Z
updated_at: 2026-03-20T15:30:47Z
parent: nuzlocke-tracker-mz16
---
Create the backend infrastructure for session journal entries.
## Data Model
`journal_entries` table:
- `id` (UUID, PK)
- `run_id` (FK to runs)
- `boss_result_id` (FK to boss_results, nullable) — optional link to a boss battle
- `title` (str, required)
- `body` (text, required) — raw markdown content
- `created_at`, `updated_at` (timestamps)
## Checklist
- [x] Create Alembic migration for `journal_entries` table
- [x] Create `JournalEntry` SQLAlchemy model with relationships to `Run` and `BossResult`
- [x] Create Pydantic schemas (`JournalEntryCreate`, `JournalEntryUpdate`, `JournalEntryResponse`)
- [x] Create CRUD operations for journal entries
- [x] Create API endpoints under `/runs/{run_id}/journal`:
- `GET /` — list entries for a run (ordered by created_at desc)
- `POST /` — create entry
- `GET /{entry_id}` — get single entry
- `PUT /{entry_id}` — update entry
- `DELETE /{entry_id}` — delete entry
- [x] Add optional `boss_result_id` query filter to GET list endpoint
## Summary of Changes
Implemented backend infrastructure for session journal entries:
**Files created:**
- `backend/src/app/alembic/versions/k2f3a4b5c6d7_add_journal_entries_table.py` - Migration creating `journal_entries` table with UUID PK, foreign keys to `nuzlocke_runs` and `boss_results`, and timestamp columns
- `backend/src/app/models/journal_entry.py` - SQLAlchemy model with relationships to `NuzlockeRun` and `BossResult`
- `backend/src/app/schemas/journal_entry.py` - Pydantic schemas for create, update, and response
- `backend/src/app/api/journal_entries.py` - API endpoints for CRUD operations
**Files modified:**
- `backend/src/app/models/nuzlocke_run.py` - Added `journal_entries` relationship
- `backend/src/app/models/__init__.py` - Exported `JournalEntry`
- `backend/src/app/schemas/__init__.py` - Exported journal entry schemas
- `backend/src/app/api/routes.py` - Registered journal entries router
**API Endpoints:**
- `GET /runs/{run_id}/journal` - List entries (supports `boss_result_id` filter)
- `POST /runs/{run_id}/journal` - Create entry
- `GET /runs/{run_id}/journal/{entry_id}` - Get single entry
- `PUT /runs/{run_id}/journal/{entry_id}` - Update entry
- `DELETE /runs/{run_id}/journal/{entry_id}` - Delete entry

View File

@@ -0,0 +1,39 @@
---
# nuzlocke-tracker-vw1z
title: 'Crash: Crash: Add team snapshot to boss battle results'
status: completed
type: bug
priority: high
created_at: 2026-03-20T19:13:27Z
updated_at: 2026-03-20T19:41:58Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-ueub
---
Agent crashed while working on nuzlocke-tracker-ueub.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZEs79fEcc7KikDZH5tuz"}
```
## Context
- Bean: nuzlocke-tracker-ueub
- Title: Crash: Add team snapshot to boss battle results
- Type: bug
## Summary of Changes
This crash was caused by an OAuth token expiration, not a code issue. The original feature (add team snapshot to boss battle results) has been implemented:
- Created `boss_result_team` table migration
- Added `BossResultTeam` model with relationships
- Updated schemas with `BossResultTeamMemberInput` and `BossResultTeamMemberResponse`
- Updated `POST /runs/{run_id}/boss-results` API to accept and save team snapshots
- Updated `BossDefeatModal` with checkboxes for alive team members with level input
- Added team snapshot display in boss cards on `RunEncounters.tsx`

View File

@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-wb85
title: Replace playstyle rules with custom rules markdown field
status: completed
type: feature
priority: normal
created_at: 2026-03-20T13:48:50Z
updated_at: 2026-03-20T13:53:08Z
---
Remove hardcoreMode, setModeOnly, bossTeamMatch playstyle rules. Add a free-text markdown customRules field so users can track their own rules (especially useful for genlockes). Also: remove 'Lost' result and attempts from BossDefeatModal, always show boss team size.

View File

@@ -0,0 +1,23 @@
---
# nuzlocke-tracker-wwnu
title: Auth hardening, admin ownership display, and MFA
status: completed
type: epic
priority: high
created_at: 2026-03-21T12:18:09Z
updated_at: 2026-03-21T12:38:27Z
---
Harden authentication and authorization across the app after the initial auth integration went live.
## Goals
- [x] Runs are only editable by their owner (encounters, deaths, bosses, settings)
- [x] Frontend hides edit controls for non-owners and logged-out users
- [x] Admin pages show owner info for runs and genlockes
- [ ] Genlocke visibility/ownership inferred from first leg's run
- [ ] Optional TOTP MFA for email/password signups
## Context
Auth is live with Google/Discord OAuth + email/password. Backend has `require_auth` on mutations but doesn't check ownership on encounters or genlockes. Frontend `RunEncounters.tsx` has zero auth checks. Admin pages lack owner columns. Genlocke model has no `owner_id` or `visibility`.

View File

@@ -0,0 +1,24 @@
---
# nuzlocke-tracker-wwwq
title: 'Crash: Show owner info in admin pages'
status: completed
type: bug
priority: high
created_at: 2026-03-21T12:49:42Z
updated_at: 2026-03-21T12:51:18Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-2fp1
---
Bean was found in 'in-progress' status on startup but no agent was running.
This likely indicates a crash or unexpected termination.
Manual review required before retrying.
Bean: nuzlocke-tracker-2fp1
Title: Show owner info in admin pages
## Reasons for Scrapping
The original bean (nuzlocke-tracker-2fp1) had all work completed and committed before the crash occurred. The agent crashed after completing the implementation but before marking the bean as completed. No additional work was needed - just updated the original bean's status to completed.

View File

@@ -0,0 +1,34 @@
---
# nuzlocke-tracker-xd9j
title: Add team snapshot to boss battle results
status: completed
type: feature
priority: low
tags:
- failed
created_at: 2026-03-20T15:11:53Z
updated_at: 2026-03-20T19:41:44Z
parent: nuzlocke-tracker-neqv
---
When recording a boss battle result, allow the player to snapshot which alive team pokemon they used and at what levels. This gives a record of "what I brought to the fight."
## Checklist
- [x] **Migration**: Create \`boss_result_team\` table (\`id\`, \`boss_result_id\` FK, \`encounter_id\` FK, \`level\`)
- [x] **Model**: Create \`BossResultTeam\` model, add relationship to \`BossResult\`
- [x] **Schemas**: Add \`BossResultTeamInput\` and update \`BossResultCreate\`/\`BossResultResponse\`
- [x] **API**: Update \`POST /runs/{run_id}/boss-results\` to accept and save team snapshot
- [x] **BossDefeatModal**: Add checkboxes for alive team members with optional level override
- [x] **Display**: Show team snapshot when viewing past boss results in \`RunEncounters.tsx\`
## Summary of Changes
Implemented team snapshot feature for boss battle results:
- Created `boss_result_team` table (`id`, `boss_result_id` FK, `encounter_id` FK, `level`)
- Added `BossResultTeam` model with relationship to `BossResult`
- Updated schemas with `BossResultTeamMemberInput` and `BossResultTeamMemberResponse`
- Updated `POST /runs/{run_id}/boss-results` to validate and save team snapshot
- Added team selection UI in `BossDefeatModal` with level override
- Display team snapshot in defeated boss cards on `RunEncounters.tsx`

View File

@@ -0,0 +1,37 @@
---
# nuzlocke-tracker-xsdr
title: 'Crash: Crash: Bug: TypeScript build fails due to optional property type mismatches in journal components'
status: completed
type: bug
priority: high
created_at: 2026-03-20T19:12:50Z
updated_at: 2026-03-20T19:17:39Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-3psa
---
Agent crashed while working on nuzlocke-tracker-3psa.
## Exit Code
1
## Last Output
```
Failed to authenticate. API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth token has expired. Please obtain a new token or refresh your existing token."},"request_id":"req_011CZEs4QPgAQoZbS63nnkqT"}
```
## Context
- Bean: nuzlocke-tracker-3psa
- Title: Crash: Bug: TypeScript build fails due to optional property type mismatches in journal components
- Type: bug
## Summary of Changes
Fixed TypeScript build errors caused by `exactOptionalPropertyTypes: true` requiring explicit `| undefined` in optional property types.
**Files changed:**
- `JournalEditor.tsx`: Added `| undefined` to `bossResults` and `bosses` prop types
- `JournalEntryView.tsx`: Added `| undefined` to `bossResult` and `boss` prop types
- `JournalSection.tsx`: Added `| undefined` to `bossResults` and `bosses` prop types

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

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,29 @@
---
# nuzlocke-tracker-26my
title: 'Crash: Show owner info in admin pages'
status: completed
type: bug
priority: high
created_at: 2026-03-22T09:41:57Z
updated_at: 2026-03-22T09:45:38Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-2fp1
---
Bean was found in 'in-progress' status on startup but no agent was running.
This likely indicates a crash or unexpected termination.
Manual review required before retrying.
Bean: nuzlocke-tracker-2fp1
Title: Show owner info in admin pages
## Resolution
No work required. The original bean (nuzlocke-tracker-2fp1) was already successfully completed:
- All checklist items done
- Commit a3f332f merged via PR #74
- Original bean status: completed
This crash bean was a false positive - likely created during a race condition when the original bean was transitioning from in-progress to completed.

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

View File

@@ -0,0 +1,62 @@
---
# nuzlocke-tracker-2fp1
title: Show owner info in admin pages
status: completed
type: feature
priority: normal
tags:
- -failed
- failed
created_at: 2026-03-21T12:18:51Z
updated_at: 2026-03-22T09:08:07Z
parent: nuzlocke-tracker-wwnu
---
## Problem
Admin pages (`AdminRuns.tsx`, `AdminGenlockes.tsx`) don't show which user owns each run or genlocke. This makes it hard for admins to manage content.
## Approach
### Backend
- The `/api/runs` list endpoint already returns run data — verify it includes `owner` (id + email). If not, add it to the response schema.
- For genlockes, ownership is inferred from the first leg's run owner. Add an `owner` field to the genlocke list response that resolves from the first leg's run.
### Frontend
- `AdminRuns.tsx`: Add an "Owner" column showing the owner's email (or "No owner" for legacy runs)
- `AdminGenlockes.tsx`: Add an "Owner" column showing the inferred owner from the first leg's run
- Add owner filter dropdown to both pages
## Files to modify
- `backend/src/app/api/runs.py` — verify owner is included in list response
- `backend/src/app/api/genlockes.py` — add owner resolution to list endpoint
- `backend/src/app/schemas/genlocke.py` — add owner field to `GenlockeListItem`
- `frontend/src/pages/admin/AdminRuns.tsx` — add Owner column + filter
- `frontend/src/pages/admin/AdminGenlockes.tsx` — add Owner column + filter
- `frontend/src/types/game.ts` — update types if needed
## Checklist
- [x] Verify runs list API includes owner info; add if missing
- [x] Add owner resolution to genlocke list endpoint (from first leg's run)
- [x] Update `GenlockeListItem` schema to include owner
- [x] Add Owner column to `AdminRuns.tsx`
- [x] Add Owner column to `AdminGenlockes.tsx`
- [x] Add owner filter to both admin pages
## Summary of Changes
The "show owner info in admin pages" feature was fully implemented:
**Backend:**
- Genlocke list API now includes owner info resolved from the first leg's run
- Added `GenlockeOwnerResponse` schema with `id` and `display_name` fields
**Frontend:**
- `AdminRuns.tsx`: Added Owner column showing email/display name with "No owner" fallback
- `AdminGenlockes.tsx`: Added Owner column with same pattern
- Both pages include owner filter dropdown with "All owners", "No owner", and per-user options
Commit: `a3f332f feat: show owner info in admin pages`

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

View File

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

View File

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

View File

@@ -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

@@ -0,0 +1,38 @@
---
# nuzlocke-tracker-532i
title: 'UX: Make level field optional in boss defeat modal'
status: completed
type: feature
priority: normal
created_at: 2026-03-21T21:50:48Z
updated_at: 2026-03-22T09:16:12Z
---
## Problem
When recording which team members beat a boss, users must manually enter a level for each pokemon. Since the app does not track levels anywhere else, this is unnecessary friction with no payoff.
## Current Implementation
- Level input in `BossDefeatModal.tsx:200-211`
- DB column `boss_result_team.level` is `SmallInteger NOT NULL` (in `models.py`)
- Level is required in the API schema
## Proposed Solution
Remove the level field entirely from the UI and make it optional in the backend:
- [x] Remove level input from `BossDefeatModal.tsx`
- [x] Make `level` column nullable in the database (alembic migration)
- [x] Update the API schema to make level optional (default to null)
- [x] Update any backend validation that requires level
- [x] Verify boss result display still works without level data
## Summary of Changes
- Removed level input field from BossDefeatModal.tsx, simplifying team selection to just checkboxes
- Created alembic migration to make boss_result_team.level column nullable
- Updated SQLAlchemy model and Pydantic schemas to make level optional (defaults to null)
- Updated RunEncounters.tsx to conditionally render level only when present
- Updated frontend TypeScript types for BossResultTeamMember and BossResultTeamMemberInput

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

View File

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

View File

@@ -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

@@ -0,0 +1,84 @@
---
# nuzlocke-tracker-73ba
title: Enforce run ownership on all mutation endpoints
status: completed
type: bug
priority: critical
created_at: 2026-03-21T12:18:27Z
updated_at: 2026-03-21T12:28:35Z
parent: nuzlocke-tracker-wwnu
---
## Problem
Backend mutation endpoints for encounters, bosses, and run updates use `require_auth` but do NOT verify the authenticated user is the run's owner. Any authenticated user can modify any run's encounters, mark bosses as defeated, or change run settings.
Additionally, `_check_run_access` in `runs.py:184` allows anyone to edit unowned (legacy) runs when `require_owner=False`.
### Affected endpoints
**encounters.py** — all mutations use `require_auth` with no ownership check:
- `POST /runs/{run_id}/encounters` (line 35)
- `PATCH /runs/{run_id}/encounters/{encounter_id}` (line 142)
- `DELETE /runs/{run_id}/encounters/{encounter_id}` (line 171)
- `POST /runs/{run_id}/encounters/bulk-randomize` (line 203)
**bosses.py** — boss result mutations:
- `POST /runs/{run_id}/boss-results` (line 347)
- `DELETE /runs/{run_id}/boss-results/{result_id}` (line 428)
**runs.py** — run updates/deletion:
- `PATCH /runs/{run_id}` (line 379) — uses `_check_run_access(run, user, require_owner=run.owner_id is not None)` which skips check for unowned runs
- `DELETE /runs/{run_id}` (line 488) — same conditional check
**genlockes.py** — genlocke mutations:
- `POST /genlockes` (line 439) — no owner assigned to created genlocke or its first run
- `PATCH /genlockes/{id}` (line 824) — no ownership check
- `DELETE /genlockes/{id}` (line 862) — no ownership check
- `POST /genlockes/{id}/legs/{leg_order}/advance` (line 569) — no ownership check
- `POST /genlockes/{id}/legs` (line 894) — no ownership check
- `DELETE /genlockes/{id}/legs/{leg_id}` (line 936) — no ownership check
## Approach
1. Add a reusable `_check_run_owner(run, user)` helper in `auth.py` or `runs.py` that raises 403 if `user.id != str(run.owner_id)` (no fallback for unowned runs — they should be read-only)
2. Apply ownership check to ALL encounter/boss/run mutation endpoints
3. For genlocke mutations, load the first leg's run and verify ownership against that
4. Update `_check_run_access` to always require ownership for mutations (remove the `require_owner` conditional)
5. When creating runs (standalone or via genlocke), set `owner_id` from the authenticated user
## Checklist
- [x] Add `_check_run_owner` helper that rejects non-owners (including unowned/legacy runs)
- [x] Apply ownership check to all 4 encounter mutation endpoints
- [x] Apply ownership check to both boss result mutation endpoints
- [x] Fix `_check_run_access` to always require ownership on mutations
- [x] Set `owner_id` on run creation in `runs.py` and `genlockes.py` (create_genlocke, advance_leg)
- [x] Apply ownership check to all genlocke mutation endpoints (via first leg's run owner)
- [x] Add tests for ownership enforcement (403 for non-owner, 401 for unauthenticated)
## Summary of Changes
Added `require_run_owner` helper in `auth.py` that enforces ownership on mutation endpoints:
- Returns 403 for unowned (legacy) runs - they are now read-only
- Returns 403 if authenticated user is not the run's owner
Applied ownership checks to:
- All 4 encounter mutation endpoints (create, update, delete, bulk-randomize)
- Both boss result mutation endpoints (create, delete)
- Run update and delete endpoints (via `require_run_owner`)
- All 5 genlocke mutation endpoints (update, delete, advance_leg, add_leg, remove_leg via `_check_genlocke_owner`)
Added `owner_id` on run creation:
- `runs.py`: create_run already sets owner_id (verified)
- `genlockes.py`: create_genlocke now sets owner_id on the first run
- `genlockes.py`: advance_leg preserves owner_id from current run to new run
Renamed `_check_run_access` to `_check_run_read_access` (read-only visibility check) for clarity.
Added 22 comprehensive tests in `test_ownership.py` covering:
- Owner can perform mutations
- Non-owner gets 403 on mutations
- Unauthenticated user gets 401
- Unowned (legacy) runs reject all mutations
- Read access preserved for public runs

View File

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

View File

@@ -1,33 +0,0 @@
---
# nuzlocke-tracker-7jba
title: Review and complete special encounters for all games
status: todo
type: task
created_at: 2026-02-10T08:59:24Z
updated_at: 2026-02-10T08:59:24Z
parent: nuzlocke-tracker-rzu4
---
Audit \`special_encounters.json\` to ensure starters, gifts, fossils, and other non-wild encounters are covered for all games.
## What counts as special encounters:
- **Starters** — the three (or more) starter Pokémon choices
- **Gift Pokémon** — NPCs that give you Pokémon (e.g. Eevee in Celadon, Lapras in Silph Co.)
- **Fossils** — Pokémon revived from fossils (e.g. Omanyte/Kabuto, Lileep/Anorith)
- **In-game trades** — Pokémon received via NPC trades (if tracked)
- **Static encounters** — Legendaries, Snorlax blocking the road, Sudowoodo, etc.
- **Event-specific** — One-time encounters tied to story events
## Checklist:
- [ ] Audit Gen 1 (Red/Blue/Yellow/FR/LG) special encounters
- [ ] Audit Gen 2 (Gold/Silver/Crystal/HG/SS) special encounters
- [ ] Audit Gen 3 (Ruby/Sapphire/Emerald/ORAS) special encounters
- [ ] Audit Gen 4 (Diamond/Pearl/Platinum/BD/SP) special encounters
- [ ] Audit Gen 5 (Black/White/B2/W2) special encounters
- [ ] Audit Gen 6 (X/Y) special encounters
- [ ] Audit Gen 7 (Sun/Moon/USUM) special encounters
- [ ] Audit Gen 8+ (Sword/Shield/Scarlet/Violet/Legends) special encounters
## Notes:
- Cross-reference with Bulbapedia "Gift Pokémon" and "In-game trade" pages
- The current file appears focused on Gen 1-2 — later gens likely need additions

View File

@@ -0,0 +1,36 @@
---
# nuzlocke-tracker-8b25
title: 'UX: Allow editing caught pokemon details on run page'
status: draft
type: feature
priority: normal
created_at: 2026-03-21T22:00:55Z
updated_at: 2026-03-21T22:04:08Z
---
## Problem
Users can mistype catch level, nickname, or other details when recording an encounter, but there's no way to correct mistakes from the run page. The only option is to go through admin — which doesn't even support editing encounters for a specific run.
## Current State
- **Backend `EncounterUpdate` schema** (`backend/src/app/schemas/encounter.py:18-23`): Supports `nickname`, `status`, `faint_level`, `death_cause`, `current_pokemon_id` — but NOT `catch_level`
- **Frontend `UpdateEncounterInput`** (`frontend/src/types/game.ts:169-175`): Same fields as backend, missing `catch_level`
- **Run page encounter modal**: Clicking a route with an existing encounter opens the modal in "edit" mode, but only allows changing pokemon/nickname/status — no catch_level editing
- The encounter modal is the create/edit modal — editing is done by re-opening it on an existing encounter
## Approach
### Backend
- [ ] Add `catch_level: int | None = None` to `EncounterUpdate` schema
- [ ] Verify the PATCH `/encounters/{id}` endpoint applies `catch_level` updates (check `encounters.py` update handler)
### Frontend
- [ ] Add `catchLevel?: number` to `UpdateEncounterInput` type
- [ ] Ensure the encounter modal shows catch_level as editable when editing an existing encounter
- [ ] Add catch_level field to the encounter edit modal (shown when editing existing encounters)
### Testing
- [ ] Test updating catch_level via API
- [ ] Test that the frontend sends catch_level in update requests
- [ ] Verify existing create/update flows still work

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

View File

@@ -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

@@ -0,0 +1,28 @@
---
# nuzlocke-tracker-95g1
title: 'Crash: Hide edit controls for non-owners in frontend'
status: completed
type: bug
priority: high
created_at: 2026-03-22T09:41:57Z
updated_at: 2026-03-22T09:46:59Z
parent: nuzlocke-tracker-bw1m
blocking:
- nuzlocke-tracker-i2va
---
Bean was found in 'in-progress' status on startup but no agent was running.
This likely indicates a crash or unexpected termination.
Manual review required before retrying.
Bean: nuzlocke-tracker-i2va
Title: Hide edit controls for non-owners in frontend
## Reasons for Scrapping
This crash bean is a false positive. The original task (nuzlocke-tracker-i2va) was already completed and merged to `develop` before this crash bean was created:
- Commit `3bd24fc`: fix: hide edit controls for non-owners in frontend
- Commit `118dbca`: chore: mark bean nuzlocke-tracker-i2va as completed
No additional work required.

View File

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

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