chore: condense all docs and markdown files

This commit is contained in:
2026-03-14 15:11:40 +03:00
parent f3811b7520
commit 8b626a940e
24 changed files with 483 additions and 1346 deletions
+27 -119
View File
@@ -1,138 +1,46 @@
# Payments Integration (Moyasar, Webhooks, Idempotency)
# Payments Integration (Moyasar)
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.
This ExecPlan follows `docs/PLANS.md`.
## Purpose / Big Picture
After this change, the backend can create Moyasar payments, track their state transitions, and reconcile them via webhooks in an idempotent and auditable way. A user can create a booking payment and see it progress from initiated to paid or failed. You can see it working by creating a payment, receiving a webhook callback that marks it as paid, and observing the payment record transition with a recorded provider reference and idempotency key.
Create payments idempotently, reconcile webhook states safely, and keep payment history auditable.
## Progress
- [x] (2026-02-28 14:35Z) Created ExecPlan for payments integration (Moyasar + webhooks + idempotency).
- [x] (2026-02-28 15:05Z) Inspected payments models/endpoints and aligned naming with Moyasar scaffolding.
- [x] (2026-02-28 15:20Z) Defined payment state model extensions and idempotency tracking fields.
- [x] (2026-02-28 15:40Z) Implemented payment creation service and API endpoint with provider gateway.
- [x] (2026-02-28 15:55Z) Implemented webhook endpoint with secret verification and status mapping.
- [x] (2026-02-28 16:10Z) Added tests for creation, idempotency, and webhook reconciliation.
- [x] (2026-02-28 16:20Z) Updated `docs/risks.md` to close payment integration gaps once tested.
- [x] (2026-02-28 14:35Z) Plan created.
- [x] (2026-02-28 15:55Z) Payment creation + webhook processing implemented.
- [x] (2026-02-28 16:10Z) Tests for create/idempotency/webhooks implemented.
- [x] (2026-02-28 16:20Z) Risks updated.
## Surprises & Discoveries
- Observation: The payments gateway needed an HTTP client dependency, so `requests` was added to backend requirements.
Evidence: `ModuleNotFoundError: No module named 'requests'` when running migrations after adding gateway calls.
- Observation: missing `requests` dependency blocked gateway calls initially.
Evidence: `ModuleNotFoundError: requests`.
## Decision Log
- Decision: Model payment state transitions as explicit status changes with audit-friendly timestamps.
Rationale: Payment flows must be auditable and deterministic under retries.
Date/Author: 2026-02-28, Codex
- Decision: Require idempotency keys on payment creation requests.
Rationale: Prevents duplicate charges when clients retry.
Date/Author: 2026-02-28, Codex
- Decision: Use a dedicated webhook endpoint with signature verification.
Rationale: Ensures authenticity of provider callbacks and protects state integrity.
Date/Author: 2026-02-28, Codex
- Decision: Store provider payloads and webhook payloads on the payment record for auditability.
Rationale: Helps trace payment transitions without introducing a separate event table yet.
Date/Author: 2026-02-28, Codex
- Decision: enforce request-level idempotency key for payment create.
Rationale: prevent duplicate charges on retries.
Date/Author: 2026-02-28/Codex
- Decision: persist provider + webhook payloads.
Rationale: payment auditability/debuggability.
Date/Author: 2026-02-28/Codex
## Outcomes & Retrospective
Payment creation, idempotency handling, and webhook reconciliation are implemented for Moyasar. Tests cover creation, idempotency, and webhook status transitions, reducing the largest Phase 1 reliability gap. Refund/capture operations remain future work if required.
Completed for MVP core flow (create + webhook). Remaining work: richer operational monitoring and optional admin capture/refund APIs.
## Context and Orientation
Payments live in `backend/apps/payments/` with current models and API endpoints. The system currently stores payment records but does not integrate with Moyasar or reconcile webhooks. Booking flows live in `backend/apps/bookings/` and should link to payments. The project standards require business logic in services and predictable error responses.
- Payment model/services/views: `backend/apps/payments/`
- Booking dependency: `backend/apps/bookings/`
## Plan of Work
First, review existing payment models and endpoints to avoid breaking field names. Identify whether `Payment` includes a reference to `Booking`, a `provider_reference`, and a status field. If any are missing, add them along with timestamps for `initiated_at`, `paid_at`, and `failed_at`. Create a migration for the new fields. Ensure status choices include at least `initiated`, `pending`, `paid`, `failed`, and `refunded` if refunds are in scope.
Next, introduce idempotency tracking. Add a `idempotency_key` field to the payment model (unique, indexed) and validate that payment creation requests require it. If a request repeats with the same key, return the existing payment without creating a new provider charge.
Then, implement the Moyasar payment creation service in `backend/apps/payments/services.py`. The service should build the provider request using amount, currency, description, and return URLs, and persist the `provider_reference` (payment id returned by Moyasar). Store the full provider response in a JSON field for audit if available.
Add a dedicated API endpoint for payment creation in `backend/apps/payments/views.py` and `backend/apps/payments/urls.py`. It should:
- Require authentication.
- Validate booking ownership and amount.
- Require `idempotency_key`.
- Call the service to create the provider payment.
- Return the payment record plus any provider redirect URL if applicable.
Then, implement the webhook endpoint (`/api/payments/webhook/`) with signature verification using Moyasars secret. It should parse the event, locate the payment by `provider_reference`, apply an idempotent state transition, and record timestamps. Unknown events should be logged but return 200 to avoid retries if possible.
Finally, add tests in `backend/apps/payments/tests/`:
- Creating a payment succeeds and stores provider reference.
- Creating with the same idempotency key returns the original record.
- Webhook for `paid` updates status and timestamp.
- Webhook with invalid signature is rejected.
- Webhook is idempotent (replay does not change state or duplicate logs).
Update `docs/risks.md` to mark payment integration gaps as addressed.
## Concrete Steps
Run these commands from the repository root (`/home/m7md/kshkool/Salon`).
1. Inspect payments models and endpoints.
- Read `backend/apps/payments/models.py`, `backend/apps/payments/views.py`, and `backend/apps/payments/serializers.py`.
2. Add fields for provider reference, status timestamps, and idempotency.
- Update `backend/apps/payments/models.py` and create a migration.
- Run:
python3 backend/manage.py makemigrations payments
3. Implement services and endpoints.
- Add `backend/apps/payments/services.py`.
- Update serializers and views accordingly.
4. Add webhook endpoint and signature verification.
- Update `backend/apps/payments/urls.py` and `backend/apps/payments/views.py`.
5. Add tests.
- Create `backend/apps/payments/tests/test_payments_flow.py`.
6. Run tests.
- Backend:
source venv/bin/activate
cd backend
python3 -m pytest
Completed for current scope.
## Validation and Acceptance
- Creating a payment with a new idempotency key returns HTTP 201 and a provider reference.
- Creating the same payment with the same idempotency key returns HTTP 200/201 with the original payment (no new provider request).
- A valid webhook updates the payment status to `paid` and sets `paid_at`.
- An invalid webhook signature returns HTTP 400/401 and does not mutate data.
- `python3 -m pytest` passes with the new payments tests.
From `backend/`:
- `python3 -m pytest backend/apps/payments/tests`
Acceptance:
- New key => new payment.
- Same key => existing payment reused.
- Valid webhook transitions state idempotently.
- Invalid webhook auth rejected.
## Idempotence and Recovery
Payment creation is safe to retry with idempotency keys. Webhook processing is idempotent and can be replayed safely. If a payment status change is applied incorrectly, it can be corrected manually via admin and will be documented in audit fields.
## Artifacts and Notes
Example idempotency pattern:
existing = Payment.objects.filter(idempotency_key=key).first()
if existing:
return existing
Example overlap-safe webhook logic:
if payment.status == PaymentStatus.PAID:
return
payment.mark_paid()
## Interfaces and Dependencies
- `backend/apps/payments/models.py` must include fields: `provider_reference`, `idempotency_key`, `status`, `initiated_at`, `paid_at`, `failed_at`, and (optionally) `provider_payload` (JSON).
- `backend/apps/payments/services.py` must define `create_payment_for_booking(booking, idempotency_key, request_data)` and `verify_webhook_signature(request)`.
- `backend/apps/payments/views.py` must expose `PaymentCreateAPIView` and `payment_webhook` with signature verification.
Plan Maintenance Note: Created on 2026-02-28 to implement Moyasar payments with idempotency and webhook reconciliation as the next Phase 1 reliability milestone.
Plan Maintenance Note (Update): Marked steps complete and recorded dependency and audit decisions after implementing payments and tests on 2026-02-28.
Idempotency key guards create path; webhook replay is safe.