# Architecture — Inquiry & Credit Validation Platform

## Architectural style

**Modular Monolith + Service Layer**

The application is deployed as one unit during the early commercial stages,
while business domains remain separated into explicit modules. This keeps
database transactions, operational simplicity and shared-hosting deployment
straightforward without sacrificing future module boundaries.

Entry points:

- User Web App
- Admin Panel
- Bale Bot adapter
- Public/Partner API

All entry points converge on the same application/domain services. UI pages,
controllers, bot handlers and API endpoints must not re-implement business
rules.

## Current Phase 1 boundaries

- Core
- Auth
- Users
- Access (Roles & Permissions)
- Settings
- Audit
- Update

## Planned domain boundaries

- ServiceCatalog
- Providers
- Pricing
- Wallet
- Payments
- Accounting
- Inquiries
- Notifications
- Sms
- Push
- Bale
- Tickets
- Reports

## Inquiry architecture

```text
User / Admin / Bale / Partner API
            |
            v
      Inquiry Service
            |
            +--> Pricing Resolver
            |
            +--> Wallet Hold
            |
            v
      Provider Manager
            |
            v
      Provider Adapter
            |
            v
       External API
            |
            v
      Result Normalizer
            |
            +--> Wallet Capture / Release
            +--> Accounting Posting
            +--> Notification Event
```

No page or bot communicates directly with an external Provider.

## Multi Provider

`ProviderManager` will resolve an adapter using:

- requested service
- provider-service mapping
- active state
- priority/routing policy
- timeout/retry policy
- future health score/failover rules

Every Provider Adapter implements a common contract and translates provider-
specific requests/responses to internal DTOs.

Provider credentials remain server-side and are read through encrypted
configuration/credential services.

## Financial boundaries

Wallet, Payment, Pricing and Accounting are related but separate:

- **Wallet Ledger**: customer money movement.
- **Wallet Hold**: temporary reservation/authorization for an inquiry.
- **Payment**: payment-gateway lifecycle and verification.
- **Pricing**: resolves sale/cost values and creates immutable snapshots.
- **Accounting Journal**: double-entry business accounting.

Normal inquiry charging policy:

1. resolve sale price;
2. create wallet hold;
3. execute provider call;
4. on success: capture the hold into posted wallet ledger;
5. on normal failure: release hold, with no posted debit;
6. if a posted debit must later be reversed: create a refund ledger entry.

The wallet balance may have a transactional projection for performance, but no
projection is allowed to change without the matching immutable ledger entry.

## Consistency and idempotency

Financial/inquiry operations will use:

- database transactions;
- row-level locking;
- unique idempotency keys;
- unique external references;
- explicit state machines instead of ambiguous booleans;
- after-commit events for asynchronous side effects.

## Money

Canonical database storage is integer **IRR (rial)**.

User-facing display may be toman or rial, but conversion is only allowed via
the central `Money` helper. Every Provider Adapter must explicitly normalize
the provider's amount unit at the boundary.

## Date and time

Canonical application/database time is UTC.

Jalali conversion and Asia/Tehran display belong to Presentation only. Raw
database dates are never stored as Jalali strings.

## Security baseline

- CSRF on web state changes;
- HttpOnly / SameSite session cookies and Secure cookies in HTTPS production;
- OTP request throttling and per-challenge attempt limits;
- server-side validation;
- Eloquent/prepared database access;
- escaped Blade rendering;
- central security headers;
- role + permission enforcement;
- encrypted secret settings;
- request IDs for technical logs;
- separate Audit Log for sensitive business/admin changes;
- strict update package path/checksum validation.

## Update architecture

The Update Center separates **package source/staging** from **installation** so
a central update server can later be added without replacing the installer.

```text
Source
  -> Stage
  -> Validate
  -> Backup DB + affected files
  -> Maintenance Mode
  -> Safe Extract
  -> Atomic File Replace
  -> Run Migrations
  -> Clear Cache
  -> Record Version
  -> Leave Maintenance
```

If install fails after backup:

- changed files are restored;
- database is restored;
- execution log is retained;
- if recovery succeeds, Maintenance Mode is disabled;
- if recovery itself fails, Maintenance Mode intentionally remains enabled and
  status becomes `failed_requires_recovery` when DB access is available.

## Phase 2 identity and delivery boundaries

Authentication delegates OTP delivery to `OtpSender`; the production
implementation is `SmsOtpSender`, which uses the shared `SmsService`. The OTP
service owns challenge lifecycle and rate limits but does not know Mida request
parameters.

`NotificationService` owns business notification events. Channel adapters own
transport delivery only:

```text
Business Service
  -> NotificationService
     -> NotificationEvent
        -> DatabaseNotificationChannel
        -> SmsNotificationChannel
        -> [future Push]
        -> [future Bale]
```

User administration is executed through `UserService`; status changes, role
changes and Super Admin safety rules are not implemented in Blade or controllers.

The SMS Mida adapter intentionally does not automatically retry a send after a
connection timeout because an accepted-but-unacknowledged request could cause a
duplicate OTP on retry.
