Commit Graph
13 Commits
Author SHA1 Message Date
Stefan Lazic 21299f0287 gallery changes
CI / ci (push) Canceled after 0s
Hero gallery: the slideshow on Home doesn’t open full screen. Only portfolio images do, as you asked.
Lightbox: it has no pinch-zoom.
Delete: removing an image still has no confirm step, same as before.
New dependency: drag-and-drop uses @dnd-kit, which I added to package.json.
Touch dragging: I couldn’t test it on a real phone. Mouse and keyboard dragging work.
Health test: src/app/api/health/__tests__/route.test.ts passes, but it prints unhandled rejections. Its prisma mock has no notificationDelivery, so getQueueHealth throws. That comes from the earlier “Remaining features” commit and I left it alone. It’s a quick fix if you want it.
2026-10-18 11:23:17 +01:00
Stefan Lazic 95ff9bd70c Package Updates
CI / ci (push) Canceled after 0s
Changed files: only package.json and package-lock.json in the app and the manager.
Main versions:
Next.js: 16.2.12 (app) and 16.3.4 (manager) → 16.4.2 in both.
React and React DOM: 19.3.1.
Prisma: 7.10.1, including the client and the MariaDB adapter.
Smaller bumps: mariadb 3.5.4, image-size 2.0.4, postcss, zod, lucide-react, react-hook-form, the Radix packages and Playwright.
Verified: typecheck and lint are clean. All 420 app unit tests, 198 manager tests and 345 integration tests on MySQL 8 pass. The Prisma migrations show no drift. Both production builds succeed, and I clicked through the calendar, business settings, reminders and booking screens with no errors from the upgrade.
2026-10-18 10:05:59 +01:00
Stefan Lazic 2ed9c5ecca security cleanup, client import, WhatsApp reminders
CI / ci (push) Canceled after 0s
1. Pre-launch review (no code)
Listed what’s left before going live: testing, backups, monitoring, legal/GDPR, and a dry run on the VPS.
Listed the features a barbershop system usually has and which of them you’re missing.
Researched WhatsApp pricing, which led to the free route below.
2. Security cleanup

This came out of that review.

Deleted: /dev/scheduling-test (a test page that shipped), /api/debug/db-connect-test (a leftover debug route), and two files of unauthenticated booking and appointment actions (11 actions). One of them listed appointments with customer details to anyone.
Audited: all 127 server actions. The only unguarded ones left are the intended public ones: availability lookups, cookie-based booking drafts, and the token-gated one-time installer.
Tidied: removed the four now-dead booking schemas from schemas.ts.
3. Client import from a spreadsheet
Entry points: an upload icon next to “+” on the Clients page, and a link on the Add Client page. It’s owner-only, checked again on the server.
Flow: /staff/clients/import.
Upload a CSV and check the guessed column mapping.
Review the preview, then import in chunks with progress.
A report lists problem rows by spreadsheet row number, with a download.
CSV template: a visible “Download CSV template” button (headers only: First name, Last name, Email, Phone).
Behavior:
Each client gets a sign-in-ready account, the same as adding one by hand.
Nobody is emailed.
Existing emails are left untouched.
Earlier guest bookings under the same email attach automatically.
“Surname, Firstname” names are read the right way round.
People sharing a phone number still import.
Limits: an email is required for every row, CSV only (no .xlsx), up to 5,000 rows per file, and notes aren’t imported.
4. WhatsApp reminders (free, manual route)
Button: a WhatsApp button next to Call and Email on four pages: the owner and barber appointment pages, “Current appointment”, and the client page. It opens WhatsApp with a ready-written reminder, including a “change it” link.
Phone numbers: read as the business’s own country when typed without a country code. This uses the new libphonenumber-js dependency. A number WhatsApp can’t use means no button.
Reminders list: a new /staff/reminders page lists tomorrow’s confirmed bookings in time order.
Each row has a one-tap Send on WhatsApp.
Tapping marks it “Sent 14:46”, with an Undo.
The mark shows on the appointment pages too.
Barbers see their own list; owners see the whole shop with barber names.
Calendar link: “WhatsApp reminders · 3 to send tomorrow” on both calendar pages.
Database: one additive migration, Appointment.whatsappReminderSentAt. Rescheduling clears it, since a reminder for the old time says nothing about the new one.
Audit log: who marked or undid each reminder is recorded.
Tests and verification
	Before today	Now
Unit tests	297	331
Integration tests	273	285
New unit tests: the CSV parser, import row logic, and WhatsApp link and phone handling.
New integration tests: the import service and the reminders service.
Checks: typecheck and lint are clean (the one old branding warning remains).
Browser: I exercised each feature in a real browser against a throwaway MySQL 8, including the permission split between Leo and Marcus.
2026-10-15 21:25:09 +01:00
Stefan Lazic a8a8d1e045 Updated Calendard
CI / ci (push) Canceled after 0s
The calendar is now react-big-calendar.
2026-10-08 11:01:32 +01:00
Stefan Lazic 2aa8405006 Revert "PHP Rebuild"
This reverts commit 2ef3654841.
2026-09-05 09:32:05 +01:00
Stefan Lazic 2ef3654841 PHP Rebuild
CI / ci (push) Canceled after 0s
Initial PHP rebuild of the app
2026-09-05 08:21:33 +01:00
Stefan Lazic 9949e2275e Database 2
fix for vercel build
2026-08-07 17:39:31 +01:00
Stefan Lazic 769d3f9ebc PWA Settings
Fixed webmanifest generation and pwa icon.

Made nav bar text optional.
2026-08-07 13:38:11 +01:00
Stefan Lazic 9e39908ea7 Post Phase 8 - Fixes 1
Delivered:

Super Administrator — env-var provisioned, no StaffProfile at all (structural exclusion from Team/barber-picker/appointments/staff-totals, not a filter). hasPermission short-circuit + new getActingBusinessContext() helper retrofitted across 16 owner pages so it can actually manage the business.
Media Manager — one upload/library/external-URL modal + field picker, backing every image field app-wide. Local-disk storage + Docker volume, SVG rejected, size-capped.
Welcome backgrounds — desktop/mobile images with CSS breakpoint swap.
Business Branding settings — logo/cover/welcome/favicon/icon/colours all editable post-install; cover image finally rendered (was dead config).
Service descriptions — now surfaced on Home and in the booking flow.
Loyalty card — live preview, ColorPicker/MediaPicker/IconPicker, flip removed for a static premium-styled card, Loyalty added to bottom nav. Fixed a real pre-existing bug where the card's configured colour/image/icon were stored but never actually rendered.
Home Screen Redesign — hero gallery + sticky Services/Portfolio/Reviews/Details tabs, backed by a new unified gallery model/service (no hero/portfolio duplication). Details tab surfaces social links and a map that were never shown before.
Google Reviews — real sync pipeline (24h cron, CRON_SECRET-gated, mirrors the existing notification cron exactly), DB-only customer reads, owner hide/unhide + policy management page.
Architecture cleanup — SettingsPageShell extracted from 6 duplicated page wrappers; fixed a second pre-existing bug where branding image fields could never actually be cleared once set.
Verification: 418 tests passing (236 unit + 182 integration, all against a real MySQL database), full typecheck/lint clean across src, and a real Docker build+run cycle — which caught and fixed a genuine bug (scripts/ wasn't copied into the production image, so Super Admin sync would have crashed on every real deployment).
2026-08-04 17:10:30 +01:00
Stefan Lazic 546613e677 Phase 7 2026-08-03 21:15:24 +01:00
Stefan Lazic 6ae145d187 Phase 4
Seed data extended with a second barber (different hours/services), a beard-trim service + category, breaks, time off, a guest customer, and appointments in all three key states — verified against a live throwaway Postgres.
14 new integration tests (38 total with Phase 3's) covering guest/authenticated booking, any-barber assignment, slot-conflict handling, ownership enforcement, guest-data isolation, and book-again repricing.
Playwright E2E suite for the 6 required customer journeys, with its own global-setup.ts that migrates and seeds a database automatically.
Full verification pass, which caught and fixed three real bugs along the way (not just test-workarounds):
A date off-by-one bug in the calendar picker that made real weekdays show as closed for anyone in a UTC+ timezone (including the business's own).
A dialog that could vanish mid-confirmation on cancellation, before the customer could read the late-cancellation notice.
A silent test-cleanup leak in the Phase 3 fixtures that had been leaking stray businesses since Phase 3.
Plus a baseline desktop-responsive fix (centered max-w-2xl columns) across Home/Appointments/Settings/booking flow, since desktop had been effectively unstyled.
Final state: 90 unit tests, 38 integration tests, and all 6 E2E journeys passing together on a fresh database; clean tsc, eslint, and next build. Full writeup with routes, security model, guest-matching rules, known limitations, and what to check before Phase 5 is in docs/phase-4-summary.md.
2026-08-02 21:39:24 +01:00
Stefan Lazic 8b63cc66a9 Booking Engine
Architecture: Six focused services with the BookingService/SchedulingService overlap resolved by giving SchedulingService exactly one job, the transactional double-booking guard , while BookingService owns the create/reschedule/cancel workflow around it.

59 unit tests, 24 integration tests
2026-08-02 18:36:39 +01:00
Stefan Lazic 090646fdfd Phase 2
Base app architecture:

    Route groups for customer, staff and owner.
* Reusable design system with around 20 UI components.
* Complete Prisma schema.
* Authentication with email/password and Google.
* Role and permission model.
* Protected routes.
* Clean separation between features, services, components and shared utilities.
2026-08-02 17:47:23 +01:00