Files
solelog/apps/admin/README.md
2026-06-17 19:17:20 +02:00

4.3 KiB

@solelog/admin

The SoleLog Admin panel: a Vite + React + TypeScript single-page app for the shop-floor administrator. An admin logs in (email + password → bearer token in localStorage), watches who is working live, and manages the handelingen (activities). It is a client only — it talks to the @solelog/api backend over HTTP with Authorization: Bearer <token>; it never touches the database.

Admin-only. Sign-in confirms role === 'admin' via GET /api/me. A worker who signs in with valid credentials is rejected with "Geen toegang — alleen beheerders." and the token is cleared. The UI is in Dutch.

It mirrors apps/worker's toolchain and conventions (same Vite/React/react-query/vitest versions, the same lib/api.ts + lib/auth-storage.ts), so it shares proven patterns.

What Phase 3a covers

  • Login — Dutch email + password form (no self-signup), with the admin-only gate.
  • Sidebar shell — left sidebar with the signed-in email + an Uitloggen button, nav to Live and Handelingen, and a muted "Binnenkort" group (Rapporten / Gebruikers / Handmatig) hinting at Phase 3b.
  • Live (/) — who is working right now, from GET /api/admin/sessions/active, auto-refreshing every 5 s (read-only in 3a). One card per session: worker name, activity, insole-type pill, pair count, and a client-side ticking elapsed timer. Empty state: "Niemand is nu aan het werk.".
  • Handelingen (/handelingen) — add / inline-edit / delete activities and their insole types (Kurk / Berk / 3D), against /api/activities (writes are admin-gated server-side; the admin bearer satisfies them).

Deferred to Phase 3b: reports + all-users CSV export, user management (/api/auth/admin/*), and manual session entry/edit + admin stop/fix of a running session (needs new backend endpoints).

Prerequisites

  • Node + Corepack (Yarn 4 is pinned in the repo).

  • From the repo root, install everything once:

    yarn install
    

Run it

Two processes: the API on :3000 and the admin SPA on :5174.

1. Backend API (:3000)

From the repo root:

yarn workspace @solelog/api db:migrate   # apply migrations (creates ./data/app.db on first run)
yarn workspace @solelog/api db:seed      # idempotent: seeds reference activities + dev logins
yarn workspace @solelog/api start        # Hono server on http://localhost:3000

db:seed creates two dev logins (dev-only — skipped when NODE_ENV=production): admin admin@solelog.local / werkplaats-admin and worker worker@solelog.local / werkplaats123. Only the admin can use this app.

The API's default WEB_ORIGINS already allows http://localhost:5174 (this app's dev origin), so cross-origin sign-in and requests work out of the box. Override with CORS_ORIGINS for other origins (e.g. a LAN IP).

2. Admin SPA (:5174)

From the repo root:

yarn workspace @solelog/admin dev        # Vite dev server on http://localhost:5174

Open http://localhost:5174 and sign in as the admin. The API base URL comes from VITE_API_URL (default http://localhost:3000).

Scripts

yarn workspace @solelog/admin dev          # dev server (:5174, LAN-exposed)
yarn workspace @solelog/admin build        # tsc -b && vite build → dist/
yarn workspace @solelog/admin preview      # preview the production build
yarn workspace @solelog/admin typecheck    # tsc -b
yarn workspace @solelog/admin test         # vitest run

Architecture

  • Auth. lib/api.ts + lib/auth-storage.ts are copied from the worker: sign-in reads the bearer token from the set-auth-token response header into localStorage, and apiFetch<T> attaches Authorization: Bearer <token> to every request. auth/AuthContext.tsx adds the admin gate (re-fetch /api/me, reject non-admins).
  • Live data. api/admin-sessions.ts useActiveSessions() uses react-query with refetchInterval: 5000; each card computes elapsed time from the server start_time with a 1 s client tick (lib/elapsed.ts formatTime).
  • Activities. api/activities.ts hooks (useActivities + create/update/delete) invalidate the ['activities'] query on every mutation.
  • Shared contracts. Request/response shapes are zod schemas in @solelog/shared, imported here for a typed client.