About this software
About Bookmysalon
BookMySalon is a complete salon and spa management platform built for the United Arab Emirates. It handles online bookings with customer self-service, a team calendar with drag-and-drop scheduling, point-of-sale checkout with split payments and VAT, client records with segments and forms, staff rosters and payroll, inventory tracking with transfers, loyalty points and referrals, SMS and email campaigns, and Stripe payments in AED. The system is multi-tenant: one installation serves many salons, each with its own data, team, roles and public booking page. Built with ASP.NET Core 10 Blazor, Clean Architecture, Dapper with hand-written SQL, SQL Server 2019+, and Hangfire background jobs.
Why Bookmysalon
What makes it better
than the alternatives
- 01
Multi-tenant architecture
- 02
UAE-specific configuration
- 03
No ORM, hand-written SQL
- 04
Clean Architecture with full test coverage
- 05
Blazor Interactive Server for admin
Static SSR for auth
Online Booking & Customer Portal
- Public booking page per salon at /
book/{slug}: service menu - professional selection
- date strip with available slots
- customer sign-in by email or UAE mobile code
- Customer authentication: 6-digit codes by email or SMS
- Google and Apple sign-in with account linking
- 60-day sliding cookie
- My Bookings page: view upcoming and past appointments
- reschedule (checks availability in transaction)
- cancel with reason
- pay deposit online
- Customer wallet: view credit balance
- top-up online
- transaction history
- Booking settings per salon: advance booking window
- cancellation deadline
- deposit percentage
- blocked days
- service visibility
- professional assignment rules
Calendar & Appointments
- Team calendar with day
- 3-day
- week and month views; one column per team member; drag-and-drop rescheduling with conflict detection
- Appointment statuses: Booked
- Confirmed
- In Progress
- Completed
- No Show
- Cancelled; change history with timestamp and user
- No double booking: every save re-checks the slot inside a database transaction (AppointmentRepository.IsSlotAvailableAsync with UPDLOCK)
- Blocked time: mark unavailable periods per professional (lunch
- training
- personal time)
- Appointment details: client
- services
- professional
- duration
- notes
- internal notes (staff only)
- deposit paid
- total price
- Automatic reminders: scheduled by MessageScheduler
- sent 24 hours before via SMS or email
Point of Sale & Checkout
- Checkout cart: add services (from appointment or walk-in)
- products
- custom items; apply discounts (percentage or fixed amount)
- promo codes
- tips
- Split payments: cash
- card
- online (Stripe)
- gift card
- package session
- membership
- wallet credit; one sale can use multiple tenders
- VAT calculation: configurable rate (default 5% UAE)
- applied to services and products
- shown on receipt
- Invoice numbering: gap-free sequence per business (SaleRepository.NextInvoiceNumberAsync with UPDLOCK)
- Receipt generation: 80mm thermal or A4 PDF (ReceiptPdfRenderer with QuestPDF)
- email to client
- print from browser
- Cash register: opening float
- cash in/out with reason
- closing count with variance report (RegisterService)
- Refunds and voids: full or partial refunds with reason
- void unpaid sales
- refund history per sale
Client Management
- Client profiles: name
- mobile
- birthday
- gender
- tags
- source
- notes
- visit count
- total spend
- last visit date
- Client segments: new (first visit <30 days)
- loyal (5+ visits)
- lapsed (no visit >90 days)
- birthdays this month
- custom filters by
tags/source/spend - Client wallet: credit balance
- top-up at checkout or online
- transaction log with sale references
- Consultation forms: custom forms per business (FormService)
- sent by link
- client fills online
- stored with client record
- Consent forms: GDPR-style consent tracking
- signed date
- form version
- CSV import: bulk import clients with mapping (ClientService.ImportFromCsvAsync)
- Contact masking: staff without 'view_client_contacts' permission see masked email/phone (ClientService applies mask based on CurrentUser permissions)
Prepaid, Loyalty & Marketing
- Gift cards: define types with value and validity period
- sell at POS or online (e-gift with email delivery)
- redeem at checkout
- balance tracking
- Packages: bundles of sessions (e.g. 10 massages)
- sold at POS
- sessions deducted at checkout
- expiry date
- remaining sessions shown in cart
- Memberships: recurring access (monthly/annual)
- sold at POS
- benefits applied at checkout (discounts
- free services)
- renewal reminders
- Loyalty points: earn points on spend (configurable rate)
- redeem for discounts
- referral bonus points
- points ledger per client (LoyaltyPosting)
- Promo codes: percentage or fixed discount
- usage limit
- expiry date
- applied at checkout (CheckoutDiscounts validates and applies)
- Blast campaigns: email or SMS to segments
- scheduled send
- unsubscribe link
- delivery tracking (CampaignService
- OutboxProcessor)
- Review requests: automatic after appointment completion
- public review page at /
review/{token} - star rating and comment (ReviewService)
Team, Roster & Payroll
- Team members: linked to user accounts
- assigned to services
- working hours
- commission rate
- hourly rate
- active/inactive status
- Roles and permissions: 8 system roles (Owner
- Admin
- Manager
- Receptionist
- Stylist
- Therapist
- Technician
- Trainee) plus custom roles; 47 granular permissions across 12 areas
- Shift scheduling: weekly roster
- assign shifts per professional
- copy previous week
- conflict detection (ShiftService)
- Timesheets: clock in/out (manual entry by manager)
- break deduction
- overtime calculation
- approval workflow (TimesheetService)
- Payroll: pay runs per period
- base salary + commission on sales + hourly for extra hours
- deductions
- net pay
- PDF payslip (PayrollService)
- Commission tracking: percentage of service price or fixed amount per service
- calculated at sale completion
- included in pay run
Inventory & Products
- Product catalog: name
- SKU
- category
- brand
- cost price
- retail price
- stock level
- reorder point
- supplier
- Stock tracking: current quantity per branch
- stock movements (purchase
- sale
- adjustment
- transfer)
- movement history
- Transfers: move stock between branches
- pending/completed status
- transfer log (TransferService
- TransferRepository)
- Low stock alerts: products below reorder point shown on dashboard
- email notification (InventoryService.GetLowStockAsync)
- Stock adjustments: manual corrections with reason (damaged
- expired
- found)
- adjustment history
- Product sales: add to checkout cart
- deduct from stock on sale completion
- cost of goods sold tracked
Payments & Billing
- Stripe integration: AED payments
- payment intents for deposits and gift cards
- webhook handling for payment confirmation (StripeGateway
- OnlinePaymentRecorder)
- Payment links: generate link for unpaid sale
- send by SMS/email
- customer pays online
- sale marked paid on webhook (PaymentLinkService)
- Deposit handling: online deposit for bookings
- held in customer wallet
- applied at checkout
- auto-refund if cancelled >24h before (OnlineBookingService.DepositReturns)
- Multi-currency support: AED only in UAE edition (Region.Currency)
- but architecture supports other currencies (Money value object)
- Billing module: subscription plans (trial
- basic
- pro)
- usage tracking
- invoice generation
- payment collection (BillingService
- Phase 16 in PHASE-NOTES.md)
Reports & Analytics
- Dashboard: today's appointments
- sales summary
- top services
- top professionals
- low stock alerts
- upcoming birthdays (DashboardService)
- Daily sales summary: total sales
- payment method breakdown
- VAT collected
- tips
- refunds
- register variance (SalesReportService.GetDailySummaryAsync)
- Sales list: filterable by date range
- professional
- payment method
- status; export to Excel/CSV (SalesReportService.GetSalesAsync
- SpreadsheetWriter)
- Appointment reports: by status
- professional
- service
- date range; no-show rate
- cancellation reasons
- Client reports: new clients
- repeat rate
- average spend
- visit frequency
- segment sizes
- Staff reports: sales per professional
- commission earned
- hours worked
- appointments completed
- Inventory reports: stock value
- movement history
- low stock
- products sold
Multi-Location & Settings
- Multi-branch support: one business can have multiple branches
- each with own address
- phone
- working hours
- staff assignment
- inventory (Phase 15 in PHASE-NOTES.md)
- Business settings: name
- slug (for booking URL)
- logo
- address
- phone
- timezone (Asia/Dubai)
- currency (AED)
- VAT rate
- booking rules (SettingsService)
- Service catalog: define services with name
- duration
- price
- category
- assigned professionals
- online visibility (CatalogService)
- Working hours: set per branch and per professional
- used for availability calculation (Availability.GetSlotsAsync)
- Email templates: customizable for login codes
- appointment confirmations
- reminders
- receipts (EmailLayout.WrapAsync)
- SMS gateway: HTTP API integration for any UAE SMS provider (SmsSenders.HttpGateway)
- configurable
URL/query/authin appsettings.json - Data protection: ASP.NET Core Data Protection keys stored in configurable folder (appsettings.json DataProtection:KeysPath)
- survives restarts
| Language | Version | Framework | Used for | Share of code |
|---|---|---|---|---|
| C# | — | — | Web, API, admin | 64.9% |
| C# (Razor) | — | — | Web pages | 23.4% |
| SQL | — | — | Database | 7.4% |
| CSS | — | — | Styling | 2.4% |
| HTML | — | — | Front-end | 1.4% |
| JavaScript | — | — | Front-end | 0.5% |
- Primary language
- C# 13 / .NET 10
- Framework
- ASP.NET Core 10 Blazor Web App (Interactive Server)
- Database
- SQL Server 2019+
- Authentication
- Cookie authentication with email/SMS OTP codes, Google OAuth, Apple Sign In
- Licence
- Single-site
- Screens
- 78
- Database tables
- 89
- Supported languages
- English only
- Browser support
- Modern browsers (Chrome, Firefox, Safari, Edge — ES6+)
| Minimum | Recommended | |
|---|---|---|
| CPU | 2 vCPU | 4 vCPU |
| RAM | 4 GB RAM / 20 GB storage | 8 GB RAM / 50 GB storage |
| OS | Linux (Ubuntu 22.04+) or Windows Server 2019+, .NET 10 runtime, SQL Server 2019+ | Linux (Ubuntu 22.04+) or Windows Server 2019+, .NET 10 runtime, SQL Server 2019+ |
| Est. monthly hosting | $40 | $40 |
```bash cp .env.example .env # Edit .env: set MSSQL_SA_PASSWORD (16+ chars, mixed case/digits/symbols) # and CODE_HASH_KEY (openssl rand -base64 32) docker compose up -d --build # Open http://localhost:8080 # Login codes appear in: docker compose logs -f web ```
```bash # Install .NET 10 SDK wget https://dot.net/v1/dotnet-install.sh chmod +x dotnet-install.sh ./dotnet-install.sh --channel 10.0 # Install SQL Server 2019+ or use a managed instance # Set connection string in environment or appsettings.Production.json cd "NET Project" dotnet publish src/BookMySalon.Web/BookMySalon.Web.csproj -c Release -o /var/www/bookmysalon # Set secrets as environment variables: export Security__CodeHashKey="$(openssl rand -base64 32)" export Database__ConnectionString="Server=localhost;Database=BookMySalon;User Id=app;Password=***;TrustServerCertificate=True" export App__BaseUrl="https://yourdomain.com" # Run with systemd service or: cd /var/www/bookmysalon dotnet BookMySalon.Web.dll # Configure Nginx reverse proxy on port 443 ```
```bash az login az group create --name bookmysalon-rg --location uaenorth az sql server create --name bookmysalon-sql --resource-group bookmysalon-rg --location uaenorth --admin-user sqladmin --admin-password "<strong-password>" az sql db create --resource-group bookmysalon-rg --server bookmysalon-sql --name BookMySalon --service-objective S1 az webapp create --resource-group bookmysalon-rg --plan bookmysalon-plan --name bookmysalon-app --runtime "DOTNET:10" # Set app settings: az webapp config appsettings set --resource-group bookmysalon-rg --name bookmysalon-app --settings \ Database__ConnectionString="Server=tcp:bookmysalon-sql.database.windows.net,1433;Database=BookMySalon;User ID=sqladmin;Password=<password>;Encrypt=True" \ Security__CodeHashKey="$(openssl rand -base64 32)" \ App__BaseUrl="https://bookmysalon-app.azurewebsites.net" cd "NET Project" dotnet publish src/BookMySalon.Web/BookMySalon.Web.csproj -c Release -o ./publish cd publish zip -r ../app.zip . az webapp deployment source config-zip --resource-group bookmysalon-rg --name bookmysalon-app --src ../app.zip ```
```bash # Start SQL Server in Docker: docker run -d --name bookmysalon-sql \ -e ACCEPT_EULA=Y \ -e MSSQL_SA_PASSWORD="YourStrong!Passw0rd" \ -p 1433:1433 \ mcr.microsoft.com/mssql/server:2022-CU27-ubuntu-22.04 cd "NET Project" # Set user secrets (never commit these): dotnet user-secrets init --project src/BookMySalon.Web dotnet user-secrets set "Security:CodeHashKey" "$(openssl rand -base64 32)" --project src/BookMySalon.Web dotnet user-secrets set "Database:ConnectionString" "Server=localhost,1433;Database=BookMySalon;User Id=sa;Password=YourStrong!Passw0rd;TrustServerCertificate=True" --project src/BookMySalon.Web # Run: dotnet run --project src/BookMySalon.Web --launch-profile https # Open https://localhost:7180 # Login codes appear in the terminal ```
Quality report
Manually reviewedHow to read the quality report
What this is. Every project on Vibe96 goes through an automated audit of its source code before a reviewer in Dubai checks it by hand. The score is out of 100; 75 is the minimum to be listed, and any single failing check blocks a listing regardless of the score.
- Security
- No real credentials in the code, every data-changing route protected, admin areas role-gated, no SQL built from user input.
- Code structure
- A developer can navigate and extend it: clear module boundaries, no giant files, little copy-paste.
- Docs & completeness
- The setup guide, example config, schema and required files the builder committed to are actually in the archive.
- Dependency health
- Packages pinned, no known critical vulnerabilities, no abandoned libraries in production paths.
- Build & deploy
- A clean machine can restore, build and start it by following the shipped instructions.
Warnings are problems that didn't block the listing; they stay visible here until a later version clears them. The audit reads the code — it does not run it — so always try the live demo before you buy. Lines of code are counted from the same audited archive.
Reviewer notes (2 minor)
No real secrets found; weak default sql password in docker-compose.yml needs attention; dapper sql is parameterized and scoped; minor schema gaps (missing indexes on fks); strong authentication and role checks; minor ownership gaps on read endpoints; moderate duplication and some oversized files; architecture is sound but refactoring needed. None of these stop the software from working; the developer has been told and improvements come in a future update.
Versions & updates
No updates yet. New versions appear here with a changelog.
Buyers receive updates free for 1 year.
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.