Commit Graph
15 Commits
Author SHA1 Message Date
Tomas DvorakandDevin 7b9080eb1c feat(reports): capacity-based utilization + report CSVs
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>
2026-09-18 17:10:15 +02:00
Tomas DvorakandDevin 76e45d4178 feat(metrics): per-staff performance view in dashboard
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>
2026-09-18 16:34:45 +02:00
Tomas DvorakandDevin 4674203502 feat(export): CSV export for bookings and customers
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>
2026-09-18 16:15:36 +02:00
Tomas DvorakandDevin d86cba61e3 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>
2026-09-18 16:06:13 +02:00
Tomas DvorakandDevin 6c3b2bf6bf feat(calendar): read-only ICS feeds for tenant and staff
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>
2026-09-18 15:20:22 +02:00
Tomas DvorakandDevin 1cd5b1ba91 feat(classes): session roster + manual waitlist promotion
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>
2026-09-18 14:37:40 +02:00
Tomas DvorakandDevin 5884203e9d feat(catalog): class template editing
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>
2026-09-18 13:13:37 +02:00
Tomas DvorakandDevin c7172544b8 feat(metrics): new-clients KPI and scheduled reminder dispatch
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>
2026-09-18 12:59:44 +02:00
Tomas DvorakandDevin 0dc26e0c16 feat(dashboard): real business metrics with week-over-week trends
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>
2026-09-18 11:34:00 +02:00
Tomas DvorakandDevin 668a54ae1d feat(bookings): dashboard cancellation and waitlist promotion
- 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>
2026-09-18 11:21:46 +02:00
Tomas DvorakandDevin 0405106587 feat(availability): per-staff working hours and class/session management
- 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>
2026-09-18 11:01:01 +02:00
Tomas DvorakandDevin 09f780e7a6 feat(catalog): add service and staff management end-to-end
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>
2026-09-18 08:52:25 +02:00
Tomas DvorakandDevin 50c8440a06 fix: backfill memberships, handle booking create errors
- 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>
2026-09-17 20:33:53 +02:00
Tomas DvorakandDevin f2f7439050 refactor(db): replace sqlc with handwritten pgx repos
- Finish Paddle-to-Stripe billing migration; drop paddle/stripe libs
- Renumber migrations; add 00012 memberships+manage_token,
  00013 location_type_capacity
- Add tests: admin, auth, bookings customer service
- Remove graphify-out artifacts and stale env files

Authored By: TDvorak <[email protected]>

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-17 20:21:34 +02:00
Tomas Dvorak da5ba13eab feat(ui): implement comprehensive dashboard and enhance frontend experience
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.
2026-05-18 14:31:20 +02:00