Files
solelog/apps/worker
Bas van Rossem ec2bb7eec9 feat(api): seed a dev login account (worker@solelog.local) for testing
db:seed now also creates a ready-made dev account via better-auth (properly
hashed), idempotent, and SKIPPED when NODE_ENV=production so no known-password
account ships to prod. Credentials: worker@solelog.local / werkplaats123.
Documented in the worker README. API tests 37/37 green; verified live (sign-in
returns a bearer token; /api/me returns the user).
2026-06-17 17:05:56 +02:00
..

@solelog/worker

The SoleLog Worker timing client: a lean Vite + React + TypeScript single-page app, installable as a PWA. It logs a worker in (email + password → bearer token in localStorage), attaches Authorization: Bearer <token> to every API call, and reproduces the three Dutch screens Stopwatch / Geschiedenis / Instellingen against the @solelog/api backend.

No Expo, no React Native, no ngrok / tunnelling. This is a plain web app. It runs in any browser at http://localhost:5173, and on a phone on the same LAN via the PC's IP — no tunnel.

Prerequisites

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

  • From the repo root, install everything once:

    yarn install
    

Run it

Two processes: the API on :3000 and the worker SPA on :5173.

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 the reference activities
yarn workspace @solelog/api start        # Hono server on http://localhost:3000

2. Worker SPA (:5173)

From the repo root:

yarn workspace @solelog/worker dev       # Vite dev server on http://localhost:5173

Open http://localhost:5173 in any browser. db:seed creates a ready-made dev login: worker@solelog.local / werkplaats123 (dev-only — skipped when NODE_ENV=production). Or use the sign-up affordance on the login screen to create your own account. After signing in you land on the Stopwatch tab.

The API base URL comes from VITE_API_URL (default http://localhost:3000).

Testing from a phone on the same LAN (no tunnel)

Vite is configured with server.host: true, so the dev server is reachable on the LAN. On a phone connected to the same Wi-Fi:

  1. Find the PC's LAN IPv4 address (e.g. 192.168.1.50).

  2. On the phone, open http://<PC-LAN-IP>:5173.

  3. Point the SPA at the API on the LAN by setting VITE_API_URL when starting the worker:

    VITE_API_URL=http://<PC-LAN-IP>:3000 yarn workspace @solelog/worker dev
    

    (On Windows PowerShell: $env:VITE_API_URL='http://<PC-LAN-IP>:3000'; yarn workspace @solelog/worker dev.)

  4. Allow that origin on the API by setting CORS_ORIGINS when you start it — no code edit:

    CORS_ORIGINS=http://localhost:5173,http://<PC-LAN-IP>:5173 yarn workspace @solelog/api start
    

    (PowerShell: $env:CORS_ORIGINS='http://localhost:5173,http://<PC-LAN-IP>:5173'; yarn workspace @solelog/api start.) Otherwise the cross-origin sign-in is blocked and the SPA cannot read the set-auth-token header.

No firewall punch-through, VPN, or tunnel is involved — just the LAN.

Install as a PWA

The app ships a web app manifest (public/manifest.webmanifest) and icons (public/icon-192.png, public/icon-512.png), linked from index.html. Use the browser's Install / Add to Home Screen action to install it. Offline support (service worker) is intentionally out of scope for Phase 1.

Scripts

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

Architecture (Phase 1)

  • Server-authoritative timing. Start / stop / discard are API calls (POST /api/sessions/start, /:id/stop, /:id/discard); the live timer only displays elapsed time computed from the server start_time. An open session therefore survives a browser/phone restart and is recovered on load via GET /api/sessions/active.
  • Shared contracts. Request/response shapes are zod schemas in @solelog/shared, imported here for a typed client.
  • Auth. Sign-in reads the bearer token from the set-auth-token response header and stores it in localStorage; apiFetch attaches Authorization: Bearer <token> to every request.