Glowhub – Salon & Spa Booking SaaS | Vibe96

Business & Operations

Glowhub – Salon & Spa Booking SaaS

Source code included

Multi-tenant salon booking platform: each salon gets a branded website, dashboard, calendar, payments and reminders.

Built by nitesh das Updated 26 Oct 2026 62,055 lines of code

Open live demo Built withClaude Code

About this software

About Glowhub – Salon & Spa Booking SaaS

Glowhub is a Laravel 12 + Vue 3 SaaS that gives salons and spas their own online booking website (subdomain or custom domain) and a dashboard to manage appointments, staff, services, customers, payments and payroll. Every tenant shares one MySQL database (organization_id scoped). The public booking flow is a 4-step wizard (service → staff → date/time → details) with SSLCommerz payment integration and automated SMS/WhatsApp reminders via Twilio. The owner dashboard includes a month/week/day calendar, staff rosters with per-staff services and working hours, a service catalogue with categories, customer records auto-created on first booking, expense tracking, payroll runs with commission calculation, and revenue reports. The platform supports multiple branches per salon (free plan: 1 branch, 10 staff), role-based access (owner/manager/staff), email verification, password reset, and a cross-tenant salon search for customers who don't know a salon's URL.

Category: Business & OperationsStack: Laravel 12 + Vue 3 · MySQL 8.0 or SQLiteBuilt with: Claude Code Licence: Single-site, full source

Why Glowhub – Salon & Spa Booking SaaS

What makes it better
than the alternatives

  1. 01

    Multi-tenant architecture

  2. 02

    Pluggable payment gateway

  3. 03

    Automated reminders

  4. 04

    Staff payroll with commission

  5. 05

    Subdomain + custom domain support

Authentication & Multi-Tenancy

  • Register (AuthController::register
  • RegisterOrganization action) creates User
  • Organization
  • Domain
  • Branch
  • Setting and PaymentSetting in one transaction
  • Login with email/password (AuthController::login)
  • rate-limited per (email
  • IP) with 5 attempts per 60s
  • returns Sanctum token + user + organization
  • Password reset (PasswordResetController
  • Password::broker()->sendResetLink
  • ResetPassword notification with FRONTEND_URL link)
  • Email verification (EmailVerificationController
  • User implements MustVerifyEmail
  • VerifyEmail notification)
  • Tenant resolution (ResolveTenant middleware reads organization_id from user->organization
  • ResolvePublicTenant reads slug from Host header or /salon/:slug path)
  • Role-based access (UserRole enum: owner/manager/staff
  • policies in app/Policies/
  • canManageOperations computed in auth store)
  • Organization status guard (OrganizationStatus enum: active/suspended/inactive
  • AuthController::login refuses non-active
  • tenant middleware 403s suspended)

Public Booking Site

  • Salon shopfront (SalonSiteView.vue
  • PublicSiteController::show returns organization + branches + services + staff + gallery + reviews)
  • 4-step booking wizard (PublicBookingView.vue: service selection → staff selection → date/time picker → customer details
  • PublicBookingController::store)
  • Slot generation (SlotGenerator service
  • respects staff working hours from staff_profiles.working_hours JSON
  • branch closures from branch_closures table
  • staff time-off from staff_time_offs table)
  • Abandoned booking release (ReleaseAbandonedBookings command scheduled every 15 minutes
  • AbandonedBookingReleaser service
  • releases held slots after BOOKING_HOLD_MINUTES)
  • Payment integration (SslcommerzGateway service
  • PaymentCallbackController::success/fail/cancel
  • stores Payment with status pending/completed/failed
  • Deposit handling (DepositType enum: none/fixed/percentage
  • PublicBookingRequest validates deposit_amount when required
  • held until payment completes)
  • Review submission (PublicReviewController::store
  • creates Review with rating 1-5 + comment
  • requires valid appointment public_token)
  • Cross-tenant salon search (DiscoveryController::index
  • searches organizations.name + branches.city + services.name
  • returns paginated results)

Appointments & Calendar

  • Appointment CRUD (AppointmentController
  • AppointmentPolicy
  • fields: customer_id
  • branch_id
  • start_time
  • end_time
  • status enum pending/confirmed/completed/cancelled/no_show
  • notes
  • public_token UUID)
  • Multi-service appointments (AppointmentService pivot
  • AppointmentServiceWriter action
  • stores service_id + staff_id + price + duration per line)
  • Month/week/day calendar (CalendarView.vue
  • AppointmentController::index with ?start_date=&end_date=
  • returns appointments + staff + services)
  • Drag-to-reschedule (calendar emits @update:appointment
  • calls AppointmentController::update with new start_time
  • recalculates end_time from total duration)
  • Status transitions (AppointmentStatus enum
  • completed appointments feed into payroll and reports
  • cancelled/no_show release the slot)
  • Booking notifications (BookingNotifier service
  • queues BookingConfirmationMail + NewBookingMail on create
  • BookingCancelledMail on cancel
  • BookingRescheduledMail on reschedule)
  • Invoice generation (AppointmentController::invoice
  • returns appointment + services + payment + customer
  • rendered in InvoiceView.vue)

Staff Management

  • Staff CRUD (StaffController
  • UserPolicy
  • creates User with role=staff + StaffProfile
  • fields: position
  • bio
  • profile_image
  • working_days JSON array
  • working_hours JSON {day: {start
  • end}})
  • Per-staff services (staff_profiles.service_ids JSON array
  • StaffProfile::services() belongsToMany
  • filtered in slot generation and booking flow)
  • Staff time-off (StaffTimeOffController
  • StaffTimeOffPolicy
  • fields: staff_id
  • start_date
  • end_date
  • reason
  • blocks slots in SlotGenerator)
  • Pay rules (staff_profiles.pay_type enum hourly/salary/commission
  • base_pay decimal
  • commission_rate decimal
  • PayrollCalculator reads these)
  • Staff-only dashboard access (isStaff computed in auth store
  • router guards /staff routes
  • StaffController::myAppointments returns own schedule)

Services & Categories

  • Service CRUD (ServiceController
  • ServicePolicy
  • fields: name
  • category_id
  • duration minutes
  • price
  • description
  • status enum active/inactive)
  • Service categories (ServiceCategoryController
  • fields: name
  • description
  • display_order
  • categories.services hasMany)
  • Bulk service creation (ServiceController::bulkStore
  • BulkStoreServiceRequest
  • creates multiple services in one request
  • used in onboarding)
  • Service presets config/service_presets.php
  • arrays of {name
  • duration
  • price} per category
  • ServiceController::presets returns them for quick setup)
  • Service status toggle (ServiceStatus enum
  • inactive services hidden from public booking but kept in historical appointments)

Customers

  • Customer CRUD (CustomerController
  • CustomerPolicy
  • fields: name
  • email
  • phone
  • notes
  • customer_account_id nullable FK)
  • Auto-creation on booking (PublicBookingController creates Customer if email not found
  • links to CustomerAccount if one exists with that verified email)
  • Customer accounts (CustomerAccount model
  • passwordless auth via CustomerLoginCode 6-digit OTP
  • CustomerAuthController::requestCode/verifyCode)
  • Account linking (CustomerAuthController::verifyCode updates all Customer rows with that email to set customer_account_id
  • backfills name from any row)
  • Customer portal (CustomerBookingController
  • customer guard
  • lists own appointments across all salons
  • cancel/reschedule if allowed)

Payments

  • Payment records (Payment model
  • fields: appointment_id
  • amount
  • method enum card/cash/other
  • status enum pending/completed/failed/refunded
  • source enum online/in_person
  • gateway_transaction_id
  • tip_amount)
  • SSLCommerz integration (SslcommerzGateway service
  • PaymentSetting.credentials encrypted:array {store_id
  • store_password
  • sandbox}
  • PaymentCallbackController handles success/fail/cancel
  • Deposit collection (PublicBookingRequest validates deposit when organization.deposit_type is fixed/percentage
  • held until appointment confirmed)
  • Tip handling (PaymentController::addTip
  • updates payment.tip_amount
  • included in staff payroll commission calculation)
  • Payment verification (PaymentController::verify
  • calls gateway API to confirm transaction
  • updates status to completed/failed)

Finance & Payroll

  • Expense tracking (ExpenseController
  • Expense model
  • fields: category enum supplies/rent/utilities/marketing/salary/other
  • amount
  • date
  • description
  • receipt_path)
  • Payroll runs (PayrollRunController
  • PayrollRun model
  • fields: period_start
  • period_end
  • status enum draft/finalized
  • total_amount)
  • Payroll calculation (PayrollCalculator service
  • reads staff pay_type + base_pay + commission_rate
  • sums completed appointments per staff
  • creates PayrollLine per staff)
  • Commission on services (PayrollCalculator::calculateCommission
  • reads appointment_services.price * staff commission_rate
  • adds to base pay)
  • Payroll finalization (PayrollRunController::finalize
  • locks the run
  • creates Expense rows for each line
  • updates status to finalized)
  • Revenue reports (ReportService
  • ReportController::index
  • aggregates payments by date/staff/service
  • filters by branch/date range)

Reminders & Notifications

  • Reminder settings (ReminderSetting model
  • fields: enabled boolean
  • hours_before integer
  • channels JSON array [sms
  • whatsapp
  • email]
  • credentials encrypted:array)
  • Twilio integration (TwilioReminderChannel
  • reads TWILIO_ACCOUNT_SID + AUTH_TOKEN + FROM + WHATSAPP_FROM from env or salon credentials
  • sends via Twilio API)
  • Reminder scheduling (SendAppointmentReminders command scheduled hourly
  • AppointmentReminderService finds appointments due in X hours
  • queues SendAppointmentReminder job per appointment)
  • Pluggable channels (ReminderChannelManager
  • resolves channel from config
  • LogReminderChannel for local dev
  • TwilioReminderChannel for production)
  • Email reminders (BookingConfirmationMail implements ShouldQueue
  • includes appointment details + salon address + cancel link)

Settings & Configuration

  • Organization settings (OrganizationController::update
  • UpdateOrganizationRequest
  • fields: name
  • email
  • phone
  • address
  • timezone
  • currency
  • theme_color
  • logo_path)
  • Branch management (BranchController
  • Branch model
  • fields: name
  • address
  • phone
  • google_map_link
  • opening_hours JSON {day: {open
  • close}}
  • free plan limited to 1 branch)
  • Branch closures (BranchClosureController
  • BranchClosure model
  • fields: branch_id
  • start_date
  • end_date
  • reason
  • blocks all slots in SlotGenerator)
  • Payment settings (PaymentSettingController::update
  • UpdatePaymentSettingRequest
  • stores gateway credentials in encrypted:array
  • validates required fields per gateway)
  • Reminder settings (ReminderSettingController::update
  • UpdateReminderSettingRequest
  • stores Twilio credentials in encrypted:array
  • validates phone format)
  • Gallery management (GalleryController
  • Gallery model
  • fields: title
  • description
  • image_path
  • display_order
  • shown on public salon site)
  • Domain management (domains table
  • fields: organization_id
  • domain
  • is_primary boolean
  • nginx-salon.conf serves custom domains
  • ResolvePublicTenant resolves by Host header)

Quality report

Manually reviewed

86/ 100

Automated audit score

✓ Approved by our review team

Listed after manual review.
Audit run: 20 Oct 2026
Reviewed by Vibe96 staff, Dubai.

Security85
Code structure78
Docs & completeness87
Dependency health85
Build & deploy92
Reviewer notes (4 minor)

Weak default credentials in example files; no real secrets found; no critical vulnerabilities; some outdated packages and missing frontend lockfile; multiple unscoped deletes, missing indexes on foreign keys, and raw sql in reports; build reproducible with gaps: missing node version in setup doc, unclear frontend env handling; moderate code duplication and some oversized files; structure generally sound. None of these stop the software from working; the developer has been told and improvements come in a future update.

Versions & updates

1.0.0
First release26 Oct 2026✓ Reviewed & audited

No updates yet. New versions appear here with a changelog.
Buyers receive updates free for 1 year.

Quality report

What you get

  • </>Full source codeThe complete audited source, delivered as a download from your account. No obfuscation.
  • ▤DocumentationSetup guide, architecture notes, CLAUDE.md and AGENTS.md.
  • ↻One year of updatesEvery new version the builder publishes, free for 12 months.
  • ♧30 days of supportInstallation and defect support through Vibe96 tickets.
$99Single-site licence Details