Skip to main content

EP-016: Spa & Wellness Management

Business Objective​

Spa and wellness services represent a high-margin revenue stream for resort and luxury properties, typically contributing 8-15% of total revenue. Indian resorts, especially Ayurveda-focused properties in Kerala and Goa, need comprehensive spa management covering treatment catalogs, therapist scheduling, appointment booking, and seamless charge posting to guest folios. Without an integrated spa module, properties rely on paper registers or standalone spa software that cannot link charges to the PMS, causing revenue leakage and guest friction. This module also supports the growing trend of spa packages sold through the booking engine as add-ons during room reservation.

Audience​

  • Primary: Spa Manager, Spa Receptionist
  • Secondary: Guests (booking via booking engine or in-house), Front Desk Agent (viewing spa charges on folio)
  • Tertiary: Revenue Manager (spa revenue analytics), General Manager (P&L review)

Scope​

In Scope​

  • Treatment catalog: services with pricing, duration, GST rate, HSN code, images
  • Treatment packages: bundles of multiple treatments with package pricing
  • Therapist management: profiles, specializations, certifications, working hours
  • Therapist availability calendar with drag-and-drop scheduling
  • Appointment booking: date, time, therapist, treatment, spa room selection
  • Spa calendar view (day/week) with therapist rows and time columns
  • Guest check-in for spa appointments
  • Charge posting to guest folio via Kafka event
  • Spa revenue reports: daily revenue, therapist productivity, treatment popularity
  • Membership/package tracking: prepaid session balance, validity, usage history
  • Couple and group appointment bookings
  • Spa room management: treatment rooms, saunas, steam rooms, pools

Out of Scope​

  • Retail product sales (covered by POS module if spa has a retail outlet)
  • Gym equipment tracking and maintenance
  • Swimming pool chemical management
  • Therapist payroll/commission calculation (covered by HR module, future)

Current Implementation Status​

Backend (spa-service)​

  • Treatments: TreatmentsService with full CRUD, DTOs with name, description, duration, price, category, taxRate. Controller with pagination and filtering.
  • Therapists: TherapistsService with CRUD, DTOs include specializations, certifications, working hours, status. Controller present.
  • Appointments: AppointmentsService with CRUD, status transitions (BOOKED -> CONFIRMED -> IN_PROGRESS -> COMPLETED / NO_SHOW / CANCELLED). Filter by date, therapist, status. Includes treatment, therapist, spaRoom in response.
  • Spa Rooms: SpaRoomsService with CRUD, room type, capacity, amenities, status tracking.
  • Packages: PackagesService with CRUD, package DTOs include treatments list, package price, validity.
  • Scheduling: SchedulingService for availability checking and conflict detection.
  • Billing: BillingService with postToFolio() method that publishes SPA_CHARGE_CREATED Kafka event with appointment details, amount, and tax.
  • Tests: Spec files exist for treatments, therapists, appointments, packages, scheduling, billing services.

Dashboard (02-hmp-web-dashboard)​

  • Spa appointments page (/spa/appointments) with list/calendar views

Booking Engine (03-hmp-booking-engine)​

  • Spa treatment browser and booking form for guests to add spa treatments during reservation

Gap Analysis​

AreaCurrent StateGapImpact
Therapist CalendarTherapistsService stores working hoursInteractive drag-and-drop calendar not built in dashboardSpa manager cannot visually manage therapist schedules
Package TrackingPackagesService stores packagesNo prepaid session counter; no deduction on appointment completionGuests who bought 10-session packages have no balance tracking
Folio IntegrationBillingService publishes Kafka eventFrontdesk-service consumer for SPA_CHARGE_CREATED not confirmed working end-to-endSpa charges may not appear on guest folio reliably
Couple/Group BookingAppointment DTO supports single guestNo multi-guest appointment linking; no couple treatment pairingCouples must book two separate appointments manually
Revenue ReportsBasic analyticsNo therapist productivity report; no treatment popularity ranking; no spa-specific RevPATH (Revenue Per Available Therapist Hour)Spa manager lacks data-driven insights for scheduling and pricing
Availability WidgetSchedulingService checks conflictsBooking engine does not show real-time spa availability by time slotGuests cannot see available slots when booking online
Membership ManagementNot implementedNo recurring membership plans (monthly/annual); no auto-renewalProperty cannot sell spa memberships to local/repeat guests
WaitlistNot implementedNo waitlist when preferred time/therapist is unavailableLost revenue when guests cannot be queued for cancellations
Consent & Health FormNot implementedNo digital health/allergy form before treatment (Ayurveda requires Prakriti assessment)Liability risk; therapists lack guest health information

User Stories​

Story IDTitlePriorityPointsStatusSprint
US-016-001Treatment Catalog ManagementP05Built5
US-016-002Therapist Profile & Availability ManagementP05Built5
US-016-003Spa Appointment BookingP08Built5
US-016-004Spa Calendar View (Day/Week)P15Partial6
US-016-005Charge Posting to Guest FolioP05Partial6
US-016-006Prepaid Package & Session TrackingP18Not Started9
US-016-007Couple & Group Appointment BookingP25Not Started10
US-016-008Spa Revenue & Therapist Productivity ReportsP18Not Started9
US-016-009Guest Health & Consent Form (Digital)P25Not Started11

Dependencies​

  • EP-004 (Front Desk & Folio): Charge posting requires folio transaction creation in frontdesk-service
  • EP-001 (Auth & Access): Spa Manager and Spa Receptionist roles need appropriate RBAC permissions
  • EP-010 (Booking Engine): Spa availability widget on booking engine
  • EP-015 (Integrations): Thermal printer for spa appointment confirmations
  • EP-013 (Analytics & Reports): Spa revenue feeds into property-level P&L reports

Acceptance Criteria (Epic Level)​

  • Spa manager can create treatments, packages, and manage therapist schedules from the dashboard
  • Guests can book spa appointments via the booking engine with real-time availability
  • Completed spa appointments automatically post charges to the guest's room folio
  • Prepaid package sessions decrement correctly and display remaining balance
  • Spa revenue reports show daily revenue, therapist utilization, and treatment popularity
  • Couple bookings link two guests to the same time slot with paired therapists

KPIs / Success Metrics​

  • Spa booking conversion rate > 30% (from availability view to confirmed appointment)
  • Folio charge posting success rate: 100% (no missed spa charges)
  • Therapist utilization rate > 70% during peak hours
  • Package session tracking accuracy: 100% (zero discrepancies in prepaid balances)
  • Average time from appointment completion to folio posting < 5 seconds
  • Guest no-show rate < 10% (with automated reminders)

Detailed User Stories​

US-016-001: Treatment Catalog Management​

As a Spa Manager, I want to create and manage a catalog of spa treatments with pricing, duration, and GST rates, So that staff and guests can browse available services with accurate information. Priority: P0 | Points: 5 | Sprint: 5 | Status: Built

Implementation Status​

TreatmentsService provides full CRUD with DTOs covering name, description, category (Massage, Facial, Body Wrap, Ayurveda, etc.), duration in minutes, price, tax rate (GST 18% for spa services), HSN code, and active/inactive status. TreatmentsController exposes REST endpoints with pagination and category filtering. Booking engine has a treatment browser for guests.

Acceptance Criteria​

Scenario: Create a new Ayurveda treatment
Given the spa manager navigates to Spa > Treatments
When they click "Add Treatment" and enter:
| Field | Value |
| Name | Abhyanga Full Body Massage |
| Category | Ayurveda |
| Duration | 60 minutes |
| Price | INR 3,500 |
| GST Rate | 18% |
| HSN Code | 999722 |
Then the treatment is saved and appears in the catalog
And the treatment is available for appointment booking

Scenario: Deactivate a seasonal treatment
Given treatment "Summer Cool Body Wrap" exists and is active
When the spa manager toggles the treatment to "Inactive"
Then the treatment no longer appears in guest-facing booking
And existing appointments for this treatment remain unaffected
And the treatment still appears in revenue reports for historical data

US-016-002: Therapist Profile & Availability Management​

As a Spa Manager, I want to manage therapist profiles including specializations, certifications, and weekly schedules, So that appointments are assigned to qualified and available therapists. Priority: P0 | Points: 5 | Sprint: 5 | Status: Built

Implementation Status​

TherapistsService supports CRUD with DTOs for name, gender, specializations (array), certifications (array), working hours (JSON with day-wise start/end times), status (AVAILABLE, ON_LEAVE, INACTIVE). Controller with filtering by specialization and status.

Acceptance Criteria​

Scenario: Add therapist with Ayurveda specialization
Given the spa manager navigates to Spa > Therapists
When they add a new therapist:
| Field | Value |
| Name | Lakshmi Nair |
| Gender | Female |
| Specializations | Ayurveda, Swedish Massage |
| Certifications | CTAA (Ayurveda), Diploma in Spa |
| Working Hours | Mon-Sat 09:00-18:00 |
Then the therapist profile is created
And the therapist appears in the scheduling calendar
And only Ayurveda and Swedish Massage appointments can be assigned to this therapist

Scenario: Therapist leave blocks appointments
Given therapist "Lakshmi Nair" has status "AVAILABLE"
When the spa manager sets her status to "ON_LEAVE" for March 10-12, 2026
Then no new appointments can be booked for Lakshmi on those dates
And existing appointments on those dates are flagged with "Therapist On Leave" warning
And the spa manager receives a prompt to reassign affected appointments

US-016-003: Spa Appointment Booking​

As a Spa Receptionist, I want to book appointments by selecting date, time, treatment, therapist, and spa room, So that guests have confirmed spa sessions without double-booking. Priority: P0 | Points: 8 | Sprint: 5 | Status: Built

Implementation Status​

AppointmentsService with full lifecycle management. Status transitions enforced: BOOKED -> CONFIRMED -> IN_PROGRESS -> COMPLETED (or NO_SHOW/CANCELLED at appropriate stages). SchedulingService validates therapist availability and room conflicts. Filter by date, therapist, property, status. Includes treatment, therapist, and spaRoom relations in query responses.

Acceptance Criteria​

Scenario: Book spa appointment for in-house guest
Given guest "Priya Sharma" is checked in to room 302 (reservation RES-2026-001)
And treatment "Abhyanga Full Body Massage" is 60 min, INR 3,500
And therapist "Lakshmi Nair" is available on March 8 at 10:00 AM
When the spa receptionist books the appointment
Then the appointment is created with status "BOOKED"
And the time slot 10:00-11:00 is blocked for therapist "Lakshmi Nair"
And the selected spa room is reserved for the same time slot
And a confirmation notification is sent to the guest (SMS/WhatsApp)

Scenario: Prevent double-booking of therapist
Given therapist "Lakshmi Nair" has an appointment from 10:00-11:00 on March 8
When the receptionist tries to book another appointment for Lakshmi at 10:30
Then the system returns a conflict error "Therapist not available at selected time"
And suggests the next available slot for Lakshmi (11:00) or alternative therapists

Scenario: Walk-in appointment booking
Given a walk-in guest "Amit Patel" (not checked in) requests a massage
When the receptionist books without a reservation ID
Then the appointment is created with guestName but no reservationId
And payment is marked as "DIRECT_PAYMENT" (not folio posting)
And the guest can pay at the spa reception after the treatment

US-016-004: Spa Calendar View (Day/Week)​

As a Spa Manager, I want to view all appointments in a calendar format with therapists as rows and time as columns, So that I can see the daily schedule at a glance and manage workload. Priority: P1 | Points: 5 | Sprint: 6 | Status: Partial

Implementation Status​

Dashboard has a spa appointments page with list view. Gap: interactive calendar grid (therapist rows x time columns) not built; no drag-and-drop to reschedule; no color coding by treatment category or appointment status.

Acceptance Criteria​

Scenario: View daily spa schedule
Given 8 appointments are booked for March 8, 2026 across 3 therapists
When the spa manager opens the Spa Calendar in Day view
Then the calendar shows rows for each therapist (Lakshmi, Priya, Raju)
And columns for each 30-minute time slot from 09:00 to 20:00
And each appointment block shows guest name, treatment name, and duration
And appointments are color-coded: Ayurveda (green), Massage (blue), Facial (pink)

Scenario: Drag-and-drop reschedule
Given guest "Priya Sharma" has an appointment at 10:00 with therapist "Lakshmi"
When the spa manager drags the appointment block to 14:00 on the same day
And the 14:00 slot is available for Lakshmi and the spa room
Then the appointment time updates to 14:00-15:00
And the guest receives a reschedule notification
And the previous time slot becomes available for new bookings

US-016-005: Charge Posting to Guest Folio​

As a Spa Receptionist, I want to post completed spa charges to the guest's room folio, So that the guest can settle all charges at checkout without separate spa payment. Priority: P0 | Points: 5 | Sprint: 6 | Status: Partial

Implementation Status​

BillingService.postToFolio() publishes SPA_CHARGE_CREATED Kafka event with appointmentId, reservationId, description, amount, and taxAmount. The appointment's paidAmount is updated. Gap: frontdesk-service consumer that creates the actual FolioTransaction record needs end-to-end verification; no handling for guests with multiple folios (e.g., split billing); no reversal mechanism for cancelled spa charges already posted.

Acceptance Criteria​

Scenario: Post completed spa treatment to folio
Given guest "Priya Sharma" completed "Abhyanga Massage" (INR 3,500 + 18% GST = INR 4,130)
And her reservation RES-2026-001 has an open folio FOL-001
When the spa receptionist marks the appointment as "COMPLETED" and clicks "Post to Folio"
Then a SPA_CHARGE_CREATED Kafka event is published
And the frontdesk-service creates a FolioTransaction:
| Field | Value |
| transactionType | CHARGE |
| transactionCode | SPA |
| description | Spa: Abhyanga Full Body Massage |
| amount | 3,500 |
| taxAmount | 630 |
And the folio balance increases by INR 4,130
And the appointment payment status shows "Posted to Folio"

Scenario: Spa charge for non-resident guest (direct payment)
Given walk-in guest "Amit Patel" completed a facial treatment (INR 2,000)
And he has no reservation in the system
When the spa receptionist marks the appointment as "COMPLETED"
Then the "Post to Folio" option is disabled
And the receptionist records direct payment (cash/card/UPI)
And a receipt is generated with property name, GSTIN, treatment details, and GST breakdown

US-016-006: Prepaid Package & Session Tracking​

As a Spa Manager, I want to sell prepaid packages (e.g., 10 massage sessions) and track remaining sessions per guest, So that package guests are served correctly and revenue is recognized per session. Priority: P1 | Points: 8 | Sprint: 9 | Status: Not Started

Implementation Status​

PackagesService manages package definitions (treatments included, package price, validity period). Gap: no per-guest package purchase record; no session counter that decrements on appointment completion; no package expiry enforcement; no partial package refund logic.

Acceptance Criteria​

Scenario: Guest purchases 10-session massage package
Given package "Monthly Wellness" includes 10 Swedish Massage sessions for INR 25,000 (valid 6 months)
When guest "Priya Sharma" purchases the package
Then a package purchase record is created with:
| Field | Value |
| guestId | guest_priya |
| packageId | pkg_monthly |
| totalSessions | 10 |
| usedSessions | 0 |
| remainingSessions| 10 |
| validUntil | 2026-09-08 |
| paymentStatus | PAID |
And the INR 25,000 payment is recorded (folio or direct)

Scenario: Package session deducted on appointment completion
Given guest "Priya Sharma" has 7 remaining sessions on "Monthly Wellness" package
When her Swedish Massage appointment is marked "COMPLETED"
Then remainingSessions decrements to 6
And the appointment is linked to the package purchase record
And no additional charge is posted to the folio for this session

Scenario: Package expiry warning
Given guest "Priya Sharma" has 3 remaining sessions expiring on 2026-09-08
When the current date is 30 days before expiry (2026-08-09)
Then the system sends a reminder SMS/WhatsApp: "Your spa package expires in 30 days. 3 sessions remaining."
And the spa manager dashboard shows the expiring package in the "Expiring Soon" section

US-016-007: Couple & Group Appointment Booking​

As a Spa Receptionist, I want to book couple treatments and group spa sessions, So that guests booking together share a time slot with paired therapists and rooms. Priority: P2 | Points: 5 | Sprint: 10 | Status: Not Started

Implementation Status​

Current appointment model supports single guest only. No grouping mechanism for linked appointments, no couple-specific room assignment, no group discount logic.

Acceptance Criteria​

Scenario: Book couple massage
Given couple spa room "Serenity Suite" has capacity for 2 therapists simultaneously
And therapists "Lakshmi" and "Raju" are both available at 15:00 on March 9
When the receptionist books a "Couple Massage" for guests "Priya Sharma" and "Rajesh Sharma"
Then two linked appointments are created with the same groupId
And both appointments share time slot 15:00-16:00 in "Serenity Suite"
And therapist "Lakshmi" is assigned to Priya and "Raju" to Rajesh
And both appointments appear as a single block on the spa calendar labeled "Couple Massage"

Scenario: Cancel one appointment in a couple booking
Given a couple booking with appointments for Priya and Rajesh
When Priya cancels her appointment
Then Priya's appointment status changes to "CANCELLED"
And Rajesh's appointment remains "CONFIRMED" but is flagged "Partner Cancelled"
And the spa manager is notified to confirm if Rajesh's appointment should continue or be reassigned to a regular treatment room

US-016-008: Spa Revenue & Therapist Productivity Reports​

As a Spa Manager, I want to view reports on daily revenue, therapist productivity, and treatment popularity, So that I can optimize pricing, scheduling, and service offerings. Priority: P1 | Points: 8 | Sprint: 9 | Status: Not Started

Implementation Status​

Basic analytics exist in analytics-service but no spa-specific report builders. Spa data is available in PostgreSQL via Prisma queries but no pre-built aggregations for therapist utilization, treatment ranking, or RevPATH calculation.

Acceptance Criteria​

Scenario: Spa daily revenue report
Given 12 spa appointments were completed today with total revenue INR 42,000
When the spa manager opens Reports > Spa Revenue > Today
Then the report shows:
| Metric | Value |
| Total Revenue | INR 42,000 |
| Total Appointments | 12 |
| Average Revenue/Appt | INR 3,500 |
| Revenue by Category | Ayurveda: 45%, Massage: 35%, Facial: 20% |
| Revenue vs Yesterday | +15% |
And a bar chart breaks down revenue by treatment category

Scenario: Therapist productivity report
Given therapist "Lakshmi Nair" worked 8 hours today and completed 6 appointments
When the spa manager views the Therapist Productivity report
Then Lakshmi's row shows:
| Metric | Value |
| Available Hours | 8 |
| Booked Hours | 6 |
| Utilization Rate | 75% |
| Revenue Generated | INR 21,000 |
| RevPATH | INR 2,625 |
| No-Shows | 0 |
And therapists are ranked by utilization rate descending

As a Spa Receptionist, I want to collect a digital health form from guests before their first treatment, So that therapists are aware of allergies, medical conditions, and preferences, reducing liability risk. Priority: P2 | Points: 5 | Sprint: 11 | Status: Not Started

Implementation Status​

No health form or consent management in the spa module. Guest preferences exist in guest-service but not spa-specific health data (allergies, medical conditions, pregnancy, blood pressure concerns).

Acceptance Criteria​

Scenario: Guest fills digital health form before first appointment
Given guest "Priya Sharma" has her first spa appointment in 24 hours
When the system sends a pre-appointment notification with a health form link
Then the guest fills in:
| Field | Value |
| Allergies | Nut oils |
| Medical Conditions | None |
| Pregnancy | No |
| Blood Pressure | Normal |
| Preferred Pressure | Medium |
| Consent | I agree to terms |
And the form is stored against the guest profile
And the assigned therapist can view the health form before the session

Scenario: Therapist reviews health form before treatment
Given guest "Priya Sharma" has allergy "Nut oils" recorded in her health form
When therapist "Lakshmi" opens the appointment details
Then a prominent alert shows "Allergy: Nut oils - avoid almond/walnut-based products"
And suggested alternative oils are listed (coconut, sesame)
And Lakshmi acknowledges the alert before starting the treatment