- booking views gain intakeLabels (declared key→label join); dashboard
modal + manage view render real question labels with slug fallback
- GET /v1/metrics/services aggregates bookings/completed/cancelled/
revenue per service + classBookings; service-report.csv delegates to
the same ServiceMetrics aggregation and gains a completed column
- services page gains a Service performance card (per-service stat grid,
locale CZK revenue, class-bookings footer); demo rows match the
fabricated service list
- staff capacity utilization subtracts blocked days — tenant-wide and
staff-scoped blocks remove that day's rule minutes via blockedAt
- tests: blocked-day capacity (tenant + staff scope), service aggregation
Authored By: TDvorak <[email protected]>
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Services declare up to 8 intake fields (text/yesno, required) stored
as JSONB; shared/intake.go is the single normalization point — slug
keys, label/dup/unknown-key rules, yes/no canonicalization. Booking
create validates answers against the service declaration (missing
required -> 400), unknown keys are dropped before persist.
Answers surface on UpcomingBooking and CustomerBookingView; the
services page gains a compact editor and the public form renders
declared questions under contact details. Verified live end-to-end.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
class_schedules rules generate concrete session rows for a rolling 28-day
horizon — no cron; materialize runs idempotently on dashboard and public
reads via a partial unique index on (schedule_id, starts_at). Rule delete
stops future sessions; existing sessions keep bookings and overrides.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Utilization now measures booked minutes against each member's
availability-rule capacity in the tenant timezone, replacing the
confirmed-share proxy. StaffMetric exposes booked/capacity minutes.
New endpoints: GET /v1/export/staff-report.csv (reuses StaffMetrics)
and GET /v1/export/service-report.csv (per-service bookings/cancelled/
revenue, class bookings rolled up). Export buttons on the staff
performance panel and services page.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
GET /v1/metrics/staff returns bookings, completed, cancelled,
utilization, and revenue per staff member over a trailing window
(default 30d, max 365d). Appointment bookings only — class sessions
have no staff assignment. All active staff appear, including
zero-booking rows.
Staff page gains a localized Performance panel; demo mode seeds
trailing-window bookings and matching metric rows.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
GET /v1/export/bookings.csv (optional from/to bounds) and
/v1/export/customers.csv — UTF-8 with BOM for Excel, labels resolved
at export time, buffered responses so auth failures stay JSON.
Export buttons on the bookings and customers pages.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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>
GET /v1/public/calendar/{token} serves an RFC 5545 calendar under a
token-as-secret URL (private Google/Outlook link model). Staff feeds
contain only that member's bookings; the tenant feed tags each event
with the staff member. Window is -30d to +180d; cancelled bookings map
to STATUS:CANCELLED, waitlisted/pending to TENTATIVE + TRANSPARENT.
Summaries resolve service or class-session titles, descriptions carry
localized contact labels, locations resolve to names.
Feed tokens live on tenants/staff (migration 00015) and are managed via
GET /v1/calendar/feed plus POST /v1/calendar/feed/rotate — rotating a
scope invalidates the old URL. ICS rendering is hand-rolled: TEXT
escaping, CRLF, 75-octet folding on rune boundaries.
Settings gains a "Kalendář (ICS)" card with copyable URLs and two-step
rotation per scope; demo mode points at the real seeded tokens.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Adds the roster and manual promotion controls deferred from the booking
lifecycle milestones. Businesses can now inspect who holds a seat and who
is queueing on a class session, and promote waitlisted customers by hand
— including a deliberate over-capacity override when the session is full.
Backend:
- GET /v1/catalog/class-sessions/{id}/roster — session metadata plus
confirmed and waitlist entry lists with queue positions
- POST /v1/catalog/bookings/{id}/promote — 409 on a full session unless
allowOverCapacity is set; 400 for non-waitlisted, 404 for missing or
foreign bookings; reuses the shared confirm path so waitlist ledger
rows resolve and reminder jobs re-arm
- ListBookingsBySession repository method (pgx + memory); ClassSession
carries waitlistCount; UpcomingBooking carries classSessionId and
waitlistPosition
- OpenAPI paths + schemas, regenerated client, catalog service tests
Frontend:
- classes tab session rows expand into a two-column roster panel with
per-entry promote buttons and an explicit confirm-anyway step on 409
- booking detail modal shows waitlist position and offers promote for
waitlisted bookings; list badges show #N queue positions
- CS/EN i18n keys and seeded demo roster data; demo mutations surface
the demo notice
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Templates were delete-and-recreate only. Adds PUT
/v1/catalog/class-templates/{id} across repository, service (sharing
the create-time validation), route, spec, and client; the classes tab
gets a pencil action that loads the row into the form with a
save/cancel affordance.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The dashboard promised a new-clients card the API never produced; the
metric now counts distinct customer emails whose earliest-ever booking
lands in the window, joining the other four KPIs with the same trend
comparison. The card grid rebalances for five items.
Reminder dispatch also had no trigger — the endpoint existed but
nothing called it. A scheduled GitHub Actions workflow now posts to it
every 15 minutes using the job-runner key, so reminders actually fire
once the two secrets are configured.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Dashboard KPIs were three flat counters with no trend data — the cards
rendered a neutral dash where the design intends movement indicators.
Summary now queries three trailing windows and emits four KPIs with
real deltas: bookings this week, completed (new CompletedCount metric
in both repositories), cancellations, and utilization in percentage
points. KPI labels localize in the frontend via a code-to-key map so
Czech operators no longer see English labels on live data.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- POST /v1/catalog/bookings/{id}/cancel lets businesses cancel
tenant-owned bookings; two-step confirm in the detail modal
- Shared PromoteWaitlist helper promotes earliest waitlisted bookings
when a class seat frees, on both dashboard and customer cancel paths;
promoted customers get a confirmation email, waitlist ledger marked
resolved
- waitlisted status surfaced in bookings UI: stats card, filter, warning
badge, demo seed, CS+EN strings
- BookingRecord gains created_at for fair ordering; GetBookingByID and
ResolveWaitlistEntry added to the repository surface
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Working-hours repo accepts nullable staff scope (pgx + memory); staff
rules live in availability_rules and drive public slot generation
- Protected routes for staff working hours, class templates, and class
sessions with tenant-ownership checks and input validation
- Sessions derive endsAt/capacity from templates; list resolves location
names and live booked counts; template delete cascades sessions,
session delete preserves bookings via SET NULL (mirrored in memory)
- Zones page: staff-scope selector on working hours, new Classes tab
with template/session CRUD, CS+EN strings, mobile tab wrapping
- Normalize availability_rules times to HH:MM in the service layer
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Services and staff existed as schema + booking FK targets but had no
management surface. Adds full CRUD: repository (pgx + in-memory with
matching FK semantics), catalog service validation with tenant isolation,
MaxStaff entitlement enforcement, protected API routes, OpenAPI schemas,
and dashboard screens for both entities.
Dashboard summary now resolves staff names on bookings and computes
setup completion from real configured state. Booking modal selects from
the tenant's actual services; blocked days can be scoped per staff member.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Migration 00012: populate tenant_memberships from tenant_users join
users, not only the seeded demo owner (Codex P1)
- bookings-page: check response.error so 4xx failures do not close the
modal silently; refetch dashboard summary after create (Codex P2)
Authored By: TDvorak <[email protected]>
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit introduces a major overhaul of the user interface, transitioning from a basic structure to a feature-rich dashboard system. Key improvements include:
- **Dashboard Implementation**: Added a complete dashboard routing system with dedicated pages for Overview, Bookings, Customers, Zones, Billing, and Settings.
- **New UI Components**: Introduced a variety of high-quality components including `AnimatedList`, `FloatingDock`, `HoverFeatureCards`, `VideoPlayer` (with ambient glow effect), `PinnedList`, and `DashboardMockup`.
- **Enhanced Dashboard Features**:
- Integrated real-time KPI cards and activity timelines.
- Implemented a multi-view calendar system.
- Added customer and booking management interfaces with filtering and search capabilities.
- Added a zone/location management view with map integration.
- **Branding & Visuals**: Updated the application with new SVG logos (horizontal and vertical variants) and implemented dark/light mode optimized branding.
- **Internationalization**: Expanded i18n support with comprehensive Czech and English translations for the new dashboard and integration modules.
- **Integration Tools**: Added a new `IntegrationModal` allowing users to easily embed Bookra widgets via HTML, React, SolidJS, or PHP.
- **Backend Support**: Updated the booking service to provide comprehensive dashboard summary data, including historical booking records for charts.