Files
Salon/docs/architecture.md
mohd 229975c612 docs: revise ADR 0001, risks, and architecture for accuracy
- ADR 0001: distinguish payment/OTP (sync by design) from notifications
  (fire-and-forget); correct misleading claim that notification failures
  surface to clients — they are silently absorbed as FAILED status
- risks.md: upgrade USERNAME_FIELD entry with concrete breakage (admin,
  create_superuser, JWT lookup); add booking overlap race condition with
  root cause and fix (select_for_update)
- architecture.md: document notification/OTP provider coupling as an MVP
  shortcut and note the Phase 2 fix (dedicated NotificationProvider)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 23:30:04 +03:00

3.6 KiB

Architecture

Overview

The Salon platform is a Django REST API backend with a React/Vite frontend, optimized for KSA (phone auth, Riyadh timezone, Arabic locale).

Backend Apps and Responsibilities

App Responsibility
accounts User model, phone/OTP auth, JWT tokens, locale preferences. OTP providers (console, Twilio, Unifonic) send SMS/WhatsApp.
salons Salon catalog, services, staff, availability windows, reviews. Read-only public APIs.
bookings Booking model, validation (availability, overlap prevention), status transitions. Triggers notifications on create and status change.
payments Payment model, Moyasar integration (create, capture, refund), webhook reconciliation, idempotency.
notifications Booking lifecycle notifications (SMS/WhatsApp). Reuses OTP provider classes as an MVP shortcut; sends on booking created/confirmed/cancelled. See note below.

Data Model Overview

The core data model centers on users, salons, and time-bound bookings. A booking ties a customer to a service, a staff member, and a scheduled time. Payments are recorded per booking and reconcile to the external gateway. Notifications are stored for every booking lifecycle message for auditability.

  • accounts.User owns phone, locale, and auth preferences.
  • salons.Salon, salons.Service, and salons.Staff define the catalog and scheduling surface.
  • bookings.Booking links customer, staff, service, and scheduled time, with status transitions.
  • payments.Payment tracks gateway state and idempotency per booking.
  • notifications.Notification records each SMS/WhatsApp send attempt tied to a booking event.

Data Flow

User → React Frontend → Django API
         ↓
    accounts (auth) ──→ OTP providers (Twilio/Unifonic/console)
    salons (catalog)
    bookings ──→ notifications ──→ OTP providers
    payments ──→ Moyasar gateway

Notification / OTP Provider Coupling (MVP Shortcut)

notifications/services.py imports PROVIDERS from apps.accounts.services.otp and uses OTP provider instances (e.g. AuthenticaOtpProvider) to send booking SMSes. This works today because Authentica handles both authentication OTPs and general SMS delivery.

Consequences of this coupling:

  • Notifications and OTP delivery cannot independently use different providers (e.g. Twilio for OTP, Unifonic for notifications).
  • The notifications app is conceptually coupled to the accounts app's auth infrastructure.

This is an acceptable MVP shortcut. Before Phase 2, introduce a dedicated NotificationProvider abstraction in notifications/ (mirroring OtpProvider) so the two systems can be configured and tested independently.

Async and Observability (MVP Decision)

Decision (MVP): All OTP sends, booking notifications, and payment gateway calls run synchronously in the request/response path. No Celery, RQ, or other task queue for the initial launch. This is captured in ADR 0001 (docs/adr/0001-synchronous-external-calls-mvp.md).

Rationale:

  • Reduces deployment complexity (no Redis, no worker processes).
  • MVP traffic is expected to be low; synchronous latency is acceptable.
  • External calls already use timeouts (e.g. Moyasar: 10s, Twilio: SDK default).

Future: When scaling, introduce a task queue (e.g. Celery + Redis) for OTP and notification sends. Payment creation and webhooks should remain synchronous for immediate feedback and idempotency.

Observability: Errors are logged via Python logging and stored in model metadata (e.g. Payment.metadata["gateway_error"], Notification.error_message). Structured logging and metrics are Phase 3 work.