Add CreateTestDatabase function for parallel isolated test databases per package.
- Add CreateTestDatabase() for isolated test DBs (parallel-safe)
- Move all TestMain functions to per-package testmain_test.go files
- Remove old TestMain from handlers_test.go, jwt_test.go, main_test.go
- Add JWT init guard in main.go to skip when -test.* flags detected
- Update testdb.go with admin DSN and proper cleanup
- Rename test database to crussell_test_db for consistency
- Replace testdb.NewPool + testdb.Migrate pattern with CreateTestDatabase
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add generate_*_id() functions for consistent short ID generation across all tables.
- Convert user_social_logins, verification_codes, custom_services,
time_blockers, forgiven_no_shows, user_referrals from BIGSERIAL to CHAR(12)
- Add name_history, referral_discounts tables
- Add dedicated generate_*_id() functions for each table
- Add FK from name_history.booking_id to bookings(id)
- Add referral_discounts index on user_id
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Restructure loyalty card: show completed-card banner above card, support multi-card display (stamps % 10), move from gradient to flat bg, update text to reflect multi-card and remaining stamps.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Remove auto-apply of pending loyalty redemption during ProgressBookingHandler. Now only checks if loyalty was applied on this booking (via booking_discounts) to skip stamp award. Redemption is purely manual via ApplyLoyaltyRedemption. Use LoyaltyStampCost constant instead of hardcoded 10.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Extract LoyaltyStampCost and add LoyaltyDiscountPercent constant. Add first-payment guard to ApplyLoyaltyRedemption — reject if a non-discount payment already exists on the booking.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
The 14-day refresh threshold was designed for the old 30-day tokens but the backend now emits 1-hour tokens. The threshold caused every page load to trigger an immediate /refresh-token call, which revoked the old JTI mid-flight while concurrent requests (profile, giftcards, bookings, etc.) were still using it, causing 401 errors.
Changes:
- Refresh threshold: 14 days -> 5 minutes (matches 1-hour token lifetime)
- Interval check: 60 min -> 2 min (must be shorter than threshold)
- Race condition: refresh now completes before profile fetch, preventing JTI invalidation during concurrent requests
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Shows the total amount already paid in the cancellation confirmation, plus deposit-specific messaging: forfeiture warning when deposit is paid, and a note that outstanding deposit is no longer due when deposit is required but not yet paid.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
The admin_notifications.booking_id FK has no ON DELETE CASCADE, so hard-deleting a booking with existing notifications fails with a FK constraint violation. Fix by explicitly deleting related notifications before the booking DELETE.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Replace Card component with custom card design: group bookings by month, add color-coded status bars/badges/dots, fly transitions, loading skeletons, empty state with calendar icon, and improved time/date formatting. Remove dependency on shadcn Card component.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Load Playfair Display from Google Fonts via preconnect and stylesheet in root layout, then apply to h1 headings on BookingFlow, Account, and Contact pages for a consistent brand typography.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Populate booking.Services with a UNION query across booking_services and booking_custom_services tables, returning service name, price, duration, and override values.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>