99 lines
4.3 KiB
Markdown
99 lines
4.3 KiB
Markdown
# @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:
|
|
|
|
```bash
|
|
yarn install
|
|
```
|
|
|
|
## Run it
|
|
|
|
Two processes: the API on `:3000` and the admin SPA on `:5174`.
|
|
|
|
### 1. Backend API (`:3000`)
|
|
|
|
From the repo root:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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.
|