5.8 KiB
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
- Tim creates Stripe account (stripe.com)
- Connects business bank account
- We get API keys from Stripe Dashboard
- Store in
.envon 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
- Calendar view — booked/available/blocked dates
- Booking management — confirm, cancel, view details
- Guest directory — past guests, contact info, stay history
- Rate management — seasonal pricing, minimum stays
- Block dates — maintenance, owner use
- Revenue reports — monthly/annual totals
- 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
- ✅ Design complete
- Set up Stripe account for Tim
- Build FastAPI backend
- Deploy on Core
- Wire up booking widget on landing page
- Test end-to-end booking flow
- Go live