feat: PDF receipts, property view tracking, booking reminders, occupancy heatmap - #1
Merged
Hovibby merged 41 commits intoAug 31, 2026
Merged
Conversation
Closes Rentars#329 Closes Rentars#330 Closes Rentars#331 Closes Rentars#332 - Cursor-based keyset pagination for notifications and bookings; useNotifications and useDashboard updated for infinite scroll (Rentars#329) - Sanitize all UGC on write: property descriptions, review comments, host responses; strips HTML/dangerous protocols, enforces length limits (Rentars#330) - Obfuscate exact coordinates on public property responses; reveal precise pin only to confirmed tenants and hosts; PropertyMap renders area circle vs pin (Rentars#331) - hCaptcha middleware on register/login/password-reset; server-side verification; HCAPTCHA_ENABLED=false bypass for dev; fail-closed in production (Rentars#332)
- Add RLS integration test suite (tests/rls/rls-policies.test.ts) covering profiles, bookings, wishlists, notifications, properties, property_images - Add migration 00021: enable RLS on wishlists and notifications tables - Add migration 00020: covering indexes for hot query patterns on bookings, properties, reviews, notifications, and availability_ranges - Add validate-migrations.ts script; exits 1 on duplicate/out-of-order prefixes - Wire migration validation into CI via .github/workflows/ci.yml - Add unit tests for validate-migrations.ts script - Add idempotent seed script database/seed.ts (bun run db:seed) - Add MIGRATIONS_NAMING.md documenting legacy duplicates and naming convention - Fix setup.sql to run all 31 migrations in canonical order - Fix tsconfig.json rootDir to include tests/ and scripts/ directories - Add SUPABASE_ANON_KEY to .env.test and .env.example - Update README.md and tests/README.md with instructions Closes Rentars#317 Closes Rentars#318 Closes Rentars#319 Closes Rentars#320
…ncy heatmap (a) PDF receipt download - Zero-dependency PDF builder (src/utils/pdf.ts) - GET /api/v1/bookings/:id/receipt.pdf - tenant/host only, confirmed/completed bookings - Download Receipt button on BookingConfirmationPage (b) Property view tracking - property_views table with 1-hour dedup window and bot filtering - POST /api/v1/properties/:id/view (anon-friendly) - GET /api/v1/properties/:id/views - host-only stats + sparkline dashboard widget (c) Booking reminders - booking_reminders table prevents duplicate delivery across job runs - Scheduler sends check-in/check-out reminders at configurable lead time - Respects per-user notification preferences - Configurable via REMINDER_CHECKIN_HOURS / REMINDER_CHECKOUT_HOURS env vars (d) Occupancy heatmap - GET /api/v1/properties/:id/occupancy-heatmap - host-only daily status - Calendar heatmap component with booked/blocked/available colour+pattern coding - Accessible: status conveyed by pattern (dot/hatch) not colour alone - Selectable property and 1/2/3-month horizon Tests: 64 new tests across 4 test files; 7 Storybook stories for the heatmap
…rice breakdown transparency closes Rentars#239 closes Rentars#238 closes Rentars#237 closes Rentars#236 - Rentars#238: submitReview now requires a Completed booking with checkout date in the past; returns descriptive errors for cancelled, disputed, and not-yet-completed stays. Added createReviewSchema validator requiring bookingId. Added DB migration with no-self-review CHECK constraint. - Rentars#239: addHostResponse switched from blocking second writes to upsert semantics so hosts can edit their single response. Ownership is now verified via property.owner_id when the review has a property_id. Added 1000-char length validation; non-owner attempts return 403. - Rentars#237: createSeasonalPricing and createSpecialEvent validate price_multiplier bounds [0.1, 10] and require start_date < end_date. New previewPricing enforces per-day MIN/MAX price bounds. New GET /api/v1/properties/:id/pricing/preview endpoint (host-only). - Rentars#236: getPropertyQuote returns base_nightly_rate, nights, subtotal, dynamic_adjustments, platform_fee (5%), and total. New public GET /api/v1/properties/:id/quote endpoint. BookingForm uses the quote endpoint and displays the itemized breakdown. useBookingDetails exposes priceBreakdown.
…ark mode A - BookingForm edge-case tests - Add minStay/maxStay props with stayViolation submit gate - 15 deterministic tests: end-before-start, zero-night, missing dates, unavailable dates, blocked pricing, min/max stay violations, guest count under/over limit, submit gating, price recomputation, happy path - Add WithGuestLimit/WithStayLimits Storybook stories B - Request timeout middleware - createTimeoutMiddleware with configurable REQUEST_TIMEOUT_MS / REQUEST_TIMEOUT_UPLOAD_MS env vars (default 30s / 120s) - AbortSignal on req.signal + res.locals.signal for upstream cancellation - 504 response with REQUEST_TIMEOUT error code on expiry - Double-send prevention via res.headersSent guard - Wired into index.ts; error middleware updated with headersSent guard - 8 unit tests covering all timeout behaviour guarantees C - Stable machine-readable error codes - Expand types/errors.ts: ValidationError, RateLimitError, InfraErrorCode - ERROR_STATUS_MAP covers all 25+ codes in error middleware - apps/web/src/lib/errors/errorCodes.ts: getErrorMessage(), isApiError(), full user-friendly message catalogue for every code - BookingForm uses new error helpers for API error display - 17 unit tests asserting correct HTTP status + code on every error class D - Dark mode fixes (20 components) - Replace all hardcoded light-only Tailwind colours with dark: variants - Booking: BookingForm, AvailabilityCalendar, HouseRulesAcknowledgement, BookingConfirmation, WalletConnectionModal, USDCEscrowFlow, EscrowStatusCard, BookingConfirmationPage, booking/page.tsx - Search: PropertyCard, FilterSidebar - Property: PropertyDetail - Dashboard: Analytics, BookingHistory, PropertyManagement, HostCalendarManagement, NotificationSystem, ProfileManagement, PropertyCalendar - All key screens target WCAG AA contrast in dark mode Zero TypeScript diagnostics across all 30 changed files.
- Add per-file retry button for failed uploads with max 3 retry attempts - Track retry count and prevent infinite retry loops - Block form progression when uploads are in progress - Display upload status indicator in PhotosStep - Disable Next button during uploads on photos step - Preserve upload progress state and file ordering
- Implement Leaflet-based map with react-leaflet-cluster integration - Replace basic iframe map with interactive clustered markers - Display property price markers with automatic grouping at lower zoom levels - Show cluster bubbles with property counts that expand on zoom - Maintain individual price markers when clusters expand - Preserve active property highlighting and click interactions
- Document Review endpoints (create, get by property/user, respond, flag, moderate) - Document Wishlist endpoints (list, add, remove) - Document Notification endpoints (list, mark read, preferences, push subscription) - Document Calendar endpoints (availability, seasonal rates, events) - Document Sync endpoints (sync properties and bookings) - Add comprehensive schemas for all new entities - Integrate swagger-ui-express for interactive API documentation - Reference shared schema components to avoid duplication - Include proper security, parameters, and error response documentation Closes Rentars#256
…control - Implement 400ms debouncing in BoundsListener to reduce excessive requests - Add bounds comparison to skip redundant queries when bounds haven't changed - Implement AbortController in usePropertySearch to cancel outdated requests - Add searchByBounds function with automatic debouncing and abort handling - Create 'Search this area' button for manual map-based searches - Track current map bounds and display button only when bounds are available - Add loading state to button during active searches
Issue Rentars#257: Database connection retry with backoff at startup - Create retry utility with exponential backoff - Probe Supabase and Redis connectivity before starting server - Configurable via environment variables: - STARTUP_RETRY_ATTEMPTS (default: 5) - STARTUP_RETRY_INITIAL_DELAY_MS (default: 1000) - STARTUP_RETRY_MAX_DELAY_MS (default: 30000) - Log each attempt and final outcome - Exit with code 1 if all retries exhausted Issue Rentars#258: Graceful shutdown handling - Register handlers for SIGTERM and SIGINT signals - Stop accepting new connections when signal received - Wait for in-flight requests to complete (configurable timeout) - Configurable via GRACE_SHUTDOWN_TIMEOUT_MS (default: 30000) - Exit with code 0 on clean shutdown, 1 if timeout exceeded - Handle uncaught exceptions and unhandled rejections - Add comprehensive tests for retry logic and configuration - Proper logging with context and correlation Closes Rentars#257 Rentars#258
…st toggling - Add 300ms debouncing to coalesce rapid wishlist toggles - Implement pending toggles tracking to batch API requests - Add error messages via toast notifications with clear feedback - Track state consistency with lastStateRef to prevent race conditions - Add getWishlistCount method for wishlist badge consistency - Implement automatic rollback on API failures with state restoration - Add authentication check with error feedback
Issue Rentars#259: Contract event emission on state transitions - Define event topics using ("booking", Symbol::short("<event_name>")) - Emit events on all booking state transitions: - "booked" - when booking is created - "confirmed" - when admin confirms booking (Pending → Confirmed) - "completed" - when booking is marked completed (Confirmed → Completed) - "cancelled" - when booking is cancelled - "disputed" - when tenant initiates dispute - "escrow_funded" - when escrow is funded - Events include relevant data: - booking_id, property_id, tenant, property_owner for all events - check_in, check_out, total_price for "booked" event - amount for "escrow_funded" event - Update CONTRACT_OVERVIEW.md with complete event schema documentation - Document each event topic, data structure, and triggers - Provide example event filters for backend sync service - Include integration guidance for off-chain services - Add comprehensive tests verifying event emission: - test_booked_event_emitted_on_create - test_confirmed_event_on_status_update - test_cancelled_event_on_cancel - test_disputed_event_on_dispute - test_escrow_funded_event Enables efficient off-chain event subscription via Stellar Event API instead of polling storage, improving sync efficiency and auditability. Closes Rentars#259
- Add moderation_status (pending/approved/rejected) and moderation_reason columns to reviews - New approveReview() and rejectReview() methods with reason support - Update public queries to show only approved reviews - Add getPendingReviews() for moderation queue - Add POST /reviews/:id/approve and POST /reviews/:id/reject endpoints - Add GET /reviews/moderation/pending endpoint - Filter reviewed content by moderation status across all public endpoints Implements Rentars#240
…earch results - Add PropertyListSkeleton display while loading properties - Add empty state with helpful message when no properties match - Add error state with retry button for failed searches - Update PropertyGrid to accept loading, error, and onRetry props - Make states mutually exclusive - Add stories for all three states - Add tests verifying loading, empty, and error states - Fix missing imports in PropertyCard
Validates required contract addresses, network passphrase, and RPC URL at application startup. Fails fast with clear error messages listing all missing or invalid configuration values. Only enforces contract requirements when BLOCKCHAIN_FEATURES_ENABLED is true.
- Add average_rating and review_count columns to properties table - Create database trigger to automatically update aggregates on review changes - Backfill existing properties with aggregate data from approved reviews - Update property search to use denormalized columns for rating-based scoring - Improve search performance by eliminating runtime review calculations - Only count approved reviews in aggregates Implements Rentars#241
Dynamically estimates transaction fees from live network fee-stats, selecting the 90th percentile with a configurable ceiling multiplier to prevent excessive fees during network congestion. Exposes estimated fee in USDC for display in booking quote UI.
- Centralize preference checks in notification service - Add shouldSendPush() and shouldSendInApp() preference validators - Add checkPushPreferences() function to push service - Update sendPushToUser() to enforce notification preferences - Create comprehensive createNotificationWithAllChannels() for multi-channel dispatch - Add migration to ensure notification_preferences table with proper defaults - Implement per-channel (email, push, in-app) preference enforcement - Document default notification types in database schema Implements Rentars#242
Periodically polls transaction status for bookings with pending escrow, transitions bookings to terminal states (confirmed/failed) based on on-chain results, and logs outcomes. Reconciliation runs every 5 minutes with bounded concurrency and exponential backoff on errors. Notifies tenants on booking failure via blockchain_logs table.
Persists listing form progress to localStorage with debounced saves, restores draft on mount with option to resume or discard. Draft is automatically cleared on successful listing creation. Includes DraftRestoreDialog component for user prompt on restoration.
- Create push_subscriptions table with unique user_id/endpoint constraint - Add POST /push/subscribe endpoint for registering subscriptions - Add POST /push/unsubscribe endpoint for removing subscriptions - Add GET /push/subscriptions endpoint to list user subscriptions - Implement push.controller.ts with validation and error handling - Add validatePushSubscription() function for input validation - Create usePushNotifications() React hook for frontend integration - Hook supports subscribe/unsubscribe with error handling - Automatic pruning of 404/410 responses (already in push.service) - Database indexes for efficient subscription lookups - Timestamps for subscription lifecycle tracking Implements Rentars#243
Fee estimation now uses a percentile-based calculation with configurable ceiling rather than querying RPC fee stats, which may not be available on all Stellar networks. Maintains the same high-level behavior.
- Create reusable Modal primitive with focus trapping - Handle Escape-to-close functionality - Restore focus to trigger on close - Add proper ARIA roles (aria-modal, role=dialog, aria-labelledby) - Make background content inert while modal is open - Refactor WalletConnectionModal to use new modal primitive - Add ModalHeader, ModalContent, ModalFooter subcomponents - Add stories demonstrating modal usage patterns - Add tests for focus trap, Escape close, and backdrop click
- Create centralized format utilities with Intl.NumberFormat and Intl.DateTimeFormat - Add formatUSDC, formatPricePerNight, formatDate, formatDateShort, formatDateRange helpers - Handle USDC decimal precision and consistent date range formatting - Replace hardcoded formatting in PropertyCard with helpers - Add comprehensive tests for all formatters covering precision and locales
- Define ValidationError class with normalized structure: { message, fields: { [field]: string[] } }
- Update error middleware to detect and return ValidationError with 400 status
- Refactor all validators (auth, booking, property, location, profile) to throw ValidationError
- Keep non-validation errors on their existing domain error shape
- Add unit tests for error middleware and validation error normalization
- Add integration tests verifying normalized error structure across endpoints
…sanitization-location-privacy-captcha feat: cursor pagination, XSS sanitization, location privacy, hCaptcha
…igrations-seed feat: RLS tests, indexes, migration validation, and seed script
feat: review eligibility, host response upsert, pricing validation & price breakdown
…review-notifications Feature/240 241 242 243 review notifications
…47-blockchain-and-draft Feature/244 245 246 247 blockchain and draft
…9-250-251 Feature/issues 248 249 250 251
…53-254-255 Feature/issues 252 253 254 255
…ful-shutdown-events
…259-api-docs-retry-graceful-shutdown-events Feature/256 257 258 259 api docs retry graceful shutdown events
…tests-timeout-error-codes-darkmode feat: booking tests, timeout middleware, error codes, dark mode
Hovibby
pushed a commit
that referenced
this pull request
Aug 31, 2026
…uploads (Rentars#222) (#1) - Add MAX_IMAGES_PER_PROPERTY (default 15) and MAX_IMAGE_SIZE_BYTES (default 5MB) to env schema - Update multer middleware to use env.MAX_IMAGE_SIZE_BYTES - Handle multer size and MIME type errors in error middleware - Enforce image count check in propertyImage service before uploading to storage - Add unit and integration tests for property image upload limits Closes Rentars#222
Hovibby
pushed a commit
that referenced
this pull request
Aug 31, 2026
fix: harden booking confirmation calendar actions
Hovibby
pushed a commit
that referenced
this pull request
Aug 31, 2026
…ardening Harden booking, calendar, and review inputs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
(a) PDF Receipt Download
src/utils/pdf.ts-- no new npm package requiredGET /api/v1/bookings/:id/receipt.pdf-- tenant or host only, confirmed/completed bookings onlyBookingConfirmationPage(b) Property View Tracking
property_viewstable with 1-hour dedup unique index,view_countcolumn onpropertiesview_countincrementPOST /api/v1/properties/:id/view(no auth required)GET /api/v1/properties/:id/views-- host-only stats + 30-day sparkline widget in dashboard(c) Booking Reminders
booking_reminderstable with unique constraint per (booking, type) -- prevents duplicates at DB levelnotification_types.booking_reminderpreferencecleanup-schedular.ts; configurable viaREMINDER_CHECKIN_HOURS,REMINDER_CHECKOUT_HOURS,REMINDER_INTERVAL_HOURS(d) Occupancy Heatmap
GET /api/v1/properties/:id/occupancy-heatmap-- host-only, returns per-day booked/blocked/available statusFiles changed
Backend (new)
apps/backend/src/utils/pdf.tsapps/backend/src/services/receipt.service.tsapps/backend/src/services/propertyView.service.tsapps/backend/src/services/reminder.service.tsapps/backend/src/services/occupancy.service.tsapps/backend/database/migrations/00020_add_property_views.sqlapps/backend/database/migrations/00021_add_booking_reminders.sqlapps/backend/src/__tests__/receipt.test.tsapps/backend/src/__tests__/propertyView.test.tsapps/backend/src/__tests__/reminder.test.tsapps/backend/src/__tests__/occupancy.test.tsBackend (modified)
apps/backend/src/controllers/booking.controller.tsapps/backend/src/controllers/property.controller.tsapps/backend/src/routes/booking.routes.tsapps/backend/src/routes/property.routes.tsapps/backend/src/middleware/auth.middleware.tsapps/backend/src/services/cleanup-schedular.tsapps/backend/.env.exampleFrontend (new)
apps/web/src/app/dashboard/host-dashboard/components/OccupancyHeatmap.tsxapps/web/src/app/dashboard/host-dashboard/components/PropertyViewStats.tsxapps/web/src/stories/OccupancyHeatmap.stories.tsxFrontend (modified)
apps/web/src/components/booking/confirmation/BookingConfirmationPage.tsxapps/web/src/app/dashboard/host-dashboard/components/PropertyList.tsxapps/web/src/app/dashboard/host-dashboard/page.tsxTests
64 new tests across 4 test files. 7 Storybook stories for the occupancy heatmap component.
Notes for reviewers
00020and00021against Supabase before deployingREMINDER_CHECKIN_HOURS,REMINDER_CHECKOUT_HOURS,REMINDER_INTERVAL_HOURSto your.env(defaults: 24h, 12h, 1h)