chore: bean organisation

This commit is contained in:
2026-03-22 08:56:06 +01:00
parent f17687d2fa
commit c064a1b8d4
26 changed files with 409 additions and 0 deletions

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,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,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,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,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,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,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,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,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,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,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,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.