4.3 KiB
Session: 2026-06-17 — Phase 3a (Admin panel MVP)
Goal
Build apps/admin: a Vite + React desktop SPA where an admin logs in, watches who is
working live (auto-refreshing, read-only), and manages handelingen (activities).
Everything rides on existing backend endpoints plus one tiny backend touch (role on
/api/me). Reports/export, user management, and manual session entry/edit are deferred to
Phase 3b. Spec: docs/superpowers/specs/2026-06-17-phase-3a-admin-panel-design.md;
plan: docs/superpowers/plans/2026-06-17-phase-3a-admin-panel.md.
Work done
Implemented Phase 3a task-by-task per the plan (TDD throughout):
- Task 1 —
roleon/api/me+ admin-origin CORS (02b7522). Addedrole: RoletoPublicUserin@solelog/shared;apps/api/src/routes/me.tsnow returns the session user's role (default'worker'). Addedhttp://localhost:5174(admin dev origin) to the defaultWEB_ORIGINSinenv.ts+.env.example(it drives bothhono/corsand better-authtrustedOrigins). Extendedme.test.tsandcors.test.ts. Worker client ignores the extra field — no worker change needed. - Task 2 — Scaffold
apps/admin(682a9dc). New@solelog/adminworkspace mirroringapps/worker's toolchain (Vite 7, React 18.3, react-router 6, react-query 5, vitest 3, TS 5.7). Copiedlib/api.ts+lib/auth-storage.tsverbatim (sharedsolelog.tokenkey; separate localStorage because the admin runs on a different port). Dev port 5174. - Task 3 — Auth context + admin gate + Login (
77659ed).auth/AuthContext.tsx:signIncalls the workersignIn, fetches/api/me, and rejects non-admins (clearToken()+ throw) soLoginshows "Geen toegang — alleen beheerders."; other failures show "Inloggen mislukt". - Task 4 — Sidebar shell + routing (
286e2d2). Left-sidebar shell: brand "SoleLog Admin",NavLinks Live / Handelingen, a muted "Binnenkort" group (Rapporten / Gebruikers / Handmatig) hinting 3b, and a header strip with the signed-in email + an Uitloggen button (aria-label="Uitloggen"). - Task 5 — Live active-work view (
67dd0d3).useActiveSessions()polls/api/admin/sessions/activewithrefetchInterval: 5000;lib/elapsed.tsformatTimeported verbatim from the worker stopwatch. One card per session (worker name, activity, insole-type pill, pair count, ticking elapsed timer). Header "Actief nu (N)"; empty state "Niemand is nu aan het werk.". - Task 6 — Activity management (
c0d9d21). Ported the legacy workerSettings.tsx(gitdecb158) near-verbatim:api/activities.tshooks (useActivities+ create/update/delete, all invalidating['activities']) andscreens/Activities.tsx(add form with insole-type toggles, list with inline edit, delete-with-confirm). Title "Handelingen". - Task 7 — Docs, lint, verification (this task). Lint/format clean, full green matrix, live smoke, docs.
Verification (Task 7)
npx oxlint— clean (exit 0).npx oxfmt --list-differentover the phase-3a files — nothing to change (all formatted).yarn workspace @solelog/api typecheck— pass;test— 46 passed (11 files).yarn workspace @solelog/admin typecheck— pass;test— 14 passed (5 files);build— pass (vite build, 89 modules).yarn workspace @solelog/worker test(regression) — 22 passed (7 files).- Live smoke (API started, seeded, then server tree killed + port 3000 freed):
- admin sign-in →
GET /api/me→{ ..., "role": "admin" }. GET /api/admin/sessions/activewith the admin bearer →[], HTTP 200.- worker sign-in →
GET /api/me→{ ..., "role": "worker" }.
- admin sign-in →
Outcome
Phase 3a is implemented and green. An admin can sign in to the admin app, see who is
working right now (5s auto-refresh, read-only), and add/edit/delete handelingen; a worker
who signs in with valid credentials is rejected with "Geen toegang". Roadmap Phase 3 status
updated to "3a implemented; 3b remaining"; apps/admin/README.md filled.
Next (Phase 3b)
- Reports + all-users filtered CSV export (current
/api/exportis self-scoped). - User management via better-auth
/api/auth/admin/*. - Manual session entry/edit + admin stop/fix of another worker's session (needs new backend endpoints).