EsteticaPro — Appointment Management Prototype
API-first scheduling platform for beauty salons, built to prove out a SaaS idea end to end. Prototype, not yet deployed to a paying customer.
Role: Solo developer
Team
Solo
Timeline
Jun 2026
Type
Personal

Dashboard

Calendar view

Appointment booking

Clients

Notifications

Services
01 · Context & Problem
What problem this solves
Beauty salons scheduling by phone, paper and WhatsApp run into the same failures every time: double-booked stylists, no-show losses from forgotten reminders, and no single source of truth when more than one person manages the calendar. I built EsteticaPro to prove out that domain end to end, architected from day one as something that could be commercialized.
02 · Solution
What it actually does
A Django REST Framework API with JWT auth, a React/TypeScript frontend, and Celery + Redis for scheduled reminder delivery — including a working WhatsApp notification channel.
- Conflict-free appointment booking: the end time is computed from the service duration and an overlap query runs on every save, scoped to that stylist, enforced at the model layer.
- An available-slots endpoint that reuses the exact same overlap query as the booking validation, instead of a separate rules engine.
- Role-scoped dashboard and data access: admins and receptionists see everything, an esthetician's queryset is hard-filtered to their own appointments.
- A notification queue with explicit pending/sent/failed states, dispatched and retried by a Celery Beat worker every minute — not fire-and-forget messaging.
- WhatsApp notifications wired through a dedicated service class, isolating a self-hosted automation gateway (OpenWA) from the scheduling and Celery code.
03 · Architecture
Architecture & decisions
Django apps split by business domain (accounts, services, clients, appointments, notifications, dashboard), each mounted under a flat REST API prefix.
API-first, modular monolith split strictly by domain.
Leaves room for a future mobile client or third-party integration without redesigning the backend.
New-appointment side effects triggered by a direct function call rather than Django signals.
Pragmatic and easy to follow, at the cost of a direct dependency from the appointments app on the notifications app's internals — a trade-off I'd revisit before scaling this to more event types.
WhatsApp delivery isolated behind a single service class.
Keeps the HTTP calls to the automation gateway out of the Celery task and the manual-resend view, so swapping providers later touches one file.
04 · Stack
Full stack, by layer
Frontend
Backend
Database
Infrastructure & Deploy
Auth
External Services
05 · Challenges
Technical challenges solved
Getting an unofficial WhatsApp gateway working end to end
Problem: There was no approved WhatsApp Business API access for a personal project, but the reminder flow needed real WhatsApp delivery to be worth demonstrating.
Solution: Integrated OpenWA, a self-hosted gateway that automates a real WhatsApp Web session via QR login, behind a dedicated service class with Costa Rica phone-number normalization and a scripted local boot sequence that starts the gateway, opens a session over its REST API and polls until it's ready. It works, end to end, without an official Business API integration.
One overlap query serving two different jobs
Problem: Preventing double-bookings and suggesting available slots are normally built as two separate pieces of logic that can drift apart.
Solution: Both the model-level booking validation and the available-slots endpoint call the same overlap predicate, so there's exactly one definition of what counts as a conflict.
Making reminders durable instead of fire-and-forget
Problem: A reminder that silently fails to send is worse than no reminder system at all.
Solution: Notifications carry an explicit pending/sent/failed state, and a Celery Beat worker polls every minute to dispatch and retry, so a failure is visible and re-triggerable instead of lost.
06 · Results
Results
A functional prototype that proves out the core scheduling domain and a working (if unofficial) WhatsApp notification channel. Not deployed and not sold.
No hard metrics confirmed yet for this project — the impact above is qualitative only.
07 · Retrospective
What I'd do differently
Before this could go to a real paying salon, two things would need to change: moving off the unofficial WhatsApp gateway to the official Business API (the current one carries real terms-of-service risk for a commercial customer), and tightening access control on a couple of endpoints that ended up under permissive defaults while the role system was still being built out.
Have a system that needs building?
Tell me what you're running today and what's breaking. I'll tell you honestly whether I can help.