Files
Salon/docs/execplans/booking-notifications.md
T

8.8 KiB
Raw Blame History

Booking Lifecycle Notifications (SMS/WhatsApp)

This ExecPlan is a living document. The sections Progress, Surprises & Discoveries, Decision Log, and Outcomes & Retrospective must be kept up to date as work proceeds.

The requirements for ExecPlans live in PLANS.md at the repository root. This document must be maintained in accordance with that file.

Purpose / Big Picture

After this change, a booking will automatically notify the customer and the assigned staff member when it is created, confirmed, or cancelled. You can see it working by creating a booking and observing two notification records (customer + staff), then changing the booking status to confirmed or cancelled and seeing two more notification records for that event. In the console provider, the messages are logged, giving an immediate, user-visible trace of the booking lifecycle.

Progress

  • (2026-02-28 17:05Z) Created ExecPlan for booking lifecycle notifications and reviewed bookings + notifications gaps.
  • (2026-02-28 17:30Z) Implemented notifications app with audit-friendly model, providers, and booking message templates.
  • (2026-02-28 17:40Z) Connected booking create/update flows to notification dispatch with idempotent event handling.
  • (2026-02-28 17:55Z) Allowed booking status updates with role checks to enable confirmation/cancellation.
  • (2026-02-28 18:05Z) Added tests for booking notifications (create, status change, no duplicate sends).
  • (2026-02-28 18:10Z) Updated docs/risks.md and validated tests (python3 -m pytest).

Surprises & Discoveries

  • Observation: Booking status updates were blocked because status was read-only on the default booking serializer. Evidence: PATCH /api/bookings/<id> returned HTTP 400 when attempting to confirm.

Decision Log

  • Decision: Store every booking notification in a dedicated Notification model for auditability, even when skipped. Rationale: Lifecycle messages are user-facing and must be traceable for support and compliance. Date/Author: 2026-02-28, Codex
  • Decision: Reuse existing OTP provider adapters for SMS/WhatsApp delivery, with a new NOTIFICATION_PROVIDER setting. Rationale: Avoid duplicate integration code while still allowing independent provider configuration. Date/Author: 2026-02-28, Codex
  • Decision: Default to SMS for booking notifications and use the recipients preferred language when formatting messages. Rationale: SMS is the most reliable baseline in KSA, and language preference is already captured on the user. Date/Author: 2026-02-28, Codex
  • Decision: Allow booking status changes via BookingSerializer with role-based validation. Rationale: Confirmation/cancellation must be reachable through the existing API, but should still respect basic role boundaries. Date/Author: 2026-02-28, Codex

Outcomes & Retrospective

Booking lifecycle notifications are now implemented with audit-friendly records and idempotent sending. Booking creation and status changes (confirmed/cancelled) trigger SMS/WhatsApp notifications for both customer and staff, and role-based validation now governs status updates. Provider adapters remain scaffolds, so production delivery still requires real SMS/WhatsApp wiring.

Context and Orientation

Booking creation and updates are handled in backend/apps/bookings/views.py via a DRF ModelViewSet. The booking model is in backend/apps/bookings/models.py, with status indicating lifecycle state. There is currently no notification system beyond OTP scaffolding in backend/apps/accounts/services/otp.py. This plan adds a new Django app at backend/apps/notifications/ to store notification records, format booking lifecycle messages, and dispatch them via SMS or WhatsApp providers.

A “notification” in this repository means a user-facing message (SMS or WhatsApp) that is stored for auditability in a Notification database row. A “lifecycle event” is a booking change that should inform the customer and staff: booking created, confirmed, or cancelled.

Plan of Work

First, create a notifications Django app with models and admin registration. Define Notification, NotificationEvent, NotificationStatus, and NotificationChannel in backend/apps/notifications/models.py. The model must capture booking, recipient, phone number, event, channel, status, provider, message, and send timestamps, and it must be idempotent by preventing duplicates for the same booking + recipient + event + channel. Register the model in backend/apps/notifications/admin.py and add apps.notifications to INSTALLED_APPS in backend/salon_api/settings.py.

Next, implement notification dispatch in backend/apps/notifications/services.py. Reuse OTP provider adapters from apps.accounts.services.otp with a new NOTIFICATION_PROVIDER setting (default to OTP_PROVIDER). Add a NOTIFICATION_DEFAULT_CHANNEL setting (default sms). Implement send_booking_notification(booking, recipient, event) to build localized message text using the recipients preferred language, send via the provider, and update the notification status. Implement notify_booking_lifecycle(booking, event) for initial sends and notify_on_status_change(booking, previous_status) to trigger only on status transitions. If the recipient lacks a phone number, record the notification as skipped with a reason.

Then, wire booking lifecycle events in backend/apps/bookings/views.py. On perform_create, call notify_booking_lifecycle(..., booking_created) so both customer and staff receive a message. On perform_update, compare the previous status to the new status and call notify_on_status_change for confirmed or cancelled transitions. Avoid sending notifications if the status does not change.

Finally, add tests in backend/apps/notifications/tests/test_booking_notifications.py. Cover booking creation (two notifications), status change to confirmed (two notifications), and a repeat status update that should not create duplicates. Ensure tests use phone numbers on users to avoid skipped notifications. Update docs/risks.md to mark “No notifications (email/SMS) beyond OTP scaffolding” as addressed once tests pass.

Concrete Steps

Run these commands from the repository root (/home/m7md/kshkool/Salon).

  1. Add notifications app code and migrations.

    • Create backend/apps/notifications/ with apps.py, models.py, services.py, admin.py, and a migration 0001_initial.py.
    • Update backend/salon_api/settings.py to include apps.notifications and notification settings.
  2. Wire booking lifecycle events.

    • Update backend/apps/bookings/views.py to call notification services on create and status changes.
  3. Add tests.

    • Create backend/apps/notifications/tests/test_booking_notifications.py.
  4. Run backend tests.

    • From backend/ with the venv active: python3 -m pytest

Validation and Acceptance

  • Creating a booking returns HTTP 201 and creates two notification records (customer + staff) with event booking_created.
  • Updating a bookings status to confirmed creates two notification records with event booking_confirmed.
  • Repeating the same status update does not create duplicate notifications (records remain at two for that event).
  • python3 -m pytest passes, and the new tests fail before the change and pass after.

Idempotence and Recovery

Notification creation is idempotent by a uniqueness constraint on booking + recipient + event + channel. Re-running the send logic will update a pending or failed notification rather than creating duplicates. If a migration needs to be reverted, use standard Django migration rollback and re-apply. If a notification provider is misconfigured, notifications will be marked failed and can be retried after fixing settings.

Artifacts and Notes

Expected console-provider log example when creating a booking:

INFO OTP SMS to 0500000002: Your booking request is received for Haircut at Main Salon on 2026-03-01 10:00.
INFO OTP SMS to 0500000003: Your booking request is received for Haircut at Main Salon on 2026-03-01 10:00.

Interfaces and Dependencies

  • backend/apps/notifications/models.py must define Notification, NotificationEvent, NotificationStatus, NotificationChannel.
  • backend/apps/notifications/services.py must expose send_booking_notification, notify_booking_lifecycle, and notify_on_status_change.
  • backend/apps/bookings/views.py must call notification services in perform_create and perform_update.
  • backend/salon_api/settings.py must define NOTIFICATION_PROVIDER and NOTIFICATION_DEFAULT_CHANNEL settings.

Plan Maintenance Note: Created on 2026-02-28 to implement booking lifecycle notifications as the next Phase 1 reliability milestone. Plan Maintenance Note (Update): Marked milestones complete, recorded the booking status update discovery, and documented role-based status validation after implementing notifications and tests on 2026-02-28.