Commit Graph
24 Commits
Author SHA1 Message Date
popertotsandSisyphus 920eb761fd feat: add excludeUserID param to scheduling time blockers
Add optional excludeUserID parameter to GetTimeBlockersInRange and CheckTimeBlockerOverlap so a user's own RESERVATION entries are excluded from overlap checks. This prevents users from self-blocking on their existing reservation when checking availability or confirming a booking.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-05 11:44:52 +01:00
popertotsandSisyphus e4b9003439 refactor(handlers): migrate remaining backend handlers to clock.Now() and transaction patterns
Apply clock.Now() migration, transaction wrapping, and minor refactors across admin, scheduling, today, user, auth handler, notifications, webhooks, services, portfolio, ratelimit, testutils, and main.go.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-06-24 23:43:50 +01:00
popertotsandSisyphus bdee60d34f refactor(scheduling): batch queries and DRY retention filter
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-06-22 00:57:51 +01:00
popertotsandSisyphus 741107df89 refactor(scheduling): replace inline duration queries with booking fields
Simplify scheduling handlers by using bookings.total_duration_minutes and bookings.end_time computed columns instead of inline UNION sub-queries for duration calculations. Remove unnecessary ::text casts from end_time columns (using native timestamptz).

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-06-21 21:47:22 +01:00
popertotsandSisyphus 88892059c5 fix(scheduling): include reservations in GetTimeBlockersInRange and fix booking overlap query
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-06-21 21:00:47 +01:00
popertotsandSisyphus 3d0e2afc4c refactor(backend): migrate db.DB to db.Conn PoolProxy across all handlers
Replace direct *pgxpool.Pool usage with PoolProxy wrapper across the entire backend:

- db.DB renamed to db.Conn (*pgxpool.Pool -> *PoolProxy)
- JWT functions now accept context.Context instead of using context.Background()
- Handler DB calls route through PoolProxy for per-test transaction support
- Fixture/helper/testdb functions accept Querier interface for decoupling
- Query ordering fixed in bookings handlers: COUNT after data query to avoid pgx conn busy
- Time truncation fixed: time.Date instead of Truncate(24*time.Hour) for week start calc
- testmain_test.go files updated with SeedBaseline and NewPoolProxy

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-06-21 19:28:54 +01:00
popertotsandSisyphus 9f9899354c feat(backend): add time blocker management and name history cleanup
Add name history cleanup to the scheduling pipeline and improve time blocker tests.

- Call CleanupOldNameHistory from GetAvailableHours to periodically purge
  old name_history entries (6+ months)
- Add time_blockers_test.go with comprehensive test coverage
- Update time-blockers.go with name_history cleanup logic

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-06-20 16:58:59 +01:00
popertotsandSisyphus 6c89fea118 feat(backend): update scheduling handlers
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-06-18 16:26:39 +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
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
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 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 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 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
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 29b9776a93 non-booking-time-blockers (nbtb) 2026-03-04 11:38:34 +00:00