The dashboard release. AppointMe now ships a business-analytics surface on top of the booking data it already owns — built the same way as the rest of the app, so it doubles as a worked example of a read-heavy vertical slice: Dapper reads, calculators unit-tested in isolation, its own permissions, and a generated typed client on the frontend.
Try it in the live demo — no signup required.
Added
- Dashboard — a new
/dashboardroute summarising a company's booking business over a selectable period.- Four KPI cards — appointments (with cancellations), revenue booked, chair utilization (booked vs. bookable hours), and returning-client rate. Each card shows a delta against the comparison period.
- Trend chart — appointments, revenue, cancellations, or new customers, bucketed by day / week / month and overlaid with the previous period.
- Bookings by staff — per-provider booking counts and utilization, so an overloaded or idle provider is obvious at a glance.
- Peak hours heatmap — average bookings per hour-of-day by weekday over the last four weeks.
- Period picker — today, yesterday, this/last week, this month, quarter, or year, with an optional "compare to previous period" mode. The selection lives in the URL, so a view is shareable and survives a reload.
- Dashboard API — two new Booking endpoints (
GET /api/v1/booking/dashboard/stats,GET /api/v1/booking/dashboard/peak-hours) and one CRM endpoint (GET /api/v1/crm/dashboard/new-customers), all reading through Dapper with the tenant predicate applied, and all range/bucket maths covered by unit tests. - Statistics permissions —
appointments.statistics:viewandcustomers.statistics:view, auto-discovered like every other permission and wired into the default grant policies. The dashboard degrades per permission: a user with only one of them sees only the widgets that permission covers. - Shared bucketing primitives —
StatsBucketandStatsBucketinginAppointMe.Shared, so day/week/month bucketing is defined once and reused by both modules. - Covering index for dashboard queries — a composite
IX_Appointments_CompanyId_Start(includingEnd,Status,ProviderId,AttendeeId), added as raw SQL because the index spans an owner scalar and an owned-type property that EF's fluentHasIndexcannot express together. - Administration menu — a super-admin-only sidebar section (cross-tenant, config-driven), currently surfacing the background-jobs dashboard.
- Demo data top-up jobs — recurring jobs that keep the demo tenant's appointments and customers rolling forward, so the dashboard always has a populated window to render.
- Build version in the footer — the frontend now shows the build it was produced from, with the commit SHA passed into the image at build time via
APP_VERSION.
Changed
- CI/CD is GitHub-only. The GitLab pipeline is gone; GitHub Actions covers build, test, frontend lint, CodeQL (now v4), and a gitleaks secret scan on every push and PR. The
infra/README was rewritten around GitHub OIDC setup for people cloning the repo. - Devtest infrastructure is cheaper. Azure Service Bus was dropped in favour of Wolverine's
SqlDurabletransport, the app-service plan defaults to F1, the SQL SKU matches the live Basic tier, and Log Analytics ingestion is capped at 0.5 GB/day. A Cloudflare Worker host-rewrite proxy provides a custom domain on the free tier, with the API honouringX-Original-Hostas the forwarded public hostname. - Dependency refresh — React Router 8, and updates to axios, TanStack Query, lucide-react, orval, and Vite.
- Dashboard layout works on phone screens — KPI cards reflow, the trend-chart series toggles collapse into a select, and the wide widgets stack.
Fixed
- Resolved flagged vulnerable dependencies.
- Added the missing
DialogDescriptionto the schedule-appointment dialog, clearing Radix'saria-describedbyconsole warning. - Corrected input field names on the sign-up form.
- Added the missing
employees:manage_ownerspermission label. - Cleared pre-existing ESLint errors now that CI runs frontend lint, and split context hooks and row-action cells into sibling files to satisfy the fast-refresh convention.
Full changelog: CHANGELOG.md · Compare: v1.0.0...v1.1.0