client: standalone /stats page with charts, off the admin dashboard

Closes #40.

New /stats route (client/stats.html + src/stats/), served by the same
catch-all pattern as /admin. Reuses the admin login (STATS_PUBLIC env var
on the server side decides whether it needs one at all).

Three uPlot charts (daily revenue, daily transaction count, top-5-drink
sold-qty trend) plus the same three tables Admin.tsx used to render inline
— those move here wholesale, Admin.tsx now just links to /stats instead of
fetching /admin/api/stats itself. The 'Statistik zurücksetzen' reset button
moves here too, gated on an actual admin session (checked separately from
whether /api/stats itself succeeded, since STATS_PUBLIC can make that true
for an anonymous viewer).

Chart lib is uPlot (~45kb) per mara's steer not to hand-roll this. Both
client and server build/typecheck clean; manually smoke-tested the auth
gate (401 unauthed, 200 after login) and the /stats route against a fresh
DB.
This commit is contained in:
iris 2026-07-30 10:25:54 +02:00 committed by mara
commit 1d99881e88
10 changed files with 332 additions and 75 deletions

8
pnpm-lock.yaml generated
View file

@ -16,6 +16,9 @@ importers:
preact:
specifier: ^10.22.0
version: 10.29.2
uplot:
specifier: ^1.6.31
version: 1.6.32
devDependencies:
'@preact/preset-vite':
specifier: ^2.8.2
@ -1865,6 +1868,9 @@ packages:
peerDependencies:
browserslist: '>= 4.21.0'
uplot@1.6.32:
resolution: {integrity: sha512-KIMVnG68zvu5XXUbC4LQEPnhwOxBuLyW1AHtpm6IKTXImkbLgkMy+jabjLgSLMasNuGGzQm/ep3tOkyTxpiQIw==}
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
@ -3766,6 +3772,8 @@ snapshots:
escalade: 3.2.0
picocolors: 1.1.1
uplot@1.6.32: {}
util-deprecate@1.0.2: {}
vite-prerender-plugin@0.5.13(vite@5.4.21(@types/node@20.19.41)(terser@5.47.1)):