Commit Graph
44 Commits
Author SHA1 Message Date
popertotsandSisyphus ad0af39237 feat(backend): integrate custom services across booking, payment, scheduling, today, and user modules
Update booking create/confirm/progress/reserve handlers to support custom_service_ids and custom overrides. Add UNION ALL queries to include custom_services in booking detail, payment summary, scheduling availability, today dashboard, and customer relationship queries.

Ultraworked with Sisyphus (https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-06-15 16:58:10 +01:00
popertotsandSisyphus 6902eabf47 feat(backend): add idempotency key cleanup scheduler
CleanupOldIdempotencyKeys clears stale idempotency keys from bookings, payments, and till_sales older than 24h (non-pending status). Wired into daily cleanup cycle in default-hours.go.

Tests: clears old bookings/payments/till_sales, preserves recent and pending entries.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-06-12 10:50:54 +01:00
popertotsandSisyphus b750b3c203 feat(scheduling): add gift card expiry and idle account cleanup
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-06-11 22:08:21 +01:00
popertots 0d4a74bd4a feat: caret preservation and Luhn validation in card inputs
- Added generic formatAndPreserveCursor() helper on frontend to track
  and restore selection caret position during dynamic input sanitization
- Applied to all card inputs, gift card code inputs, and expiry inputs
- Added Luhn validation (isValidLuhn) for saved cards and gift cards
- Rebuilt payments test DB and got 100% green tests
2026-06-05 21:05:36 +01:00
popertots f4a6033715 feat: financial data retention & aggregation system
Add CleanupExpiredFinancialRecords to enforce HMRC + Limitation Act
compliance (7-year retention, 1-year post-anonymization buffer).

- financial_aggregates table: monthly totals by payment method/type (no PII)
- CleanupExpiredFinancialRecords(): aggregates expired payments/refunds,
  deletes granular records, idempotent via ON CONFLICT DO UPDATE
- Wired into GET /api/availability alongside existing cleanup functions
- 8 tests: 7yr expiry, 1yr buffer, 9yr override, aggregation totals,
  idempotency, active user protection, both-thresholds elapsed, refunds
- testdb.go: financial_aggregates in drop-order and truncate lists
- README + Technical Manual updated
2026-06-05 16:37:04 +01:00
popertotsandSisyphus f88854e5c2 feat(scheduling): add expired loyalty cleanup and extend guest anonymization
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-06-05 15:40:38 +01:00
popertotsandSisyphus b460c2ec20 fix(scheduling): extend AnonymizeStaleGuestAccounts with additional field scrubbing
AnonymizeStaleGuestAccounts now additionally scrubs profile_pic_url (NULL), referral_code (NULL), notes (NULL), and data_retention_consent (FALSE) for stale guest accounts. Previously only scrubbed name, email, phone, and date_of_birth. Ensures comprehensive PII removal for guests with no active/pending bookings and last booking over 6 months old.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-06-05 12:12:38 +01:00
popertots 169d7dc6e3 feat(scheduling,admin,today): week-range queries, file size limits, mobile nav UX
- Expand exceptional application query to Monday of start week
- Add 20MB file size limit with visual feedback in ImageUpload
- Reorder admin nav links, add burger badge, slide transition + backdrop
- Fetch week-range working/available hours, add closing time indicator
- Skip lunch protection for days <= 5h via shouldApplyLunchProtection
- Extract formatDateISO to shared utils
2026-06-03 10:22:16 +01:00
popertotsandSisyphus b1847b4cfc fix(payments,portfolio,scheduling): add ID validation hardening
Add validators.IsValidID() checks on URL param IDs to return 404 instead of 400 for invalid IDs. Add offset cap and query length limit in portfolio images handler.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-31 18:49:16 +01:00
popertotsandSisyphus 965b8b2794 feat: validate admin and time-blocker request structs
Ultraworked with Sisyphus (https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-31 10:54:59 +01:00
popertotsandSisyphus c442c150c0 feat: scheduling exceptional hours support and default hours validation
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-28 16:29:17 +01:00
popertots e73c96b653 refactor: optimize test DB setup — TestMain per package, truncate-only between 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)
2026-05-10 17:27:51 +01:00
popertots 83c62ffb97 feat: edit request time blockers, today closing time, UI polish, and test fixes
- 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
2026-05-10 16:53:17 +01:00
popertots 88ee265603 refactor: remove auto deposit penalty on no-shows, add comprehensive tests
- Remove automatic deposits_required=3 on no-shows, give admin flexibility
- Add tests for no-show deposit logic (forgiven, over 24h, under 24h)
- Add tests for reservation cleanup TTL (admin walk-in/call-in 15min)
- Add tests for EXIF GPS data stripping in portfolio images
- Add tests for contact info endpoint
- Add tests for guest account anonymization
2026-05-03 15:59:40 +01:00
popertots 6808752e0d feat: unify walk-in and call-in reservation flows with 15min TTL, guest booking support, and slot awareness
- backend/handlers/bookings/admin_reserve.go:
  - Add explicit reservation_type field ("walkin" | "callin") to request struct
  - Remove TTL-based heuristic for type detection
  - Walk-in: uses duration_minutes, allows null user_id, 1min past grace
  - Call-in: requires service_ids, validates future time, calculates duration from services
  - Both types now use 15-minute TTL

- backend/handlers/scheduling/time-blockers.go:
  - Update CleanupOldReservations: both walkin and callin use 15min TTL (was 10min/60min)

- frontend/WalkInBooking.svelte:
  - Full rewrite of reservation logic
  - If available now and >15min remaining: reserve from now to slot end
  - If <=15min or not available: reserve next full slot
  - Always reserves before opening modal (never open without hold)
  - Passes reservedDuration to modal
  - TTL changed from 5 to 15 minutes

- frontend/WalkInCreateModal.svelte:
  - Replace dead commented-out guest code with working guest creation
  - Guest account created at submit time (not earlier)
  - Phone defaults to +447700900000 if blank
  - Phone field marked optional with helper text
  - Name split into firstName/lastName for backend
  - Validation relaxed: only name required for guests

- frontend/BookingCreateModal.svelte:
  - TTL changed from 60 to 15 minutes
  - Add reservation_type: "callin" to reserve payload
  - Guest creation uses correct firstName/lastName fields
  - Default guest phone to +447700900000
  - Reservation no longer requires selectedUserId (works for guests)

- docs: Update Future Work backlog to mark completed items
2026-05-03 15:09:50 +01:00
popertots 7b396b7a9d fix: resolve guest booking failures from router conflict, reservation self-block, and closed-day miscalculation
- backend/main.go: Flatten /bookings/* sub-Route to explicit paths to prevent
  RequireAuth middleware from bleeding into OptionalAuth POST /bookings
- backend/handlers/scheduling/time-blockers.go: Exclude RESERVATION:* entries
  from GetTimeBlockersInRange so overlap checks dont reject the users own
  reservation before CreateBookingHandler can delete it
- local-dev-2.sh: Fix open_day to skip Saturday (6) not Monday (1), matching
  working_hours schema; move guest booking dates to +16/+20/+22 days beyond
  the upcoming loop range; add reserve-then-book step mirroring frontend flow
2026-04-30 16:06:51 +01:00
popertotsandSisyphus 52ca9b425b test: add guest booking, reservation, and anonymization tests
New tests: guest user creation (success, duplicate email, registered collision),
guest booking flow (success, missing user_id, non-guest user_id, deposit bypass),
reservation lifecycle (logged-in, anonymous, replace, validation, conflict detection,
dual cleanup), anonymization (6mo threshold, pending exclusion).

Fixes: deposit advance rule 48h→24h (stale test), time-based test flakiness
(2h→72h offsets), handler confusion in no-show tests, enum type casting for
booking status.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-30 11:45:08 +01:00
popertotsandSisyphus 4f173b04dc feat: dual TTL reservation cleanup and guest account anonymization
CleanupOldReservations now handles four reservation types:
logged-in (1hr), anonymous (10min), admin-walkin (10min), admin-callin (1hr).

AnonymizeStaleGuestAccounts scrubs PII from guest accounts whose last booking
was 6+ months ago and who have no pending/confirmed bookings. Financial records
remain intact — only personal data is wiped (UK GDPR compliance).
Triggered on every GetAvailableHours call.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-30 11:44:51 +01:00
popertotsandSisyphus b6e98353bc test: update cleanup test for new RESERVATION:user: description format
Test was using RESERVATION:{user_id}:timestamp which no longer matches
the dual-TTL cleanup patterns. Updated to RESERVATION:user:{user_id}:{timestamp}.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-29 23:15:32 +01:00
popertotsandSisyphus 6766c6128c feat: wire reserve route, dual TTL cleanup, and booking reservation deletion
Add POST /api/bookings/reserve route with OptionalAuth middleware and rate limiting.
Update CleanupOldReservations to handle dual TTLs: 1hr for logged-in users,
10min for anonymous reservations. Update CreateBookingHandler to also match
anon reservations by start_time for users who register mid-flow.
Add comprehensive tests for reservation creation, validation, conflict detection, and cleanup.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-29 23:05:48 +01:00
popertotsandSisyphus b549716b89 test: fix flaky time_blockers test and improve testdb migration
Un-harden TestTimeBlockers_List dates (now relative to current time) and
update TestCleanupOldReservations to use fixture users instead of hardcoded IDs.
Improve Migrate() to drop types before tables (CASCADE dependency fix) and
add forgiven_no_shows to truncate list. Seed default working hours in admin
booking tests to prevent business-logic check failures.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-29 22:55:58 +01:00
popertots 99ab43eefb test: update tests to reflect current behavior changes
UPDATED TEST FILES:

1. backend/handlers/bookings/bookings_test.go (added 6 new tests):
   - TestBookings_Create_MinimumAdvance: Renamed from 48h check, now tests 1h requirement
   - TestBookings_Create_WithNotes_StatusPending: NEW - verifies notes cause 'pending' status
   - TestBookings_Create_WithoutNotes_StatusConfirmed: NEW - verifies auto-approval without notes
   - TestBookings_Create_Within1Hour_ShouldFail: NEW - verifies < 1h bookings are rejected
   - TestBookings_Delete_NoShow24hThreshold: NEW - tests 24h no-show rule & deposit penalty
   - TestBookings_Delete_NoShow_WithForgiveness: NEW - tests forgive_no_show parameter

2. backend/handlers/admin/bookings_test.go (added 2 new tests):
   - TestAdminBookings_Create_EnforceDeposits_Bypass: NEW - admin can bypass deposit checks
   - TestAdminBookings_Create_EnforceDeposits_Enforced: NEW - default enforcement behavior

3. backend/handlers/scheduling/time_blockers_test.go (added 1 new test):
   - TestCleanupOldReservations: NEW - verifies 1h+ old reservations are cleaned up

TEST COVERAGE FOR NEW FEATURES:

✓ 1h minimum advance requirement (universal, not deposit-dependent)
✓ Notes → 'pending' status (auto-approval workflow)
✓ No notes → 'confirmed' status (auto-approved)
✓ 24h no-show threshold (< 24h = penalty, >= 24h = late cancellation)
✓ forgive_no_show parameter (admin can forgive no-shows)
✓ Deposit penalty: set to 3 (not +=3, prevents escalation)
✓ enforce_deposits parameter (admin can bypass checks)
✓ Reservation cleanup (auto-delete > 1h old reservations)

VERIFICATION:
✓ All test code compiles (go build -tags test ./handlers/bookings)
✓ All test code compiles (go build -tags test ./handlers/admin)
✓ All test code compiles (go build -tags test ./handlers/scheduling)
✓ Main build still works (go build -tags dev ./main.go)

TEST EXECUTION (to run):
go test -tags test -v ./handlers/bookings -run TestBookings_Create_WithNotes
go test -tags test -v ./handlers/bookings -run TestBookings_Delete_NoShow
go test -tags test -v ./handlers/admin -run TestAdminBookings_Create_EnforceDeposits
go test -tags test -v ./handlers/scheduling -run TestCleanupOldReservations
2026-03-07 18:02:13 +00:00
popertots faa4d89152 Implement business logic changes: deposits, no-shows, reservations, approval workflow
CHANGES:
Phase 1: Schema
- Change deposits_required default from 3 to 0 for new users
- Add forgiven_no_shows table to track forgiven no-show bookings

Phase 2: No-Show Logic (manage.go)
- CountUnforgivenNoShows(): Count unforgiven no-shows in 6-month period
- ApplyDepositsIfNeeded(): Auto-apply 3 deposits if 2+ no-shows detected
- ForgiveNoShowsForUser(): Clear no-shows and reset deposits on full payment

Phase 3: Slot Reservation System
- Add CleanupOldReservations() to delete 1h+ old reservation blockers
- Call cleanup in GetAvailableHours() on each availability check
- Delete existing user reservation before creating new booking

Phase 4: Minimum Advance Time
- Changed from 48h (deposit-only) to 1h (all users)
- Now universally enforced at booking creation time

Phase 5: Notes-Based Approval Workflow
- If booking has notes (not empty) → status = 'pending' (needs approval)
- If no notes → status = 'confirmed' (auto-approved)
- Uses CASE statement in INSERT for status determination

Phase 6: Late Night Lock
- After 22:00, non-admin users cannot book next morning before 11:00
- Implemented in GetAvailableHours() via artificial blocker subtraction
- Admin users see all times (no restriction)

Phase 7: Admin Notifications
- Notify admin if booking has notes OR is for same day
- All qualifying bookings trigger notification for admin review

VERIFICATION:
✓ Build passes: go build -tags dev ./main.go succeeds
✓ All 7 phases implemented as per dev-approved plan
✓ No breaking changes to existing schemas
✓ Backward compatible with existing booking flow
2026-03-07 16:38:23 +00:00
popertots 2c6dcc066d cron nbtb 2026-03-04 20:36:04 +00:00
popertots 182adaed6d fix nbtb, add tests 2026-03-04 20:12:07 +00:00
popertots 7c3f922725 Fix nbtb, add tests 2026-03-04 20:11:51 +00:00
popertots 29b9776a93 non-booking-time-blockers (nbtb) 2026-03-04 11:38:34 +00:00
popertots dd097c1022 Large manual tests corruption fix 2026-03-02 18:07:13 +00:00
popertots 817d5dd021 Test docstrings 2026-03-02 11:37:31 +00:00
popertots eac5dccc3c testing update + docs 2026-03-02 10:16:55 +00:00
popertots df3439bd70 fix: improve test infrastructure and add ID validation
- Add TestMain to set test env vars and testdb.TruncateTables for test
  isolation
- Add chi routing context to test helpers for path parameter extraction
- Fix SQL error handling to use errors.Is() instead of ==
- Add validators package with ID validation
- Fix admin test middleware chain (RequireAdmin wrapper)
- Update test user inserts to include phone and date_of_birth fields
- Update service delete test to check soft-delete (is_active=false)
- Update holiday hours test to use new schema (weekday, is_open)
- Add phone number validation tests for UK mobile numbers
2026-02-23 00:59:32 +00:00
popertots 355e8a26c1 fix: correct middleware chain in scheduling NonAdmin tests
- RequireAdmin needs RequireAuth to populate context first
- Add mw.RequireAuth wrapper to all NonAdmin test middleware chains
- Tests now properly validate auth before checking admin role
- Tests passing: 30/33 (up from 24/27)
- Remaining failures are handler bugs, not test setup issues
2026-02-22 00:34:53 +00:00
popertots ed5598a59f fix: correct time format assertions in scheduling tests
- Database returns HH:MM:SS format, tests expected HH:MM
- Fix assertions in TestScheduling_GetDefaultHours and TestScheduling_UpdateDefaultHours_Admin
- Tests now pass: 24/27 (up from 18/27)
- Remaining failures are real test logic issues
2026-02-22 00:31:04 +00:00
popertots fb0a7fa59b fix: test database setup and scheduling test build error
- Add explicit verification loop in local-dev-2.sh to wait for crussell_test database to be ready before running tests (prevents race condition)
- Remove unused 'handler' variable declaration in scheduling_test.go that was breaking the build
- Tests now properly execute without immediate 'database does not exist' errors
- Real test failures are now visible instead of being masked by setup issues
2026-02-22 00:20:28 +00:00
popertots 9ca102153b Add crussell_test database creation and schema seeding to dev script
- Create crussell_test database after PostgreSQL reset
- Seed test DB schema from init-script.sql so tests can run
- This fixes the TLS connection errors in test runs

Also:
- Fixed color variables in script (C_RESET, C_GREEN, etc.)
2026-02-22 00:06:03 +00:00
popertots 44cac94f64 Fix test setup and middleware chain - Handler tests now passing
- Fix TestRequireRoleMiddleware by chaining RequireAuth before RequireRole (role context requirement)
- Remove unused 'strings' import from testdb.go
- Create crussell_test database in Docker setup
- Tests now properly initialize authentication context for role-based tests

Result: handlers test suite passes (13/13 tests)
Remaining failures in admin/auth/bookings/portfolio/scheduling/services/user packages need further investigation (environment setup, database constraints, endpoint initialization)
2026-02-21 23:50:17 +00:00
popertots f536a7fd04 Fix booking count filters, add admin notifications, and improve bookings
UI
2026-01-06 16:45:17 +00:00
popertots 989e45e55c add holiday test and tweak services 2025-10-21 00:26:21 +01:00
popertots ded1081a16 fix calendar again 2025-10-20 20:19:31 +01:00
popertots 17ebaeba94 Add exceptional hour modals 2025-10-19 21:17:28 +01:00
popertots 5efc893269 split exceptional from default hours 2025-10-19 18:40:54 +01:00
popertots 35f5dd2563 time picker changes 2025-10-17 00:08:40 +01:00
popertots 8c7d9d159f add GetAvailableHours 2025-10-15 21:25:45 +01:00
popertots 29aaa7392e Working default hours update 2025-10-14 22:09:49 +01:00