Booking lifecycle notifications and status updates
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
# 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
|
||||
|
||||
- [x] (2026-02-28 17:05Z) Created ExecPlan for booking lifecycle notifications and reviewed bookings + notifications gaps.
|
||||
- [x] (2026-02-28 17:30Z) Implemented notifications app with audit-friendly model, providers, and booking message templates.
|
||||
- [x] (2026-02-28 17:40Z) Connected booking create/update flows to notification dispatch with idempotent event handling.
|
||||
- [x] (2026-02-28 17:55Z) Allowed booking status updates with role checks to enable confirmation/cancellation.
|
||||
- [x] (2026-02-28 18:05Z) Added tests for booking notifications (create, status change, no duplicate sends).
|
||||
- [x] (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 recipient’s 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 recipient’s 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 booking’s 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.
|
||||
+1
-1
@@ -21,7 +21,7 @@ This file tracks known gaps and risks to address in future iterations.
|
||||
## Data And UX
|
||||
- Ratings are not recalculated from reviews.
|
||||
- No image upload or storage strategy for photos.
|
||||
- No notifications (email/SMS) beyond OTP scaffolding.
|
||||
- Booking lifecycle notifications are implemented (SMS/WhatsApp via provider scaffolds); production delivery still needs real provider adapters.
|
||||
- Localization foundations are in progress; full Arabic translation coverage and RTL QA are still pending.
|
||||
|
||||
## Ops And Compliance
|
||||
|
||||
Reference in New Issue
Block a user