- Replace flat mustard with softer champagne tones and gentler shadows - Hero eyebrow: Book direct · Shitaye Suite Hotel - Lighter pattern grid, chips, badges, card hover ring; meetings band ring toned down - Ignore .dev.vars and .wrangler for local secrets and cache Made-with: Cursor
8.5 KiB
Booking & payments — administrator panel specification
This document describes the guest booking domain as implemented in the Shitaye FrontEnd demo today, and what a separate administrator application should support to manage bookings, holds, and payments. Use it as a blueprint when you build the admin API, database schema, and UI.
The public site lives in this repository (Shitaye-FrontEnd). The admin panel is not included here; this README is the handoff for that work.
1. Goals of the admin system
- List and search reservations (by date, status, guest, reference, room, payment state).
- Open a booking and see full guest, stay, pricing, flight/arrival, coupons, and payment metadata.
- Reconcile payments (paid, pending, failed, refunded) against holds or confirmed bookings.
- Operational actions (policy-dependent): cancel hold, extend hold, mark no-show, issue refund, add internal notes, export for finance.
2. Current public app (this repo) — important limitations
Today the storefront is a client-side mock:
- State lives in React context (
BookingProvider) in the browser — nothing is persisted to your backend when a guest “books”. submitBookingHoldandprocessPaymentinsrc/lib/mocks/api.tsonly simulate latency and return fake IDs (SHY-…,PAY-…).- No real card processing, no webhooks, no idempotent payment IDs.
Implication for admin: you will introduce a real backend (or extend an existing PMS/booking engine). The admin panel should talk to that system, not to the in-memory Next.js state.
Reference files in this repo
| Area | Path |
|---|---|
| Guest & stay state | src/context/BookingContext.tsx |
| Guest shape | GuestDetails in same file |
| Hold / payment mock API | src/lib/mocks/api.ts |
| Room catalogue (ids, rates) | src/lib/mocks/rooms.ts |
| Tax rate | src/lib/mocks/site.ts (taxRate, e.g. 0.15 = 15%) |
3. Domain model (what to persist)
3.1 Guest (contact + arrival)
Aligned with GuestDetails:
| Field | Type | Notes |
|---|---|---|
firstName |
string | |
lastName |
string | |
email |
string | Primary contact; unique per booking or account policy TBD |
phone |
string | E.164 recommended in production |
flightBookingNumber |
string | PNR / record locator / ticket ref |
arrivalTime |
string | Currently HH:mm from UI; store as time or datetime with timezone (Addis Ababa) in production |
3.2 Stay
| Field | Type | Notes |
|---|---|---|
checkIn |
date (ISO date) | YYYY-MM-DD in UI |
checkOut |
date (ISO date) | |
guests |
integer | 1–12 in UI |
roomId |
string | Catalogue key: penthouse, standard, connecting-suite, junior-studio (see rooms.ts) |
nights |
integer | Derived; validate against check-in/out |
3.3 Pricing (display currency vs ledger)
The storefront shows USD catalogue rates on the server-side math, with an optional display currency (EUR, GBP, AED, etc.) via CurrencyContext / src/lib/currency.ts.
Admin / accounting recommendation
- Store amounts in a single base currency (e.g. ETB or USD) per property policy.
- Store FX snapshot at booking or payment time if you show multi-currency to guests.
- Line items to persist (mirroring checkout):
| Concept | Source in app |
|---|---|
| Nightly subtotal | nightlyRate × nights from room catalogue |
| Coupon code | string |
| Discount % | e.g. 10 or 5 (mock codes SHITAYE10, WELCOME5) |
| Discount amount | % of subtotal |
| Tax | siteConfig.taxRate × taxable base (after discount) |
| Total | Grand total charged or to be charged |
3.4 Hold vs payment (lifecycle)
The UI distinguishes:
| Concept | Flag / field | Meaning |
|---|---|---|
| Hold reference | holdReference |
e.g. SHY-… — created when guest continues from /booking (pay now or pay later path) |
| Pay later | payLaterHold |
true if guest chose “Reserve now — pay later” before visiting payment |
| Payment confirmation | confirmationId |
e.g. PAY-… after successful (mock) payment |
| Paid timestamp | paidAt |
ISO datetime string |
Suggested persisted statuses (you can rename):
draft— abandoned cart (optional)held— hold created, not paid (payLaterHoldmay be true or false; both paths create a hold in the current flow)payment_pending— guest on payment step (optional transient)confirmed— payment succeeded (confirmationId+paidAt)cancelled/expired— hold released or timeout
Map the mock’s payLaterHold to your policy: e.g. held unpaid vs held with intent to pay later.
4. Mock API payloads (prototypes for real endpoints)
Today’s TypeScript types in src/lib/mocks/api.ts:
4.1 Create hold (after guest details + flight)
BookingPayload:
roomId,email,flightBookingNumber,arrivalTime
Real API should also accept: checkIn, checkOut, guests, full guest name/phone, pricing breakdown, coupon fields — everything needed to reconstruct the reservation without trusting the client for totals.
Response (mock): { reference: string }
4.2 Process payment
PaymentPayload:
totalCents(integer; mock uses USD × 100)last4(optional; card last four — never store full PAN in admin DB)
Response (mock): { confirmationId: string, paidAt: string }
Production: integrate PSP (Stripe, Chapa, etc.), store payment intent ID, status, receipt URL, and audit trail; admin reads from your payment service or synced tables.
5. Room catalogue keys (admin filters & reports)
Use the same id values as src/lib/mocks/rooms.ts unless you migrate to UUIDs:
roomId |
Display name (short) |
|---|---|
penthouse |
The 4 Bedroom Penthouse |
standard |
Standard Rooms |
connecting-suite |
Connecting Suite |
junior-studio |
Junior Studios |
Each room has nightlyRate (USD in mock), maxGuests, slug for public URLs.
6. Administrator panel — recommended features
6.1 Dashboard
- Today’s arrivals / departures
- Unpaid holds (pay-later + overdue)
- Revenue snapshot (range selector)
6.2 Bookings list
- Filters: status, date range (stay or created), room, email, hold ref, payment ref
- Sort: check-in, created at, total
- Bulk export CSV (finance)
6.3 Booking detail
- Guest, stay, room, pricing lines, coupon, flight/PNR, arrival time
- Payment section: provider, amount, currency, status, timestamps, refund button (if allowed)
- Internal notes (staff-only), activity log
6.4 Payments
- List transactions linked to bookings
- Reconciliation view (settled vs pending)
- Manual “mark paid” only if you accept bank transfer / cash — with strict RBAC
6.5 Configuration (optional)
- Tax rate, active coupon codes, hold TTL, room rates (or sync from PMS)
7. Security & compliance
- RBAC: roles such as
viewer,front_desk,finance,superadmin. - PII: encrypt at rest where required; minimize data in logs; GDPR-style export/erase if you serve EU/UK guests.
- PCI: never store raw card data; use tokenization via your PSP; admin UI shows only last4 / brand if provided.
- Audit: who changed status, refunds, or manual overrides.
8. Integrating the public Next.js app later
Replace src/lib/mocks/api.ts calls with fetch/axios to your backend:
- POST
/bookings/hold— persist reservation + return realholdReference - POST
/bookings/:id/payor PSP redirect + webhook — update status to confirmed - Optional GET
/bookings/:reffor guest “lookup my booking”
The admin app should use the same API (or an internal admin API with stronger scopes) so there is a single source of truth.
9. Open decisions (product / engineering)
- Single vs multi-property admin
- Whether “pay later” holds expire automatically and how guests resume payment (magic link vs login)
- Official currency of record and whether ETB is required for local compliance
- Connection to an existing PMS (Opera, Cloudbeds, etc.) vs custom DB only
10. Document maintenance
When you change the guest booking flow in Shitaye-FrontEnd, update:
- Section 3 (fields), 4 (payloads), and 5 (room ids)
- This file path:
ADMIN_BOOKING_README.md(repository root)
Prepared for Yaltopia / Shitaye Suite Hotel — booking management administrator development.