Marketplace Starter Kit

Inbox & Messaging

Architecture, schema design, and business logic for guest-to-host messaging and quoting.

Overview

The Inbox & Messaging module is a critical feature in the marketplace. It facilitates communication between guests and hosts and acts as a precursor to bookings. The system supports:

  • Standard messaging
  • Custom quote generation
  • Real-time price breakdowns based on listing configurations

Use Cases

  • Guests can inquire about availability and details before booking
  • Hosts can offer tailored pricing or packages
  • Messaging interface can evolve into a full inbox or conversation thread

UI & Component Architecture

MessageHostContainer.tsx

This container handles:

  • Rendering dynamic forms based on the listing’s pricingStrategy
  • State management via react-hook-form + zod
  • Live price calculations using useDeepCompareEffect
  • Conditional rendering of time pickers, alcohol checkbox, and custom activity fields

Key Concepts:

  • Controlled inputs for all fields (dates, guests, activity, etc.)
  • Dynamically calculates price as the user adjusts the form
  • Triggers a dialog (PriceBreakdownDialog) to confirm pricing before submission
  • Displays error feedback on submission failure

Schema Design

Zod Schema (MessageHost.schema.ts)

z.discriminatedUnion("type", [
  z.object({ type: z.literal("LUMPSUM"), listingId, activity, numberOfPeople, consumeAlcohol, message }),
  z.object({ type: z.literal("PER_HOUR"), listingId, date, from, to, ... }),
  z.object({ type: z.literal("CUSTOM"), listingId, activity, message }),
])

Why Discriminated Unions?

  • Enables dynamic validation and conditional form rendering
  • Prevents invalid field combinations depending on strategy
  • Simplifies inference and autocomplete for consumers of the schema

Utilities

calculateLumpsumPrice, calculatePerHourPrice

These functions receive listing metadata and guest input, then compute pricing:

  • Lumpsum: flat rate per person + alcohol surcharge
  • Per Hour: hourly rate × duration
  • Custom: optional pricing

Internally they use:

  • differenceInHours from date-fns
  • Alcohol multiplier logic
  • Configurable pricing per listing record

Messaging Logic

Currently the "Send Message" flow:

  1. Validates input with Zod
  2. Shows a price breakdown dialog for confirmation
  3. Submits data to a messageHost mutation or route (tRPC or REST depending on backend)
  4. Creates an initial message or pending booking intent in DB

Potential Improvements

Full Inbox View

  • Build an inbox by grouping messages per listing/user
  • Use Supabase realtime to sync new messages
  • Add read/unread tracking, timestamps, and indicators

Real-Time Chat

  • Use Supabase channel subscriptions or WebSockets
  • Allow hosts and guests to chat before or after a booking

Quotes as Bookings

  • Quote messages could trigger draft bookings
  • Improve conversion by enabling "Accept Quote" → "Book Now"

Attachments

  • Support file/image uploads for proposals or verification
  • Use Supabase storage with signed URLs

Security & Abuse Protection

  • Validate message payloads against session identity
  • Rate-limit submissions per user/listing
  • Optionally scan messages for harmful content (e.g. profanity, links)

File Index

FileResponsibility
containers/message-host/MessageHostContainer.tsxMessaging UI, form state, rendering
containers/message-host/MessageHost.schema.tsZod schema validation per strategy
utils/calculateBookingPrice.tsPricing computation logic
components/ui/loading-button.tsxUI button with pending state
components/ui/dialog/PriceBreakdownDialog.tsxDialog to confirm price before submission