diff --git a/backend/apps/accounts/tests/test_twilio_provider.py b/backend/apps/accounts/tests/test_twilio_provider.py deleted file mode 100644 index 63a2907..0000000 --- a/backend/apps/accounts/tests/test_twilio_provider.py +++ /dev/null @@ -1,51 +0,0 @@ -"""Tests for Twilio OTP provider implementation.""" - -import pytest -from unittest.mock import MagicMock, patch - - -@pytest.mark.django_db -@patch("apps.accounts.services.otp.TwilioOtpProvider._get_client") -def test_twilio_send_sms_calls_client(mock_get_client): - from apps.accounts.services.otp import TwilioOtpProvider - - mock_client = MagicMock() - mock_get_client.return_value = mock_client - - with patch.dict("os.environ", { - "TWILIO_ACCOUNT_SID": "AC123", - "TWILIO_AUTH_TOKEN": "token", - "TWILIO_FROM_NUMBER": "+966500000000", - }): - provider = TwilioOtpProvider() - provider.send_sms("+966512345678", "Your code is 123456") - - mock_client.messages.create.assert_called_once_with( - body="Your code is 123456", - from_="+966500000000", - to="+966512345678", - ) - - -@pytest.mark.django_db -@patch("apps.accounts.services.otp.TwilioOtpProvider._get_client") -def test_twilio_send_whatsapp_calls_client(mock_get_client): - from apps.accounts.services.otp import TwilioOtpProvider - - mock_client = MagicMock() - mock_get_client.return_value = mock_client - - with patch.dict("os.environ", { - "TWILIO_ACCOUNT_SID": "AC123", - "TWILIO_AUTH_TOKEN": "token", - "TWILIO_FROM_NUMBER": "+966500000000", - "TWILIO_WHATSAPP_FROM": "14155238886", - }): - provider = TwilioOtpProvider() - provider.send_whatsapp("+966512345678", "Your code is 123456") - - mock_client.messages.create.assert_called_once_with( - body="Your code is 123456", - from_="whatsapp:14155238886", - to="whatsapp:+966512345678", - ) diff --git a/docs/adr/0003-authentica-otp-provider.md b/docs/adr/0003-authentica-otp-provider.md index 7351e55..7952d64 100644 --- a/docs/adr/0003-authentica-otp-provider.md +++ b/docs/adr/0003-authentica-otp-provider.md @@ -6,11 +6,11 @@ Accepted ## Context -The platform requires phone-first authentication with OTP delivery for KSA. The codebase includes multiple provider adapters (`console`, `twilio`, `unifonic`, `authentica`) but only Authentica is implemented for provider-managed OTP delivery (send/verify) and direct SMS messaging. Twilio and Unifonic adapters are partial or unimplemented; a console provider exists for local development. +The platform requires phone-first authentication with OTP delivery for KSA. The codebase includes provider adapters (`console`, `authentica`) and Authentica is implemented for provider-managed OTP delivery (send/verify) and direct SMS messaging. A console provider exists for local development. ## Decision -Use Authentica as the primary OTP provider for the MVP, with `OTP_PROVIDER=authentica` in production environments. Keep `console` for local development and tests, and retain Twilio/Unifonic adapters as scaffolds for future expansion. +Use Authentica as the primary OTP provider for the MVP, with `OTP_PROVIDER=authentica` in production environments. Keep `console` for local development and tests. ## Consequences @@ -20,8 +20,6 @@ Use Authentica as the primary OTP provider for the MVP, with `OTP_PROVIDER=authe ## Alternatives Considered -- Twilio as primary provider: not selected due to KSA-focused delivery needs and current adapter gaps. -- Unifonic as primary provider: deferred until the adapter is fully implemented and validated. ## Related diff --git a/docs/architecture.md b/docs/architecture.md index b0ab8d4..9338e2a 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -67,7 +67,7 @@ The roadmap assumes a KSA-focused first launch (phone auth and Riyadh timezone d ### Backend Risks - **Incomplete provider implementations for production-critical flows** - - Twilio/Unifonic providers in `[backend/apps/accounts/services/otp.py](backend/apps/accounts/services/otp.py)` are stubs with `NotImplementedError` for send methods, yet they are the backbone for both OTP and booking notifications. + - Authentica is the only OTP/notification provider; ensure it is fully configured and exercised in production-like environments. - `MoyasarGateway` lacks `capture_payment` and `refund_payment` implementations, limiting payment lifecycle coverage. - **Risk**: Code reads “production ready” at the API level, but the underlying integrations are not, which could cause outages if deployed naively. - **Tight coupling between OTP and notifications** @@ -125,7 +125,7 @@ This roadmap assumes “MVP” is equivalent to **Phase 1: Core MVP Reliability* ### Phase 0 – Architecture & Production Readiness Hardening - **Finalize critical provider implementations** - - Implement at least one real SMS/WhatsApp provider (Twilio or Unifonic) end-to-end, behind the existing provider abstraction in `[backend/apps/accounts/services/otp.py](backend/apps/accounts/services/otp.py)`, and wire it into `[backend/apps/notifications/services.py](backend/apps/notifications/services.py)`. + - Ensure Authentica OTP/SMS is fully configured and validated end-to-end behind the provider abstraction in `[backend/apps/accounts/services/otp.py](backend/apps/accounts/services/otp.py)`, and wired into `[backend/apps/notifications/services.py](backend/apps/notifications/services.py)`. - Implement or deliberately fence off `capture_payment` and `refund_payment` in `[backend/apps/payments/services/gateway.py](backend/apps/payments/services/gateway.py)` so that the MVP either fully supports or explicitly does not support partial captures/refunds. - **Clarify and document boundaries** - Add a short architecture section in `README`/docs describing how `accounts`, `salons`, `bookings`, `payments`, and `notifications` interact, and what each service is responsible for. @@ -220,4 +220,3 @@ This diagram clarifies current coupling and highlights where future refactors (e - It identifies the highest-risk design/architecture issues that could impede MVP reliability or future evolution. - It provides a phased, concrete sequence of work packages that can be implemented via ExecPlans (e.g., booking notifications, Moyasar payments, phone auth UX). - Each major feature area (auth, bookings, payments, notifications, localization, tests) should have or adopt an ExecPlan under `docs/execplans/` in line with `PLANS.md` before implementation begins. - diff --git a/docs/risks.md b/docs/risks.md index 3661198..8367ce0 100644 --- a/docs/risks.md +++ b/docs/risks.md @@ -5,7 +5,7 @@ This file tracks known gaps and risks to address in future iterations. ## Security And Auth - Phone normalization is KSA-focused and minimal; broaden for multi-country use. - OTP protections are basic; add device fingerprinting and IP throttling if needed. -- Authentica OTP provider is implemented (SMS + WhatsApp via Authentica OTP); Unifonic remains a scaffold. +- Authentica OTP provider is implemented (SMS + WhatsApp via Authentica OTP). - Social login is a placeholder. - `USERNAME_FIELD` is now `"phone_number"`; `REQUIRED_FIELDS = []`; `create_superuser` accepts `phone_number`. Admin and `createsuperuser` work correctly for phone-only users.