Files
solelog/apps/worker/README.md
Bas van Rossem 34c48d6353 feat(api): drive CORS + trusted origins from CORS_ORIGINS env
Phone/LAN testing previously required editing both app.ts (cors origin) and
auth.ts (better-auth trustedOrigins). Now both read env.WEB_ORIGINS, parsed from
a comma-separated CORS_ORIGINS env var (default http://localhost:5173). To test
from a phone, set CORS_ORIGINS to include the LAN origin and restart the API — no
code edit. Documented in .env.example. Also fixed the worker README (db:migrate
creates ./data/app.db, not ./.tmp; phone step now uses CORS_ORIGINS). API tests
36/36 green; typecheck clean.
2026-06-17 16:50:21 +02:00

3.9 KiB

@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. There is a sign-up affordance on the login screen for creating a test 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.