Backend:
- Add enriched response types (EditSnapshot, EnrichedEditRequest) with original vs proposed snapshots
- Add 4 new GET endpoints for viewing edit requests (user and admin scoped)
- Remove github.com/lib/pq dependency — use native PostgreSQL array scanning
- Clean up edit requests, time blockers, and notifications on booking cancellation
- Validate exceptional closed hours on admin approve (409 Conflict)
- Notification upsert on edit request replace (no duplicate admin notifications)
Frontend:
- New user EditRequestModal with time/services/both modes and lunch protection
- New admin EditRequestModal with side-by-side diff (date/time, services, notes)
- Integrate edit requests into PendingApprovals card and notifications page
- Preload 3 months of availability to prevent calendar snap-back
- Apply lunch protection to isDateUnavailable in BookingFlow and BookingCreateModal
- Fix accessibility: card list items use <button> instead of <div>
Dev & Docs:
- Seed edit requests in local-dev-2.sh
- Update all Obsidian manuals with enriched edit request documentation
- 42 new tests (438/441 passing)
Split Crussell Nails.md (822 lines) into 5 focused documents:
- README.md: slimmed to 84 lines (elevator pitch + run instructions)
- Overview.md: expanded landing page with architecture diagram and quick links
- User Manual.md: 358 lines, customer-facing journeys in plain English
- Admin Manual.md: 493 lines, staff operations guide with zero technical jargon
- Technical Manual.md: 736 lines, full API reference, schema, key systems
All user/admin manuals rewritten for non-technical audiences — no API
endpoints, component names, or implementation details.
Reflect new PUT /api/admin/bookings/{id} services endpoint, EditBookingModal
component, and updated test count (306/308). Mark handleEdit() stub resolved
in gap backlog.
Replace placeholder BookingModal on the Next Appointment edit button with a
dedicated EditBookingModal that allows admins to add, remove, and override
services on an active booking. Includes backend PUT endpoint with overlap
detection and full test suite (20 tests).
- Add TestMain to all 10 test packages (schema DROP+CREATE runs once per package)
- Convert per-test setupTestDB to resetTestData (TRUNCATE only, ~60% faster)
- Add 3 missing tables to TruncateTables (booking_edit_requests, exceptional_group_applications, business_settings)
- Remove dead truncateDiscountTables helper
- Consolidate discount_test.go into package bookings (was external test package)
- Update testutils.SetupTestDB to truncate-only
- Fix unused imports across user, bookings, and handlers packages
- Verify: 286 passing, 2 skipped, 0 failures with -count=2 (no state leakage)
- Add time blocker management for booking edit requests
- Add closing_time field to admin today/current-next endpoint
- Update UserBookingModal and CurrentAppointment UI components
- Fix fmt import in bookings_test.go (was missing)
- Fix created_by FK in TestAdminApproveEditRequest_TimeBlockerOverlap
- Update test coverage for edit request time blocker overlap
- Update gap backlog documentation
- generateGroupedTimeSlots now accepts lunchProtection map parameter
- Lunch-blocked slots treated as unavailable during grouping, not after
- Consecutive lunch-blocked slots merge into one unavailable button
- Admin BookingCreateModal already had this fix; BookingFlow now matches
- Fetch /api/scheduling/working-hours and /api/scheduling/available-hours for reschedule month
- Generate grouped time slots using same logic as BookingFlow (available + unavailable with start-end times)
- DatePicker uses isDateUnavailable based on real availability (no slots = unavailable)
- Time slots show X - Y format (e.g. 9:30 AM - 10:00 AM) matching booking flow
- Unavailable slots shown as disabled buttons
- Today's slots respect 2-hour minimum notice buffer
- Hours fetched on first reschedule open or calendar month change
- Replace Modal.Footer with plain div to avoid bits-ui class merging (sm:flex-row override)
- DatePicker wrapped in flex items-center justify-center matching BookingCreateModal
- Time picker uses Button elements with fuchsia selection (hover:bg-fuchsia-50, bg-fuchsia-100)
- Generate 30-min time slots from 08:00-18:00 matching salon hours
- Reschedule form container uses bg-gray-50 matching other sections
- Footer: two rows with flex-1 buttons for equal width
- Footer: row 1 has Cancel + Reschedule, row 2 has Add to Calendar + Close
- Replace native datetime-local input with DatePicker component from BookingFlow
- Add native time input for preferred time selection
- Buttons use flex-1 for equal width on mobile
- Add new discount types to testdb.Migrate drop list (campaign_type, milestone_type, etc.)
- Add new discount tables to testdb.Migrate drop order and TruncateTables
- Move discount type definitions to top of init-script.sql with other enums
- Remove duplicate type definitions that were after admin_notification_reason
- Types must be defined before tables that reference them