feat(activity): per-tenant audit feed in notification dropdown

activity_events records booking lifecycle transitions with the actor
behind each change — staff (dashboard), customer (self-service), or
system (auto-promotion). The notification dropdown leads with the real
feed instead of derived recent-booking guesses.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Tomas DvorakandDevin committed 2026-09-18 16:06:13 +02:00
1 parent e5cb9bd543
commit d86cba61e3
18 files changed
+634 -28

No files matched your search

+10 -2
View File
@@ -162,6 +162,15 @@
- `SessionMoveTarget` schema + both endpoints documented in OpenAPI; generated client regenerated
- verified live + browser: created a second session of the demo template, moved a confirmed booking over HTTP (200 + new `classSessionId`), then repeated through the real manage page in Czech and English — success banner, updated date/time, clean console
- remaining: live staging validation on Neon + pgx repository path
- `[done/partial]` Milestone 24: Per-tenant activity feed
- `activity_events` table (migration 00016) + `GET /v1/activity` — tenant-scoped audit feed, newest first, `limit` capped at 100; `ActivityEvent`/`ActivityFeedResponse` in OpenAPI
- actor model distinguishes `staff` (dashboard user, principal name/subject), `customer` (self-service via manage token), and `system` (automatic waitlist promotion)
- booking lifecycle writes land at every transition: public create → `booking.created`, dashboard cancel + manual promote → staff events, customer cancel/reschedule/move → customer events, `PromoteWaitlist` auto-drain → system event; all writes are best-effort (`_ =`) so the feed can never fail a booking
- summaries are human-readable `{customer} — {service/session title}` resolved at write time; the frontend never needs secondary lookups
- notification dropdown now leads with the real feed when it returns events (derived recent-bookings guesses remain as fallback); unknown future actions degrade to the raw action string instead of a broken i18n key; CS/EN labels for all five actions
- demo repo seeds three varied events so the dropdown has content on first open
- verified live: feed returns seeds newest-first, public booking create lands `booking.created` with entity id, customer cancel lands `booking.cancelled`; browser-checked both locales against the demo dashboard, console clean
- remaining: live staging validation on Neon + pgx repository path; settings/CRUD edits can join the feed when a concrete need appears
## Overview
Bookra is a Czech-first booking SaaS for small local service businesses. It targets salons, massage therapists, small clinics, repair shops, and small studios/clubs that need a simple public booking flow, internal schedule management, reminders, and basic business reporting without becoming a full ERP.
@@ -411,11 +420,10 @@ Key entities:
## Future Phases
Shortlist of worthwhile directions once v1 stabilizes — kept deliberately small, in line with the "no feature sprawl" principle:
- **Activity/audit log**: a per-tenant feed of who changed what (booking created/cancelled/promoted, settings edits). Natural fit for the notification dropdown and useful for multi-staff accountability.
- **Google Calendar sync**: M22 shipped read-only ICS feeds; two-way sync (push bookings into Google, pull busy blocks back as availability exceptions) needs OAuth and conflict rules — larger commitment, defer until a concrete request.
- **Recurring class schedules**: templates currently schedule sessions one at a time; a weekly recurrence rule with per-session overrides would cut setup time for studios.
- **Booking notes intake**: structured intake fields per service (e.g. "first visit?", "injuries?") instead of the single free-text notes field — still schema-light.
- **Persistent notification center**: the dropdown currently derives notifications from summary data; a `notifications` table would enable read/unread state and delivery history in-app.
- **Persistent notification center**: M24 put real activity events in the dropdown, but read state is still in-memory and there's no delivery history; a `notifications` table (or read-cursor on `activity_events`) would persist both.
- **Staff performance view**: bookings/completion/utilization per staff member — the metrics primitives already exist; this is a filtered presentation layer.
- **CSV export**: bookings and customers export for accounting/backup; cheap to build, frequently requested by small businesses.