Files
mooresunnydaze/docs/stripe-reservation-system.md

5.8 KiB

Moore Sunny Daze — Reservation System with Stripe

Architecture Overview

Guest Browser → Landing Page → Check Availability → Book → Stripe Checkout → Confirmation
                                            ↑
                              Admin Dashboard (Tim)

Components

1. Public Booking Flow

Landing Page (mooresunnydaze.com)
  → "Check Availability" button
    → Availability calendar (fetches from API)
      → Select dates → guest count → price quote
        → Guest details form (name, email, phone, # guests, pet?)
          → Stripe Checkout (embedded or redirect)
            → Confirmation page + email

2. Backend API (FastAPI on Core/app1)

Endpoint Method Purpose
/api/availability GET Get booked dates for a month
/api/quote POST Calculate price for selected dates
/api/booking POST Create booking (pending payment)
/api/booking/{id}/confirm POST Confirm after Stripe payment
/api/booking/{id} GET View booking details
/api/guest/{email} GET Lookup returning guest

3. Database Schema (SQLite)

-- Guests
CREATE TABLE guests (
  id TEXT PRIMARY KEY,
  name TEXT NOT NULL,
  email TEXT UNIQUE NOT NULL,
  phone TEXT,
  notes TEXT,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Bookings
CREATE TABLE bookings (
  id TEXT PRIMARY KEY,
  guest_id TEXT REFERENCES guests(id),
  check_in DATE NOT NULL,
  check_out DATE NOT NULL,
  guests_count INTEGER NOT NULL,
  nightly_rate REAL NOT NULL,
  cleaning_fee REAL DEFAULT 150,
  total REAL NOT NULL,
  status TEXT DEFAULT 'pending', -- pending, confirmed, cancelled, completed
  stripe_session_id TEXT,
  stripe_payment_intent TEXT,
  notes TEXT,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Blocked Dates
CREATE TABLE blocked_dates (
  date DATE PRIMARY KEY,
  reason TEXT -- 'booking_XYZ', 'maintenance', 'owner'
);

-- Rate Rules
CREATE TABLE rate_rules (
  id TEXT PRIMARY KEY,
  name TEXT,
  start_date DATE,
  end_date DATE,
  nightly_rate REAL,
  min_nights INTEGER DEFAULT 3
);

Stripe Integration

Setup

  1. Tim creates Stripe account (stripe.com)
  2. Connects business bank account
  3. We get API keys from Stripe Dashboard
  4. Store in .env on server

Payment Flow

# 1. Create Stripe Checkout Session
session = stripe.checkout.Session.create(
    payment_method_types=['card'],
    line_items=[{
        'price_data': {
            'currency': 'usd',
            'product_data': {
                'name': f'Moore Sunny Daze — {nights} nights',
                'description': f'{check_in} to {check_out}, {guests} guests'
            },
            'unit_amount': int(total * 100),  # cents
        },
        'quantity': 1
    }],
    mode='payment',
    success_url='https://mooresunnydaze.com/booking/confirmed?session_id={CHECKOUT_SESSION_ID}',
    cancel_url='https://mooresunnydaze.com/booking/cancelled',
    customer_email=guest_email,
    metadata={
        'booking_id': booking_id,
        'property': 'moore-sunny-daze'
    }
)

# 2. Redirect to session.url
# 3. Stripe webhook → mark booking confirmed

Webhook Handling

@app.post("/stripe-webhook")
async def stripe_webhook(request: Request):
    payload = await request.body()
    sig = request.headers.get('stripe-signature')
    event = stripe.Webhook.construct_event(payload, sig, WEBHOOK_SECRET)

    if event['type'] == 'checkout.session.completed':
        session = event['data']['object']
        booking_id = session['metadata']['booking_id']
        mark_booking_confirmed(booking_id)
        send_confirmation_email(booking_id)
        add_blocked_dates(booking_id)

    return {"status": "ok"}

Deployment

Server

  • Deploy on Core (152.53.33.195) as systemd service
  • Port: 8910 (internal)
  • Caddy reverse proxy: mooresunnydaze.com/api/* → localhost:8910

Filesystem

/opt/mooresunnydaze/
├── server.py          # FastAPI app
├── db.sqlite          # SQLite database
├── .env               # STRIPE_SECRET_KEY, etc
├── requirements.txt   # fastapi, uvicorn, stripe, aiosqlite
└── templates/         # Email templates

systemd Service

# /etc/systemd/system/mooresunnydaze.service
[Unit]
Description=Moore Sunny Daze Booking API
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/opt/mooresunnydaze
ExecStart=/opt/mooresunnydaze/venv/bin/uvicorn server:app --host 127.0.0.1 --port 8910
Restart=always

[Install]
WantedBy=multi-user.target

Admin Features

  1. Calendar view — booked/available/blocked dates
  2. Booking management — confirm, cancel, view details
  3. Guest directory — past guests, contact info, stay history
  4. Rate management — seasonal pricing, minimum stays
  5. Block dates — maintenance, owner use
  6. Revenue reports — monthly/annual totals
  7. Email templates — confirmation, pre-arrival, post-stay

Pricing Integration

Tim's property is currently listed at ~$295/night (peak season, from Airbnb). We'd implement:

  • Base rate: $295/night peak, $225/night off-peak
  • Cleaning fee: $150 flat
  • Pet fee: $50 (if applicable)
  • Minimum stay: 3 nights
  • Holiday premium: +20% for major holidays

Comparison: Direct vs VRBO

VRBO (current) Direct (our system)
3-night stay @ $295 $885 + VRBO fee (~$130) $885 (no fee)
Guest pays ~$1,015 $885
Owner receives ~$885 - VRBO 5% host fee $885 - Stripe 2.9%
Owner net ~$840 ~$859
Savings to guest $130 (13%)
Savings to owner ~$19/stay + guest relationship

Next Steps

  1. Design complete
  2. Set up Stripe account for Tim
  3. Build FastAPI backend
  4. Deploy on Core
  5. Wire up booking widget on landing page
  6. Test end-to-end booking flow
  7. Go live