About this software
About WashBay
WashBay runs car wash and detailing businesses from one system. Customers book slots and pay online through a Flutter mobile app (Android/iOS). Branch staff check in customers by QR code, track wash jobs through a live board, take before/after photos and close daily cash on a tablet. Managers control branches, pricing, staff and reports from an ASP.NET Core web panel with a guided product tour. The system handles multiple countries with separate currencies and VAT rates, and multiple branches per country with individual opening hours, holidays and bay configurations.
Why WashBay
What makes it better
than the alternatives
- 01
Live wash board over SignalR
Every bay updates in real time across web panel and staff tablets with job status, assigned washer and customer timeline
- 02
Dual Flutter apps from one codebase
Customer booking app (main.dart) and staff tablet app (main_staff.dart) share auth, network and domain logic
- 03
Branch-specific pricing
Services have a base price per vehicle type, with optional branch overrides and a cached menu (CatalogCache) invalidated on catalog changes
- 04
Guided demo mode
In-browser sample data (demo/store.js) and a chapter-based product tour (tour/provider.js) that plays without server calls, controlled by ProductionGuards.cs
- 05
Plain JavaScript web panel
No build step; ES modules (core/api.js, ui.js, resource.js) and Razor Pages render tables and forms with Tailwind CSS
Customer Mobile App (Flutter)
- Email/password registration with OTP verification (AuthRepository
- LoginCubit
- OtpCubit)
- My vehicles list with default selection (VehiclesScreen
- VehicleRepository)
- Branch list sorted by GPS distance with hours
- directions and call (BranchesScreen
- LocationHelper)
- Service selection with live price including VAT
- package and add-on support (SelectServicesScreen
- BookingFlowCubit)
- Real-time slot availability from SlotCalculator
- 5-minute hold during checkout (SelectSlotScreen
- BookingRepository)
- Stripe hosted checkout or pay-at-counter
- PDF invoice download (SummaryScreen
- PaymentService
- InvoicePdf)
- Live wash timeline: checked in → washing → quality check → ready → picked up (BookingDetailScreen
- LiveSession widget)
- Ratings and reviews after completion (RatingsController)
- In-app notifications list and optional Firebase push (NotificationsScreen
- PushService)
- English and Arabic with full RTL support (LocalizationCubit
assets/language/ar.json
Staff Tablet App (Flutter)
- One-time pairing with manager email/password
- then 4-digit PIN login (PairScreen
- PinScreen
- StaffAuthController)
- PIN lock after 5 wrong attempts for 15 minutes (Operations:PinMaxAttempts
- PinLockMinutes)
- Live board with lanes per bay
- drag jobs between statuses (BoardScreen
- BoardCubit
- LaneColumn widget)
- QR code scanner for customer check-in (ScanScreen
- JobCubit.checkIn)
- Job detail drawer: customer
- vehicle
- services
- assign washer
- before/after photo upload (JobScreen
- JobSections)
- Walk-in booking: select vehicle type and services
- see price and free slots
- capture customer details (WalkInScreen
- WalkInCubit)
- Daily cash closing: counter payments total and submit (CashController)
Web Admin Panel (Razor Pages + JS)
- Dashboard: today's bookings
- revenue and average rating
Pages/Panel/Dashboard.cshtml pages/dashboard.js- Live board: all branches
- real-time job updates over SignalR
Pages/Panel/Live.cshtml core/live.js- LiveHub)
- Countries: add countries with currency code and VAT rate
Pages/Panel/Countries.cshtml - OrgController.CreateCountry)
- Branches: name
- address
- time zone
- opening hours
- holidays
- bays with category limits
Pages/Panel/Branches.cshtml components/branch-form.js- Catalog: vehicle types
- categories
- services
- packages
- add-ons with translatable names
Pages/Panel/Catalog.cshtml - CatalogController)
- Price board: base price and duration per vehicle type
- branch overrides
components/price-board.js - CatalogController.UpdatePrices)
- Branch menu: turn services on/off per branch (CatalogController.UpdateBranchMenu
- CatalogCache invalidation)
- Bookings list: filter by branch and day
- cancel when needed
Pages/Panel/Bookings.cshtml - BookingsController)
- Staff management: create accounts
- set roles (Super Admin
- Country Admin
- Branch Manager
- Front Desk
- Supervisor
- Washer)
- set/clear PINs
- unpair tablets
Pages/Panel/Staff.cshtml - StaffAdminController
- StaffAppController)
- Ratings: reviews list with summary stats
Pages/Panel/Ratings.cshtml - RatingsController)
- Reports: daily branch report with bookings
- walk-ins
- no-shows
- cancellations
cash/card/onlinerevenue- average stars
- CSV export
Pages/Panel/Reports.cshtml - ReportsController)
- Guided product tour: 8 chapters
tour/chapters/ - in-browser demo data
demo/store.js - skippable and resumable
tour/provider.js - AuthController.UpdateTours)
- Session: signed httpOnly cookies with Data Protection
- auto-refresh
Panel/PanelSessionFilter.cs - PanelAuthController)
- English and Arabic UI
Panel/i18n/ar.json core/i18n.js
Booking Engine
- Quote calculation: services + package + add-ons
- VAT included (BookingsController.Quote
- QuoteService)
- Slot generation: SlotCalculator reads branch hours
- holidays
- bay availability and existing bookings to return free times
- 5-minute hold: BookingHold entity locks a slot while customer confirms (Booking:HoldMinutes)
- Booking creation: validates hold
- creates Booking with line items
- sends confirmation (BookingsController.Create)
- Reschedule: cancel cutoff enforced (Booking:CancelCutoffMinutes)
- new slot hold and swap (BookingsController.Reschedule)
- Cancellation: allowed until cutoff
- refund if paid online (BookingsController.Cancel)
- Max active bookings per customer (Booking:MaxActiveBookings)
- Walk-in bookings: staff create on-the-spot with immediate check-in (StaffAppController.CreateWalkIn)
Operations & Job Flow
- Check-in: QR code or typed code
- validates early check-in window (Operations:CheckInEarlyMinutes)
- creates Job entity (StaffAppController.CheckIn)
- Job statuses: Pending → InProgress → QualityCheck → Ready → PickedUp (JobStatus enum
- JobRules.CanTransition)
- Washer assignment: supervisor or front desk assigns staff
- tracked in Job.AssignedStaffId (StaffAppController.AssignWasher)
- Before/after photos: required by default (Operations:RequireBeforePhotos
- RequireAfterPhotos)
- uploaded to storage/uploads (FilesController
- JobPhotosService)
- No-show detection: manual mark or auto after 2 hours (Operations:NoShowAfterMinutes
- AutoNoShowAfterMinutes
- NoShowWorker background service)
- Live updates: SignalR LiveHub broadcasts job changes to web panel and tablets (LiveNotifier
- LiveHub.SubscribeToJobs)
Payments & Invoicing
- Payment providers: None
- Demo (try-out only with DemoPayToken signed links)
- Stripe (PaymentOptions.cs
- OnlinePaymentProviders)
- Stripe integration: hosted checkout session
- webhook signature verification (StripePaymentProvider
- StripeWebhookController)
- Demo payments: simulated success/failure with signed expiring tokens
- blocked in production (ProductionGuards.cs
- DemoPaymentProvider)
- Invoice generation: QuestPDF creates PDF with company details
- line items
- subtotal
- VAT
- total (InvoicePdf
- InvoiceService)
- Invoice storage: saved to storage/invoices
- downloadable by customer (PaymentsController.DownloadInvoice)
- Payment methods: Online (Stripe)
- Counter (cash/card at branch)
- tracked per booking (PaymentMethod enum)
Multi-Tenancy & Access Control
- Countries: separate currency and VAT rate
- Country entity (OrgController)
- Branches: belong to one country
- have time zone
- hours
- holidays
- bays (Branch entity)
- Role-based access: Super Admin (all countries)
- Country Admin (one country)
- Branch Manager (one branch)
- Front
Desk/Supervisor/Washer(branch staff) - Customer (Roles.cs
- AuthPolicies)
- Access scoping: TenantContext and AccessScope limit staff to their country or branch (ClaimsUser.CountryId
- BranchId)
- Policy enforcement: [Authorize(Policy = AuthPolicies.Panel)] for web panel
- [Authorize(Policy = AuthPolicies.Operations)] for staff tablet (AuthPolicies.cs)
- Branch filtering: operations pages (bookings
- cash
- reports
- ratings
- live) filter by branch
core/branch-picker.js
Notifications
- In-app notifications: stored in Notification entity
- paginated list (NotificationsController
- NotificationRepository)
- Push delivery: Log (development) or FCM (production) via Notifications:PushProvider (PushService
- FcmPushService)
- Notification types: BookingConfirmed
- BookingCancelled
- BookingReminder
- JobStatusChanged
- PaymentReceived (NotificationType enum)
- User preferences: opt-in push
- device token registration (NotificationsController.RegisterDevice)
- Retention: keeps last 100 per user (Notifications:KeepPerUser)
Catalog & Pricing
- Vehicle types: Car
- SUV
- Truck
- Van
- Motorcycle (VehicleType entity
- seeded in CatalogSeeder)
- Service categories: Exterior
- Interior
- Detailing
- Protection (ServiceCategory entity)
- Services: translatable name/description (Localized<string>)
- base price and duration per vehicle type (Service entity
- ServicePrice)
- Packages: bundles of services with discount (Package entity
- PackageService)
- Add-ons: optional extras (AddOn entity)
- Branch menu: services enabled/disabled per branch (BranchService entity
- CatalogController.UpdateBranchMenu)
- Price overrides: branch-specific prices (BranchServicePrice entity
- CatalogController.UpdatePrices)
- Catalog cache: in-memory branch menu
- invalidated on any catalog change (CatalogCache
- CatalogService.InvalidateCache)
Security & Production Guards
- JWT tokens: access (60 min) and refresh (30 days) with HS256 signing (TokenService
- Jwt:SigningKey)
- Password hashing: Argon2id with salt (PasswordService)
- OTP verification: 6-digit code
- 5 attempts
- 5-minute expiry
- 30-second resend cooldown (OtpService
- Otp:* settings)
- Production guards: refuses to start in Production with DemoSite=true
- OTP demo mode
- demo passwords or Demo payment provider (ProductionGuards.cs)
- Rate limiting: 20
req/min/IPfor auth routes - 10
req/15min/devicefor PIN login (RateLimitPolicies - Program.cs)
- CORS: configurable allowed origins (Cors:AllowedOrigins)
- Panel session: signed httpOnly cookies
- auto-refresh
- same-origin [RequirePanelHeader] (PanelSessionFilter
- PanelAuthController)
- Stripe webhook: HMAC signature verification before processing (StripeWebhookController)
- Authorization tests: EndpointAuthorizationTests.cs ensures every mutating route has a role or is reviewed as public
| Language | Version | Framework | Used for | Share of code |
|---|---|---|---|---|
| C# | — | — | Web, API, admin | 40.6% |
| Dart | — | — | Mobile app | 29.8% |
| JavaScript | — | — | Front-end | 17.7% |
| CSS | — | — | Styling | 5.9% |
| SQL | — | — | Database | 2.7% |
| HTML | — | — | Front-end | 1.7% |
| C# (Razor) | — | — | Web pages | 1.1% |
| Java | — | — | API | 0.3% |
| Swift | — | — | Mobile app | 0.1% |
| Shell | — | — | Scripts | 0.1% |
| Kotlin | — | — | Mobile app | 0% |
- Primary language
- C# 13 / .NET 10
- Framework
- ASP.NET Core 10 + Flutter 3.35
- Database
- Microsoft SQL Server 2019+
- Authentication
- JWT + refresh tokens, OTP email verification, 4-digit PIN for staff tablets
- Licence
- Single-site
- Screens
- 28
- Database tables
- 24
- Supported languages
- English, Arabic (full RTL)
- Browser support
- Modern browsers (Chrome, Firefox, Safari, Edge)
| Minimum | Recommended | |
|---|---|---|
| CPU | 2 vCPU | 4 vCPU |
| RAM | 4 GB RAM / 20 GB SSD | 8 GB RAM / 40 GB SSD |
| OS | Linux or Windows Server, .NET 10 runtime, SQL Server 2019+ | Linux or Windows Server, .NET 10 runtime, SQL Server 2019+ |
| Est. monthly hosting | $35 | $35 |
```bash cp .env.example .env # Edit .env: set MSSQL_SA_PASSWORD, JWT_SIGNING_KEY, ADMIN_PASSWORD docker compose up -d --build # Open http://localhost:8080 ```
```bash # Install .NET 10 SDK and SQL Server 2019+ git clone <repo> cd washbay-vibe96/NET\ Project cp appsettings.json appsettings.Production.json # Edit appsettings.Production.json: set ConnectionStrings:Default, Jwt:SigningKey dotnet user-secrets set "Seed:SuperAdminPassword" "<password>" dotnet ef database update dotnet publish -c Release -o /var/www/washbay sudo systemctl enable washbay sudo systemctl start washbay # Configure nginx reverse proxy to port 5080 ```
```bash az group create --name washbay-rg --location eastus az sql server create --name washbay-sql --resource-group washbay-rg --admin-user sqladmin --admin-password <password> az sql db create --resource-group washbay-rg --server washbay-sql --name WashBay --service-objective S1 az webapp create --resource-group washbay-rg --plan washbay-plan --name washbay-api --runtime "DOTNET:10" az webapp config appsettings set --resource-group washbay-rg --name washbay-api --settings ConnectionStrings__Default="<connection-string>" Jwt__SigningKey="<key>" Seed__SuperAdminPassword="<password>" cd "NET Project" dotnet publish -c Release az webapp deploy --resource-group washbay-rg --name washbay-api --src-path bin/Release/net10.0/publish.zip ```
```bash # Start SQL Server in Docker docker run -d --name washbay-sql -e ACCEPT_EULA=Y -e MSSQL_SA_PASSWORD='YourStrong!Pass123' -p 1433:1433 mcr.microsoft.com/mssql/server:2022-latest cd "NET Project/WashBay.Api" dotnet user-secrets set "ConnectionStrings:Default" "Server=localhost,1433;Database=WashBay;User Id=sa;Password=YourStrong!Pass123;TrustServerCertificate=True;MultipleActiveResultSets=True" dotnet user-secrets set "Jwt:SigningKey" "$(openssl rand -base64 48)" dotnet user-secrets set "Seed:SuperAdminPassword" "Admin123!" dotnet ef database update dotnet run # Open http://localhost:5080 ```
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 (4 minor)
No critical vulnerabilities found; some outdated dependencies in flutter apps; strong authentication and role checks; minor ownership gaps on read endpoints; no real credentials found; weak defaults in example files need stronger guidance; moderate duplication and some oversized files; module boundaries mostly sound. None of these stop the software from working; the developer has been told and improvements come in a future update.
Versions & updates
Release historyCurrent version
Updates in the last 90 days
Buyers
Updates included
-
1.1.0 Version Current22 Oct 2026 ✓ Reviewed & audited
- New features have been added to the admin panel: Email, Stripe, Database Backup, and Database Cleanup.
-
1.0.0 First release 19 Oct 2026 ✓ Reviewed & audited
How updates work: versions add features and go through the full AI audit and human review. Patches are small fixes, audited and checked by a reviewer before release. Buyers get every update free for 1 year and are emailed the how-to-apply steps.
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.