FizzBee/Salon Appointment Booking AppTry FizzBee →
Document4 of 4
Shared project · read-onlyTry it with yours →
Prompt

Build an appointment booking app for my salon where customers can book appointments with stylists based on their availability.

Individual seeking to book a salon service.

Service provider whose availability is managed in the system.

Select a stylist and time slot to schedule a service.

Actors: Customer

Set and update the times when they are available for bookings.

Actors: Stylist

Manages the salon operations, stylist accounts, and global configurations.

Add new stylists, update their details, or deactivate them.

Actors: Salon Owner / Admin

Define the standardized list of services, durations, and prices for the salon.

Actors: Salon Owner / Admin

Customer views their upcoming and past appointment history.

Actors: Customer

Stylist views their daily or weekly booked appointments.

Actors: Stylist

Customer cancels an upcoming appointment.

Actors: Customer

Stylist or admin cancels a customer's appointment (e.g., due to illness or emergency).

Actors: Stylist

  • Generating spec
  • Quick checks
  • Extensive verification

Reassign an existing appointment to a different stylist.

Actors: actor_owner

  • Generating spec
  • Quick checks
  • Extensive verification
Behavior Model v1Open ↗
Behavior scenarios
Shared setup
  • Walkthrough

    1. The owner adds a new stylist (Stylist#0) to the salon roster.
    2. The owner adds a service (svc0) to the global catalog.
    3. Stylist#0 adds an availability slot (slot0) to their schedule.
    4. All participants' views are updated to reflect the new stylist, service, and availability.

    Trace

    1. Owner#0.AddStylist
    2. Owner#0.AddService
    3. Stylist#0.AddAvailability
        slot=slot0
    4. Owner#0.Refresh
    5. Stylist#0.Refresh
    6. Customer#0.Refresh
    7. Customer#1.Refresh
    
  • Walkthrough (from Setup A)

    1. Customer#0 selects the service and the available slot to book an appointment.
    2. The system views update to show the slot is now occupied and the appointment is confirmed.

    Trace

    8. Customer#0.BookAppointment
        svc=svc0
        sched={stylist=Stylist#0, slot=slot0}
    9. Owner#0.Refresh
    10. Stylist#0.Refresh
    11. Customer#0.Refresh
    12. Customer#1.Refresh
    
Scenarios
  • Walkthrough (from Setup A)

    1. Customer#0 selects service svc0 and Stylist#0's available slot0 to book their appointment.
    2. The system records the appointment, linking it to the customer and the specific stylist and slot.

    Trace

    8. Customer#0.BookAppointment
        svc=svc0
        sched={stylist=Stylist#0, slot=slot0}
        expect: db.appointments contains record with id=appt0
        expect: db.appointments[appt0].customer == Customer#0
        expect: db.appointments[appt0].service == svc0
    

    Verifies: AppointmentInSchedule (always), AppointmentStylistActive (always), CanBookAppointment (exists), implements exp_availability_constraint

  • Walkthrough (from Setup B)

    1. Customer#1 attempts to book an appointment for the same stylist and slot (Stylist#0, slot0).
    2. The system blocks the booking because the slot is no longer available in the authoritative schedule.

    Trace

    13. Customer#1.BookAppointment
        svc=svc0
        sched={stylist=Stylist#0, slot=slot0}
        expect: action disabled by require (len([a for a in self.appointments if a.stylist == stylist_id and a.slot == slot]) == 0)
    

    Verifies: StylistNoOverlap (always), implements exp_no_double_booking

  • Walkthrough (from Setup B)

    1. The owner removes service svc0 from the global catalog.
    2. While the service is no longer in the catalog for new bookings, the existing appointment (appt0) still correctly references svc0.

    Trace

    13. Owner#0.RemoveService
        svc=svc0
        expect: svc0 not in db.catalog
    14. System#0.Refresh
        expect: db.appointments[appt0].service == svc0
    

    Verifies: implements exp_service_soft_delete

  • Walkthrough (from Setup B)

    1. Stylist#0 attempts to remove their availability for slot0.
    2. The system blocks the removal because an active appointment is already scheduled for that specific slot.

    Trace

    13. Stylist#0.RemoveAvailability
        slot=slot0
        expect: action disabled by require (len([a for a in self.appointments if a.stylist == stylist_id and a.slot == slot]) == 0)
    

    Verifies: AppointmentInSchedule (always), implements exp_avail_block_removal

  • Walkthrough (from Setup B)

    1. The owner removes Stylist#0 from the active roster.
    2. The system deactivates the stylist and clears the assignment from the existing appointment, moving it to an 'unassigned' state rather than cancelling it.

    Trace

    13. Owner#0.RemoveStylist
        s=Stylist#0
        expect: Stylist#0 not in db.active_stylists
        expect: db.appointments[appt0].stylist == None
        expect: db.appointments[appt0].slot == None
    

    Verifies: HasUnassignedAppointment (exists), implements exp_unassigned_state, implements exp_inactive_stylist

  • Walkthrough (from Setup B)

    1. The owner adds a second stylist (Stylist#1) and they provide availability for slot0.
    2. The owner removes Stylist#0, causing the existing appointment to become unassigned.
    3. The owner's view updates to show the unassigned appointment and the new stylist's availability.
    4. The owner reassigns the unassigned appointment to Stylist#1 at slot0.

    Trace

    13. Owner#0.AddStylist
    14. Stylist#1.AddAvailability
        slot=slot0
    15. Owner#0.RemoveStylist
        s=Stylist#0
    16. Owner#0.Refresh
    17. Owner#0.ReassignUnassigned
        appt={id=appt0, customer=Customer#0, stylist=None, slot=None, service=svc0}
        sched={stylist=Stylist#1, slot=slot0}
        expect: db.appointments[appt0].stylist == Stylist#1
        expect: db.appointments[appt0].slot == slot0
    

    Verifies: AppointmentInSchedule (always), AppointmentStylistActive (always), implements exp_reassign_strict

  • Walkthrough (from Setup B)

    1. The owner adds Stylist#1, who adds availability for slot0.
    2. Customer#1 books Stylist#1 for slot0, occupying that slot.
    3. The owner removes Stylist#0, making the original appointment (appt0) unassigned.
    4. The owner's view updates, but when they attempt to reassign the unassigned appt0 to Stylist#1 at slot0, the system blocks it because the slot is already booked.

    Trace

    13. Owner#0.AddStylist
    14. Stylist#1.AddAvailability
        slot=slot0
    15. Customer#1.Refresh
    16. Customer#1.BookAppointment
        svc=svc0
        sched={stylist=Stylist#1, slot=slot0}
    17. Owner#0.RemoveStylist
        s=Stylist#0
    18. Owner#0.Refresh
    19. Owner#0.ReassignUnassigned
        appt={id=appt0, customer=Customer#0, stylist=None, slot=None, service=svc0}
        sched={stylist=Stylist#1, slot=slot0}
        expect: action disabled by require (len([a for a in self.appointments if a.stylist == new_stylist_id and a.slot == new_slot]) == 0)
    

    Verifies: StylistNoOverlap (always), implements exp_reassign_strict

Approved without comment.

Documentation · ready

The requirements in this specification were confirmed in earlier rounds. This document packages those decisions so you can share them, hand them to coding agents, or keep them as a project record.

Ready to build the one you actually want?
Answer FizzBee's questions on your own idea. It takes a few minutes.
Try FizzBee →