101 Commits

Author SHA1 Message Date
Bas van Rossem
8d303dabcb docs: phase 3b.3 user-management session log + roadmap (Phase 3 complete)
All checks were successful
Build and Push Docker Image / build (push) Successful in 57s
2026-06-24 23:14:59 +02:00
Bas van Rossem
b9aa24c5ae harden(api): adminGuard rejects banned admins; fix mixed-case create + real last-admin guard coverage 2026-06-24 23:12:40 +02:00
Bas van Rossem
0f42960f00 feat(admin): Gebruikers screen (list, create, role, password, deactivate) 2026-06-24 23:03:34 +02:00
Bas van Rossem
4b80898b0e feat(api): admin reset-password endpoint 2026-06-24 22:57:35 +02:00
Bas van Rossem
40977f8abd feat(api): deactivate/reactivate users (ban + revoke sessions) with guards 2026-06-24 22:54:02 +02:00
Bas van Rossem
88b7773317 feat(api): set user role with self-demote + last-admin guards 2026-06-24 22:50:52 +02:00
Bas van Rossem
2b4b633961 feat(api): admin-users router with enriched roster + user creation 2026-06-24 22:46:59 +02:00
Bas van Rossem
a32406de69 refactor(api): extract adminGuard + add user-management contracts 2026-06-24 22:42:35 +02:00
Bas van Rossem
4463a2e41a docs(plan): phase 3b.3 user management implementation plan 2026-06-24 22:39:15 +02:00
Bas van Rossem
6e4ce6b472 docs(spec): phase 3b.3 user management design 2026-06-24 22:33:59 +02:00
Bas van Rossem
bbf29120ac docs: phase 3b.2 reports/export session log + roadmap note
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m17s
2026-06-24 16:44:17 +02:00
Bas van Rossem
8d75be0462 feat(admin): Rapporten screen with filters, totals, breakdowns + CSV export 2026-06-24 16:40:25 +02:00
Bas van Rossem
8ad2e69ec3 feat(admin): reports API client (useReport + downloadExport) 2026-06-24 16:33:28 +02:00
Bas van Rossem
d33fcb7cce feat(api): admin all-users filtered CSV export 2026-06-24 16:30:17 +02:00
Bas van Rossem
4b213e25a8 feat(api): admin report endpoint + ReportResponse contracts 2026-06-24 16:25:36 +02:00
Bas van Rossem
01fa18f401 refactor(api): extract buildSessionsCsv shared by worker + admin exports 2026-06-24 16:22:06 +02:00
Bas van Rossem
eac1eed71a docs(plan): phase 3b.2 reports + all-users export implementation plan 2026-06-24 16:18:15 +02:00
Bas van Rossem
3eccdef313 docs(spec): phase 3b.2 reports + all-users export design 2026-06-24 15:46:24 +02:00
Bas van Rossem
84677080fc docs: phase 3b.1 manual-sessions session log + roadmap note 2026-06-17 22:54:18 +02:00
Bas van Rossem
7d3daaa760 feat(worker): poll + reconcile stopwatch to server (admin stop/cancel) 2026-06-17 22:50:31 +02:00
Bas van Rossem
f1ec249ee7 feat(admin): stop/cancel an active session from the live view 2026-06-17 22:47:05 +02:00
Bas van Rossem
69b46bee04 feat(admin): manual session create/edit form
Add the shared SessionForm component (create/edit) used by the Sessies screen.
- Create mode: worker picker (useAdminUsers), activity (useActivities), zooltype,
  pair count, start/end datetime-local, pauze, notitie; posts CreateManualSessionInput.
- Edit mode: hides the worker picker, prefills from the row session, adds a status
  select; PUTs AdminUpdateSessionInput (end_time nulled when status=active).
- Builds ISO start_time/end_time from the datetime-local values; live "gewerkt"
  preview = end - start - paused; inline error on a 400.
- Wires the form into Sessions.tsx ("+ Nieuwe registratie" -> create, pencil -> edit).

Products affected: SoleLog admin client
2026-06-17 22:44:06 +02:00
Bas van Rossem
b5366413b6 feat(admin): sessions management screen (list + filter + actions) 2026-06-17 22:38:28 +02:00
Bas van Rossem
53c66ee144 feat(api): admin manual-session create/edit/stop/discard + users roster
Sub
Phase 3b.1 needs admin-side write paths so an admin can hand-create a
session for a worker, correct any session, and stop/cancel a worker's
stuck active session — duration always derived server-side.

Adds under the existing /api/admin/* admin guard:
- GET /api/admin/users — {id,name,email} roster ordered by name (worker picker)
- POST /api/admin/sessions — manual create -> completed, source=manual,
  duration = max(0, round((end-start)/1000) - paused)
- PUT /api/admin/sessions/:id — edit any session (no user reassignment);
  recomputes duration when end_time present, else duration null
- POST /api/admin/sessions/:id/stop — fold open pause, end=now, completed
- POST /api/admin/sessions/:id/discard — status=discarded, end=now

Validates end>=start, pair_count>=1, paused<=span, activity/user exist
(400/404); stop/discard on an already-closed session -> 409. Responses
reuse toWorkSession.

Products affected: SoleLog backend (apps/api)
2026-06-17 22:32:58 +02:00
Bas van Rossem
7d1e816fe2 feat(ci): set database location to local folder 2026-06-17 22:28:55 +02:00
Bas van Rossem
00993c67da feat(shared): manual-session create/update contracts
Add CreateManualSessionInput and AdminUpdateSessionInput zod schemas plus
inferred types. packages/shared has no test runner, so these are exercised
via Task 2's API tests rather than a standalone parse test.
2026-06-17 22:28:02 +02:00
Bas van Rossem
9d21576014 docs: spec + plan for phase 3b.1 manual session entry/edit + admin stop/fix 2026-06-17 22:25:28 +02:00
Bas van Rossem
70ac27ec8e style: align oxfmt to trailing-comma 'all' and normalize code
All checks were successful
Build and Push Docker Image / build (push) Successful in 28s
The repo was authored prettier-style (trailing-comma 'all') but .oxfmtrc.json
was set to 'es5', so every formatted file diverged. Switch the config to 'all'
to match the existing code, ignore docs/** and **/drizzle/** (prose + generated
snapshots the formatter should not own), and reformat the source tree once for
consistency. No behavioural change; all suites green (api 60, worker 28, admin 21).
2026-06-17 21:36:18 +02:00
Bas van Rossem
1807f2b6d6 docs: pause-accounting + reorder session log
Finalize the pause-accounting + reorderable-handelingen + login-tab-fix
feature: session log (goal/work/verification/outcome), a one-line roadmap
status note, and an oxfmt pass over the changed files that strips a stray
trailing comma after the last call argument in the worker Stopwatch (es5
trailing-comma style) — pure formatting, tests stay green.
2026-06-17 21:24:16 +02:00
Bas van Rossem
e48df48376 feat(admin): reorder handelingen with up/down arrows 2026-06-17 21:18:07 +02:00
Bas van Rossem
0b0a6bd073 feat(admin): show paused sessions in live view; reset to live on logout
- Live cards freeze the worked timer at paused_at and show an amber
  "Gepauzeerd" badge plus a "Pauze H:MM:SS" total when paused.
- AuthContext.signOut resets the path to / so the next admin login lands
  on Live rather than the tab it logged out from.
2026-06-17 21:14:15 +02:00
Bas van Rossem
a7c8925b3c feat(deploy): build + serve worker and admin as static nginx images
All checks were successful
Build and Push Docker Image / build (push) Successful in 53s
- per-app Dockerfiles (vite build → nginx) + SPA nginx.conf
- Gitea workflow pushes 3 images; frontends bake VITE_API_URL
- docker-compose.prod.yml (registry images, solelog_network) + .env.prod.example
- docker-compose.yml runs the full stack locally; add .dockerignore
2026-06-17 21:11:32 +02:00
Bas van Rossem
1765f4036c fix(worker): show paused time in history; reset to stopwatch on logout 2026-06-17 21:10:01 +02:00
Bas van Rossem
ce396ecf2d feat(worker): server-authoritative pause/resume on the stopwatch 2026-06-17 21:06:10 +02:00
Bas van Rossem
56e0162230 feat(api): orderable activities + admin reorder endpoint 2026-06-17 20:58:06 +02:00
Bas van Rossem
974ecb120d feat(api): server-authoritative pause/resume + worked-time stop + CSV paused
Add user-scoped POST /api/sessions/:id/pause and /resume endpoints,
mirroring the stop handler's ownership/lookup and 401/404/409 guards.
Pause sets paused_at (status stays active); resume folds the open span
into paused_seconds and clears paused_at.

Change stop to fold any open pause span into paused_seconds, then set
duration_seconds = max(0, round((end-start)/1000) - paused_seconds) so
saved duration is worked time, and clear paused_at.

Add a "Paused Duration" column to /api/export (after "Total Duration")
using formatDuration(paused_seconds).

Products affected: SoleLog backend (apps/api)
2026-06-17 20:54:42 +02:00
Bas van Rossem
0d82b6efbc feat(shared,api): add pause + sort_order columns and contracts
Adds server-side pause accounting and activity ordering primitives.
- WorkSession contract gains paused_seconds (number) and paused_at (ISO string | null).
- Activity contract gains sort_order (number); new ReorderActivitiesInput zod.
- work_sessions += paused_seconds (int NOT NULL DEFAULT 0) + paused_at (timestamp_ms nullable).
- activities += sort_order (int NOT NULL DEFAULT 0).
- toWorkSession / toActivity map the new fields; generated migration 0003.

The new fields are additive; existing api/worker/admin tests stay green.

Products affected: SoleLog backend (apps/api), shared contracts (packages/shared)
2026-06-17 20:49:56 +02:00
Bas van Rossem
eae9a53a26 fix(docker): drop COPY .yarn/ — dir is gitignored, absent in CI builds
All checks were successful
Build and Push Docker Image / build (push) Successful in 37s
2026-06-17 20:45:53 +02:00
Bas van Rossem
cbfcb4a414 docs: spec + plan for pause accounting, reorder, login-tab fix 2026-06-17 20:43:19 +02:00
Bas van Rossem
660cbe50c8 ci(docker): build and push image to Gitea registry on push to main
Some checks failed
Build and Push Docker Image / build (push) Failing after 28s
2026-06-17 20:42:58 +02:00
Bas van Rossem
76ad235c9f docs(admin): phase 3a session log + roadmap status 2026-06-17 19:17:20 +02:00
Bas van Rossem
c0d9d21991 feat(admin): activity management (handelingen CRUD) 2026-06-17 19:11:50 +02:00
Bas van Rossem
67dd0d398f feat(admin): live active-work view (5s refresh) 2026-06-17 19:07:36 +02:00
Bas van Rossem
286e2d29db feat(admin): sidebar shell + routing 2026-06-17 19:03:35 +02:00
Bas van Rossem
77659edf8e feat(admin): bearer auth with admin-only gate + login screen 2026-06-17 18:59:43 +02:00
Bas van Rossem
682a9dce44 feat(admin): scaffold Vite+React admin workspace 2026-06-17 18:56:28 +02:00
Bas van Rossem
02b7522b87 feat(api): include role in /api/me + allow admin origin in CORS
Add `role: Role` to the shared `PublicUser` contract and return it from
`GET /api/me` (defaulting to 'worker' when the session user has no role).
This lets the planned admin app gate access by role.

Also add the admin dev origin `http://localhost:5174` to the default
`WEB_ORIGINS` (env.ts) and to `.env.example`, so the admin SPA on :5174 can
reach the API at :3000 cross-origin (drives both hono/cors and better-auth
trustedOrigins).
2026-06-17 18:53:39 +02:00
Bas van Rossem
bb0a0b2a57 docs(admin): fold admin-origin CORS into phase 3a Task 1 2026-06-17 18:49:16 +02:00
Bas van Rossem
7cdc88e824 docs(admin): phase 3a spec + implementation plan 2026-06-17 18:46:11 +02:00
Bas van Rossem
6fce7a7197 docs(roadmap): fold activity-management UI port into Phase 3 scope 2026-06-17 18:29:40 +02:00