# VTU / Digital Services Platform — Architecture Document

Stack: **Laravel 11 (PHP 8.3) + MySQL 8**, Redis (queue/cache), Laravel Sanctum (optional customer auth), Horizon (queue monitoring).

This document is Phase 1 of the build, matching your own required order: architecture → schema → interfaces → flows → security → permissions → implementation.

---

## 1. High-Level Architecture

```
┌─────────────────────────────┐        ┌──────────────────────────────┐
│   Customer Web (Blade/       │        │   Admin Dashboard (Blade/     │
│   Vue/Livewire, no login)    │        │   Livewire or separate SPA)   │
└──────────────┬───────────────┘        └───────────────┬───────────────┘
               │ HTTPS                                    │ HTTPS (auth+2FA)
        ┌──────▼─────────────────────────────────────────▼──────┐
        │                Laravel Application Layer                │
        │  Controllers → Form Requests → Services → Repositories  │
        └──────┬───────────────┬───────────────┬──────────────────┘
               │               │               │
     ┌─────────▼──┐   ┌────────▼───────┐  ┌────▼─────────────┐
     │ PaymentGate │   │ VtuProvider    │  │ NotificationProv │
     │ wayInterface│   │ Interface      │  │ iderInterface    │
     │ (adapters)  │   │ (adapters +    │  │ (SMS/Email/Push) │
     │             │   │  failover mgr) │  │                  │
     └─────────────┘   └────────────────┘  └──────────────────┘
               │               │               │
        ┌──────▼───────────────▼───────────────▼──────┐
        │   MySQL (transactional data, ledger)          │
        │   Redis (queue, cache, rate limiting)          │
        │   Queue Workers / Horizon (async processing)   │
        └────────────────────────────────────────────────┘
```

Key principle: **controllers never talk to a payment gateway or VTU provider directly.** They call a `TransactionService`, which calls interfaces. Adding a new provider = writing one adapter class + one DB row, never touching core logic (your requirement #41/#53).

---

## 2. Folder Structure

```
app/
  Contracts/
    PaymentGatewayInterface.php
    VtuProviderInterface.php
    NotificationProviderInterface.php
  Services/
    Payment/
      PaystackGateway.php
      FlutterwaveGateway.php
      MonnifyGateway.php
      PalmPayGateway.php
      PaymentGatewayManager.php      # resolves active/default gateway
    Vtu/
      VtuProviderManager.php         # failover + priority logic
      Providers/
        ExampleDataProviderA.php     # REQUIRES PROVIDER API DOCUMENTATION
        ExampleDataProviderB.php
    Notification/
      SmsProvider.php
      EmailProvider.php
      PushProvider.php
    TransactionService.php           # orchestrates the full purchase flow
    IdempotencyService.php
    ReconciliationService.php
    FraudService.php
  Models/
    Transaction.php, Payment.php, DataPlan.php, Network.php,
    ApiProvider.php, ApiCredential.php, PaymentGateway.php,
    WalletAccount.php, WalletLedgerEntry.php, Refund.php,
    Referral.php, AuditLog.php, WebhookLog.php, ApiLog.php, ...
  Http/
    Controllers/Api/  (customer-facing, no auth required)
    Controllers/Admin/ (role-protected)
    Middleware/ (RateLimitPurchase, VerifyWebhookSignature, RoleAccess)
    Requests/ (form validation classes)
  Jobs/
    ProcessVtuPurchase.php, RetryFailedTransaction.php,
    SendReceiptEmail.php, RunApiHealthCheck.php, ReconcileTransactions.php
  Events/ + Listeners/ (TransactionSucceeded, TransactionFailed, ...)
database/
  migrations/
  seeders/
routes/
  api.php        # customer endpoints
  web.php        # public pages
  admin.php      # admin dashboard
config/
  vtu.php, payment.php   # provider registry config
```

---

## 3. Core Design Decisions

- **No mandatory accounts.** Every purchase creates a `transactions` row keyed by a public `reference` (e.g. `VTU-20260905-8F72K9`). Customers track status via phone + reference, never raw IDs.
- **Payment verification is server-authoritative.** The frontend never marks a transaction successful. A webhook *or* a polling job hits the gateway's verify endpoint; only that result changes `payment_status`.
- **Idempotency everywhere.** Every payment-webhook and VTU-dispatch call carries an idempotency key (the transaction `reference`). Before dispatching to a provider, we lock the row (`SELECT ... FOR UPDATE`) and check `service_status` isn't already `SUCCESS`/`PROCESSING`.
- **Provider failover is data-driven**, not code-driven: `api_providers` has a `priority` column per `(network_id, service_type)`; `VtuProviderManager` iterates providers in priority order and records success/failure rates.
- **Wallet is double-entry.** `wallet_ledger_entries` is append-only; `wallet_accounts.balance` is a cached, recomputable projection, never mutated directly outside a DB transaction that also writes a ledger row.
- **Credentials are encrypted at rest** using Laravel's `encrypted` cast on `api_credentials.value` / `payment_gateways.secret_key`, and are never returned by any API response or admin JSON payload (hidden via `$hidden` + explicit redaction in logs).

Full DB schema, interface contracts, and the purchase/webhook flow are in the accompanying files:
- `02-DATABASE-SCHEMA.md`
- `app/Contracts/*.php`
- `03-PURCHASE-FLOW.md`
- `04-SECURITY-AND-PERMISSIONS.md`
