# LendCore System Modules and Database Schema

## Scope and source of truth

This document is a code-reading inventory of the LendCore Laravel application. It describes the active routes, controllers, services, Eloquent models, migrations, jobs, and console commands currently present in the repository. The migration files are the schema authority; the live database may contain additional data or historical differences until migrations are run.

No application code is changed by this document.

## System shape

LendCore is a loan-management system with three authenticated web roles/surfaces and a mobile/API surface:

- **Customer web portal**: registration, login, loan applications, fee payments, repayment payments, and transaction history.
- **Admin portal**: loan, tier, repayment, fine, user/officer, guarantee-deposit, suspense, settings, audit, reporting, and export management.
- **Officer portal**: read-oriented dashboards for assigned users, loans, and repayments.
- **Sanctum API**: mobile authentication and customer loan/repayment/transaction/notification access.
- **M-Pesa integration**: STK push, C2B validation/confirmation, B2C disbursement callbacks, callback URL registration, and non-STK payment handling.

The primary business chain is:

```text
User -> LoanRequest -> Loan -> Repayment -> Fine
  |        |            |         |
  +--------+------------+---------+--> Transaction -> PaymentAllocation
                                           |
                                           +--> SuspenseTransaction when unmatched
```

`GuaranteeDeposit` belongs to both a user and a loan. `Tier` controls loan eligibility and pricing. `AuditLog` records important administrative and callback actions. `Setting` stores runtime configuration.

## Major modules and functions

### Authentication, roles, and registration

**Web controllers**

- `Auth\\RegisterController`: displays and processes customer registration.
- `Web\\UserAuthController`: customer login form, login, and logout.
- `Officer\\OfficerAuthController`: officer login form, login, and logout.
- `routes/web.php`: admin login/logout are currently inline route handlers; admin access is checked by role.
- `Api\\AuthController`: API login, registration, current-user response, profile update, accessible-tier lookup, and token logout.

**Models and middleware**

- `User`: role/status casting, customer loans and requests, transactions, accessible tier, officer assignments, login activities, and guarantee deposits.
- `AdminMiddleware`, `UserMiddleware`, and `OfficerMiddleware`: restrict the corresponding authenticated areas.
- Sanctum personal access tokens protect the authenticated API group.

**Data touched**: `users`, `password_reset_tokens`, `sessions`, `personal_access_tokens`, `login_activities`, `tiers`, `notifications`.

### Tier and product configuration

**Admin controller**: `Admin\\TierController`

- `index`, `create`, `store`, `show`, `edit`, `update`, `destroy`: manage tier definitions.

**Model**: `Tier`

- `loans`: all loans created under a tier.
- `isSequential`, `isAdhoc`: tier behavior checks.
- `canBeAccessedBy`, `scopeAccessibleToUser`: enforce tier visibility/access.

**Pricing fields** include amount range, interest rate, duration periods, installment period, LAF fee type/value, and tier type. Tiers are used by `LoanService` for validation, fee computation, and repayment schedule generation.

**Data touched**: `tiers`, `users`, `loans`, `loan_requests`.

### Loan origination and lifecycle

**Customer web/API controllers**

- `Web\\LoanController`: list/show customer loans, render/submit a loan request, initiate fee payment, and check fee-payment status.
- `Api\\LoanController`: list/show loans, create a loan through the API, and pay the loan fee.

**Admin controller**: `Admin\\LoanController`

- CRUD: `index`, `create`, `store`, `show`, `edit`, `update`, `destroy`.
- Lifecycle: `approve`, `refreshFees`, `disburse`, `manualDisburse`, `status`, `default`, `complete`, `completeDisbursement`, `cancelDisbursement`.

**Core service**: `LoanService`

- `calculateInterest`: calculates interest from principal and rate.
- `calculateFees`: calculates LAF and registration fees, including first-disbursement behavior.
- `isFirstDisbursement`: checks customer disbursement history.
- `calculateInstallmentAmount`: derives an installment amount from total payable and duration.
- `calculateTotalPayable`: combines principal, interest, fees, and previous penalties.
- `applyPreviousPenalty`: applies an imported or prior penalty to a loan.
- `generateRepaymentSchedule`: creates repayment rows for the loan.
- `createLoan`: creates and initializes a loan.
- `updateLoanStatus`, `approveLoan`: transition and approve loans.
- `disburseLoan`, `manualDisburseLoan`: initiate or record automated/manual disbursement, including guarantee-deposit behavior.
- `processMpesaCallback`: handles a disbursement callback.
- `completeLoan`, `defaultLoan`: terminal lifecycle transitions.
- `getLoanSummary`: returns calculated loan status and balance data.

**Model**: `Loan`

- Calculated attributes: total repayable, total repaid, effective status, fees-paid state, fee-payment due, and arrears.
- `syncCompletionStatus`, `hasZeroOutstandingBalance`: synchronize and inspect completion state.
- Relationships: user, tier, repayments, fines through repayments, transactions, allocations, latest disbursement transaction, and guarantee deposits.

**Data touched**: `users`, `tiers`, `loan_requests`, `loans`, `repayments`, `transactions`, `guarantee_deposits`, `payment_allocations`, `audit_logs`.

### Repayments and payment allocation

**Customer web/API controllers**

- `Web\\RepaymentController`: list/show repayments, render payment form, initiate payment, and check status.
- `Api\\RepaymentController`: list/show repayments, initiate payment, and query payment status. Singular `/repayment/...` aliases support older clients.

**Admin controller**: `Admin\\RepaymentController`

- CRUD: `index`, `show`, `create`, `store`, `edit`, `update`, `destroy`.
- Payment operations: `createPayment`, `storePayment`, and `markOverdue`.

**Core service**: `RepaymentService`

- `recordPayment`: records a payment and its related transaction.
- `processMpesaPaymentCallback`: converts an M-Pesa callback into repayment activity.
- `applyPaymentFromTransaction`: applies a transaction to a repayment, with optional rollover.
- `updateRepaymentStatus`, `calculateBalance`: maintain status and outstanding amount.
- `recordLoanPayment`: applies a payment across a loan's repayment schedule.
- `recordPaymentForUserActiveLoans`: resolves and applies payments against active customer loans.
- `recordFeePayment`: records registration/LAF fee payment.
- `markAsOverdue`, `getOverdueRepayments`, `isOverdueTodayOrPastDue`, `getDaysOverdue`: overdue processing.
- `applyPartialPayment`: handles partial installments.
- `getRepaymentSummary`: returns repayment totals and status.

**Payment allocation**: `PaymentAllocation` provides an allocation ledger when one incoming transaction is distributed across one or more loan installments. `TransactionService` and `RepaymentService` are the main writers/readers.

**Data touched**: `repayments`, `transactions`, `payment_allocations`, `loans`, `fines`, `users`, `suspense_transactions`.

### Fines and arrears

**Admin controller**: `Admin\\FineController`

- `index`, `show`, and `waive` review and waive fines.

**Core service**: `FineService`

- `calculateFine`: calculates a repayment fine using the configured rules and payment state.
- `getLoanTotalFines`, `getRepaymentFineForLoan`: aggregate fines.
- `applyFine`: creates or applies a fine to an overdue repayment.
- `getFineDetails`: returns fine calculation details.
- `captureFineOnPayment`: captures fine amounts during payment allocation.
- `waiveFine`: waives or reduces a fine with a reason.
- `getUserTotalFines`, `getUserPendingFines`: customer-level fine summaries.

**Model**: `Fine` belongs to one `Repayment`. Fine settings are read from `Setting`; administrative changes are audited.

**Data touched**: `fines`, `repayments`, `loans`, `users`, `settings`, `audit_logs`, `transactions`.

### Transactions and M-Pesa payments

**Services**

- `TransactionService`: creates payment/disbursement transactions; resolves callback timestamps; creates repayment references; finds pending or M-Pesa transactions; updates callbacks/status; returns transaction and payment summaries; reverses transactions.
- `MpesaAuthService`: obtains and caches an OAuth access token.
- `MpesaApiService`: posts to configured M-Pesa endpoints.
- `MpesaService`: sends B2C payments, sends STK pushes, and registers C2B and non-STK callback URLs.

**Callback controllers**

- `Api\\MpesaCallbackController`: handles STK callback, B2C result/timeout, C2B validation/confirmation, non-STK validation/confirmation, callback URL registration, duplicate/pending queue checks, and reference resolution.
- `ExternalUrlsEndpoints\\MpesaBounceController`: forwards production callback payloads to configured application endpoints.

**Queue path**

- `ProcessC2bNonStkConfirmation`: queued processing for non-STK C2B confirmations.
- `Api\\WebQueueController`: web-triggered queue processing endpoint.
- `QueueWorkerTriggerService`: detects pending queue jobs and starts/configures the worker process.

**Data touched**: `transactions`, `repayments`, `loans`, `users`, `payment_allocations`, `suspense_transactions`, `jobs`, `failed_jobs`, `audit_logs`.

### Suspense and unmatched payments

**Admin controller**: `Admin\\SuspenseTransactionController`

- `index`, `show`: inspect unmatched transactions.
- `searchUsers`, `getUserLoans`, `getLoanInstallments`: find a possible destination.
- `reassign`, `destroy`, `clearAll`: apply, delete, or clear suspense records.

**Service**: `SuspenseService`

- `saveUnmatchedTransaction`: stores an incoming payment that cannot be matched.
- `removeProcessedTransaction`, `clearAllSuspenseTransactions`: remove resolved records.
- `reassignAndApply`: links a suspense payment to a user/loan/repayment and applies it.

**Service**: `C2bUserMatchingService`

- `findUserByBillRef`: resolves a customer from a bill/reference value.
- `buildCandidateRefs`: normalizes possible reference formats.

**Data touched**: `suspense_transactions`, `users`, `loans`, `repayments`, `transactions`, `payment_allocations`.

### Guarantee deposits

**Admin controller**: `Admin\\GuaranteeDepositController`

- `index`: dashboard/reporting view.
- `updateUser`: update the customer's deposit balance/configuration.
- `update`: update a loan-specific guarantee deposit.

**Model**: `GuaranteeDeposit` belongs to `User` and `Loan`. Loan disbursement methods determine the amount, percentage, and usage (`offset_final_installment`, `carry_forward`, or `user_account`).

**Data touched**: `guarantee_deposits`, `loans`, `users`, `transactions`.

### User, officer, and legacy import administration

**Admin controller**: `Admin\\UserController`

- Customer administration: `index`, `show`, `approve`, `reject`, `updateTier`.
- Import: `showImportForm`, `importLegacyCsv`.
- Officer administration: `listOfficers`, `showCreateOfficerForm`, `createOfficer`, `editOfficerForm`, `updateOfficer`, `deleteOfficer`.
- Assignments: `officerAssignments`, `addUserToOfficer`, `removeAssignedUser`.

**Import service**: `MasterLegacyImportService`

- `import`, `doImport`, and `processRow`: execute the CSV import.
- `normalizeHeaders`, `parseDecimal`, `parseDate`, `extractPrimaryPhone`: normalize source data.
- `findOrCreateUser`, `createOrUpdateLoan`, `createLoan`: upsert imported customers and loans.
- `resolveTierForImport`, `findTierForAmount`: map historical amounts to tiers.
- `applyLoanImportDefaults`, `reconcileLoanSummaryFromRepayments`: initialize and reconcile imported loans.
- `ensureDisbursementTransaction`, `markFeesAsPaid`, `applyHistoricalPayment`: reconstruct historical financial state.
- `collectOfficerAssignment`, `assignPendingOfficerAssignments`, `resolveOfficerByNationalId`: restore officer assignments.
- `validateLegacyImportPaidValue`, `shouldBypassNormalReconciliation`: protect legacy accounting behavior.

**Data touched**: `users`, `tiers`, `loans`, `repayments`, `transactions`, `payment_allocations`, `guarantee_deposits`, `audit_logs`.

### Settings and audit

**Settings controller**: `Admin\\SettingsController`

- `index`: display settings.
- `updatePin`, `resetPinToDefault`: manage the admin PIN.
- `updateRegistrationFee`: update registration fee configuration.
- `updateFineSettings`: update fine calculation configuration.

**Models/services**

- `Setting::get` and `Setting::set`: database-backed key/value configuration.
- `AuditService::log`: records an administrative or system action.
- `AuditService::getResourceLogs`, `getAdminLogs`, `getActionLogs`: retrieve audit history.
- `Admin\\AuditLogController::index` and `show`: browse audit records.

**Data touched**: `settings`, `audit_logs`, `users`.

### Reporting and exports

**Service**: `ReportingService`

- `getDisbursementReport`: disbursement view.
- `getLoanStatusReport`: loan status totals.
- `getCollectionReport`: collection and repayment totals.
- `getLoanPerformanceReport`: performance metrics.
- `getGuaranteeDepositReport`: guarantee-deposit metrics.
- `getActiveUsersReport`: active customer metrics.
- `getIndustryMetrics`: broader aggregate metrics.

**Controller**: `Admin\\AdminReportingController`

- Dashboard/index plus disbursement, performance, collection, C2B transaction, allocation, and loan-general-information reports.
- Generic and detailed Excel/PDF export methods for those reports.

**Data touched**: primarily `users`, `tiers`, `loans`, `repayments`, `fines`, `transactions`, `payment_allocations`, `guarantee_deposits`, and `suspense_transactions`.

### Notifications and observability

- `Api\\NotificationController::index`: returns notifications for the authenticated API user.
- Laravel notifications use the `notifications` table and polymorphic `notifiable` columns.
- Laravel Telescope uses `telescope_entries` for request/job/query observation when enabled.
- `LoginActivity` tracks login metadata and belongs to `User`.

## Database tables

The following table list combines the base migrations and all later schema changes. Columns are grouped by purpose to keep the inventory readable; defaults and nullability should be confirmed in the migration files before making database changes.

### Domain tables

#### `users`

Identity and account table for customers, admins, and officers.

- Identity/authentication: `id`, `name`, `email`, `email_verified_at`, `password`, remember token, timestamps.
- Profile/import data: `id_number`, `national_id`, `address`, `phone`, `age`, `mpesa_phone`.
- Access and workflow: `role`, `status`, `accessible_tier_id`, `assigned_officer_id`, `first_disbursement_completed`.
- Security/configuration: `admin_pin_hash`.
- Relationships: self-referencing officer assignment; optional accessible tier; loans, loan requests, transactions, login activities, and guarantee deposits.

#### `tiers`

Loan products and eligibility/pricing rules.

- `id`, `name`, `min_amount`, `max_amount`, `interest_rate`.
- `duration_periods`, `installment_period` (`weeks` or `months`).
- `laf_fee_type` (`percentage` or `fixed`), `laf_fee_value`.
- `tier_type` (including sequential/adhoc behavior), timestamps.
- Referenced by `users.accessible_tier_id`, `loans.tier_id`, and `loan_requests.tier_id`.

#### `loan_requests`

Customer applications before or alongside loan creation.

- `id`, `user_id`, `tier_id`, `requested_amount`, `approved_amount`.
- `status` (`pending`, `approved`, `rejected`, or `disbursed`).
- `admin_notes`, `approved_by`, `approved_at`, timestamps.
- `approved_by` is a second relationship to `users`; a request can have one associated `loan`.

#### `loans`

Principal, pricing, lifecycle, and loan-level balance state.

 Ownership/product: `id`, `user_id`, `tier_id`.
- Pricing: `amount`, `interest`, `laf_fee`, `registration_fee`, `previous_penalty_amount`, `total_payable`.
 `id`, `repayment_id`, `amount`, `days_overdue`, timestamps.
 Fine values are calculated and updated by `FineService`; waiver actions are audited in `audit_logs` rather than stored as fine status/reason columns.
- Lifecycle: `status`, `legacy_import`, `legacy_paid`, timestamps.
 `approved_by` is a second relationship to `users`; the model exposes an associated `loan` relationship, but the current migration set does not define a `loan_request_id` column on `loans`.
- Relationships: user, tier, loan request, repayments, transactions, allocations, fines through repayments, and guarantee deposits.

#### `repayments`

Scheduled installments and their payment state.

- `id`, `loan_id`, `installment_number`, `is_active`, `due_date`.
- `amount_due`, `amount_paid`, `status`, `paid_at`, timestamps.
- Has one optional fine, many transactions, and many payment allocations.

#### `fines`

Fine records attached to repayment obligations.

- `id`, `repayment_id`, `amount`, status/reason fields from the base fine migration, timestamps.
- Fine values are calculated and updated by `FineService`; waiver actions are audited.

#### `transactions`

Financial event ledger for payments and disbursements.

- Ownership/links: `id`, `user_id`, nullable `loan_id`, nullable `repayment_id`.
- Core event: `reference`, `amount`, transaction `type`, `status`, timestamps.
- M-Pesa data: `mpesa_code`, `mpesa_transaction_id`, `checkout_request_id`, `originator_conversation_id`, `callback_data`, `processed_at`.
- Used for payment history, STK/B2C/C2B callback idempotency, disbursement tracking, and repayment allocation.

#### `payment_allocations`

Breakdown of a payment transaction applied to a loan installment.

- `id`, nullable `transaction_id`, `loan_id`, `repayment_id`.
- `mpesa_transaction_id`, nullable `batch_reference`, `amount`, timestamps.
- The migration defines indexes but not application-level foreign-key constraints for all three IDs; the services maintain the logical links.

#### `guarantee_deposits`

Deposit movements or balances associated with a customer and loan.

- `id`, `user_id`, `loan_id`, `amount`, plus status/usage and timestamps from the guarantee migrations.
- Cascades with the owning user/loan according to the migration constraints.

#### `suspense_transactions`

Unmatched inbound payment records awaiting operator resolution.

- Optional `user_id`, `loan_id`, `repayment_id`.
- Unique `transaction_id`, `bill_ref_number`, `msisdn`, `amount`.
- `status` (`unmatched`, `matched`, or `applied`), `original_payload`, timestamps.

#### `settings`

Database-backed key/value configuration.

- `id`, unique `key`, `value`, timestamps.
- Used for registration-fee, fine, PIN, and related runtime settings.

#### `audit_logs`

Administrative/system action history.

- `id`, `admin_id`, `action`, nullable `resource_type`, nullable `resource_id`.
- `changes`, `reason`, `ip_address`, `user_agent`, timestamps.
- `admin_id` points to `users`; resource references are polymorphic-by-convention rather than a database foreign key.

#### `login_activities`

Login telemetry.

- `id`, nullable `user_id`, `login_type`, `device_type`, `phone_type`, IP/user-agent and timestamp fields from the migration.
- User deletion nulls the user reference.

### Laravel and operational tables

These tables support the framework or runtime infrastructure rather than loan-domain behavior.

- **`password_reset_tokens`**: email-keyed password reset tokens and creation time.
- **`sessions`**: server-side web sessions when the database session driver is used.
- **`cache`**: cache key/value/expiration storage.
- **`cache_locks`**: distributed cache locks.
- **`jobs`**: queued job payloads, attempts, reservation, and availability timestamps.
- **`job_batches`**: batch metadata, pending/failed counts, options, and cancellation time.
- **`failed_jobs`**: failed queue payloads, exception details, UUID, and failure time.
- **`personal_access_tokens`**: Sanctum polymorphic API tokens, abilities, and expiry/revocation fields.
- **`notifications`**: Laravel database notifications with UUID primary key and polymorphic `notifiable` identity.
- **`telescope_entries`**: Telescope observation records, including request/command/job/query payload content and batch/index metadata.

There are two queue-table migrations in the repository history: the Laravel base queue migration and `2026_06_27_000001_create_queue_tables.php`. The latter is intended to create the queue tables when they are absent; deployments should ensure migrations are not applied in a way that attempts to recreate existing tables.

## Relationship map

| Parent | Child | Cardinality / purpose |
| --- | --- | --- |
| `users` | `tiers` | A user may have one accessible tier; a tier may be accessible to many users. |
| `users` | `users` | An officer may have many assigned users through `assigned_officer_id`. |
| `users` | `loan_requests` | One user can submit many requests. |
| `tiers` | `loan_requests` | One tier can receive many requests. |
| `users` | `loans` | One user can hold many loans. |
| `tiers` | `loans` | One tier can define many loans. |
| `loan_requests` | `loans` | A request may produce one loan. |
| `loans` | `repayments` | One loan has many scheduled repayments. |
| `repayments` | `fines` | A repayment may have one fine; a loan exposes fines through repayments. |
| `users` | `transactions` | One user can have many financial transactions. |
| `loans` | `transactions` | A loan may have many payment/disbursement transactions. |
| `repayments` | `transactions` | A repayment may have many related transactions. |
| `transactions` | `payment_allocations` | One transaction can be split into multiple allocation rows. |
| `loans` | `payment_allocations` | Allocations identify their destination loan. |
| `repayments` | `payment_allocations` | Allocations identify their destination installment. |
| `users` / `loans` / `repayments` | `suspense_transactions` | Optional links are added when an unmatched payment is resolved. |
| `users` | `guarantee_deposits` | One user can have many deposit records. |
| `loans` | `guarantee_deposits` | One loan can have many deposit records. |
| `users` | `audit_logs` | An admin user authors many audit entries. |
| `users` | `login_activities` | A user can have many login records. |

## Main operational flows

### Customer loan flow

1. A customer registers or logs in.
2. The customer is limited to accessible `tiers`.
3. A loan request is submitted or an eligible loan is created.
4. `LoanService` calculates interest, fees, total payable, and the repayment schedule.
5. An admin approves the loan and initiates automated or manual disbursement.
6. M-Pesa callbacks update `transactions` and the loan lifecycle.
7. Scheduled `repayments` are paid through STK, manual entry, or matched C2B payments.
8. `RepaymentService` allocates money, updates balances, and handles rollover/partial payment.
9. Overdue installments receive `fines`; operators can waive them with an audit reason.
10. The loan is completed when its outstanding balance is cleared, or marked defaulted by an admin.

### C2B matching flow

1. M-Pesa sends validation/confirmation data.
2. `C2bUserMatchingService` attempts to resolve the bill/reference to a user.
3. A matching payment becomes a `transaction` and is applied to active loans/repayments.
4. An unmatchable payment is stored in `suspense_transactions`.
5. An admin selects a user, loan, and installment; `SuspenseService` reassigns and applies it.
6. Allocation and status records provide the audit trail for the applied amount.

### Reporting flow

Admin report routes call `ReportingService`, which aggregates domain tables. Export methods transform the same report families into Excel or PDF output. Reports do not introduce a separate reporting database table in the migration set.

## Important implementation notes

- Money fields are represented as decimal database columns and are cast by the models/services; preserve decimal arithmetic when changing financial logic.
- Several compatibility endpoints and legacy-import fields exist intentionally. `legacy_import` and `legacy_paid` should be treated as historical accounting inputs, not ordinary new-loan fields.
- `transactions` is the integration ledger, while `payment_allocations` is the distribution ledger. They answer different questions and should not be collapsed.
- `audit_logs.resource_type/resource_id` and notification/token polymorphic fields are convention-based links; they are not ordinary domain foreign keys.
- The migration history contains incremental renames and duplicate-safe guarantee/queue migrations. Inspect the complete migration sequence before changing a production schema.

## Primary source files

- [Web routes](../routes/web.php)
- [API routes](../routes/api.php)
- [Models](../app/Models)
- [Services](../app/Services)
- [HTTP controllers](../app/Http/Controllers)
- [Migrations](../database/migrations)
- [Queued jobs](../app/Jobs)
- [Console commands](../app/Console/Commands)

## Mobile app interface

Mobile source inspected: `C:\Users\HomePC\Documents\Devs\newtronic`.

This section documents the current Flutter client branching and its interaction with the LendCore API. It is an interface inventory, not an implementation plan. No mobile or Laravel source code was changed while preparing it.

### Mobile application structure

- **Entry point**: `lib/main.dart`.
- **API client**: `lib/services/api_service.dart`.
- **State providers**: `lib/providers/auth_provider.dart` and `lib/providers/loan_provider.dart`.
- **API/data models**: `lib/data/model/` (`ApiUser`, `Tier`, `Loan`, `Repayment`, `Fine`, `Transaction`, `Balance`, `Bank`, and related models).
- **Screens**: `lib/presentation/screen/`.
- **Legacy/local repository**: `lib/data/repository/repository.dart`.
- **Testing**: `test/widget_test.dart`.

The app uses Flutter, Provider, Dio, the `http` package, Flutter Secure Storage, dotenv, and device-information plugins.

### Startup and navigation branching

`MyApp` registers `AuthProvider` and `LoanProvider`, starts an inactivity timer, and logs the user out after two minutes without pointer interaction or when the app becomes inactive, paused, or detached.

Named routes are selected by `_MyAppState.onGenerateRoute` in `lib/main.dart`:

| Route | Screen / purpose |
| --- | --- |
| `/splash` | Startup authentication decision. |
| `/authentication` | Welcome, login, and registration `PageView`. |
| `/home-screen` | Authenticated customer shell. |
| `/pending-approval` | Non-approved account state. |
| `/profile` | Profile display/edit surface. |
| `/notifications` | Notification surface. |
| `/loan-details` | Loan overview/details. |
| `/apply-loan` | Tier selection and loan application. |
| `/repayments` | Repayment list. |
| `/repayment-detail` | Repayment detail and payment initiation. |
| `/transaction` | Local transaction prototype. |
| `/add-transaction` | Local bank-transfer prototype. |
| `/status-transaction` | Local transfer status prototype. |
| `/transaction-history` | Local/mock transaction history. |

Unknown routes fall back to `/splash`.

#### Splash decision tree

`SplashScreen._routeToInitialScreen()` calls `AuthProvider.checkAuth()` and waits two seconds before routing:

```text
checkAuth()
  no valid user/token -> /authentication
  valid user + status == approved -> /home-screen
  valid user + any other status -> /pending-approval
```

#### Authentication decision tree

`AuthenticationScreen` uses a non-scrollable `PageView`:

- Page 0: welcome.
- Page 1: login.
- Page 2: registration.

Login validates email/password locally, calls `AuthProvider.login()`, then routes approved users to `/home-screen` and pending users to `/pending-approval`. Other statuses are logged out and shown as an error. Registration validates name, email, password confirmation, and a required `254XXXXXXXXX` M-Pesa number, calls `AuthProvider.register()`, and routes based on the returned status.

The Laravel API permits `mpesa_phone` to be nullable, but the mobile registration UI currently requires it.

#### Authenticated customer shell

`MainNavigationScreen` keeps a local selected-tab index and presents five tabs:

1. `HomeScreen`
2. `LoanDetailsScreen` without a loan argument
3. `RepaymentsScreen`
4. `TransactionHistoryScreen`
5. `ProfileScreen`

The shell does not use nested navigation routes for tab state.

### Mobile authentication and transport contract

`ApiService.baseUrl` resolves in this order:

1. `--dart-define=API_BASE_URL`.
2. The mobile `.env` value.
3. `http://localhost:8000/api`.

The inspected mobile `.env` points to an ngrok API URL. The legacy repository separately stores the same host and appends `/api`.

Tokens are stored primarily in Flutter Secure Storage under `token`, with browser `localStorage['auth_token']` as a web fallback and `_cachedToken` in memory. Authenticated requests send:

```http
Authorization: Bearer {token}
Accept: application/json
Content-Type: application/json
```

The Dio interceptor adds `ngrok-skip-browser-warning` for ngrok hosts and retries connection/timeout failures up to three times with exponential delays. Logout attempts the remote endpoint and always clears local credentials.

Operational concerns in the current client:

- Request headers and request data are sent to `debugPrint`, which can expose authorization/request details in debug logs.
- Retrying a POST after the server processed it but before the response reached the app can duplicate a loan or payment operation unless the server-side operation is idempotent.
- `AuthProvider.checkAuth()` checks for a token and calls `/user`; failed non-401 responses do not necessarily clear the token.

### API endpoints currently used by mobile

All paths are relative to the Laravel `/api` prefix. Authenticated paths require a Sanctum bearer token.

| Mobile caller | HTTP endpoint | Request / use |
| --- | --- | --- |
| `ApiService.login()` | `POST /login` | `email`, `password`, `login_type`, `device_type`, `phone_type`. |
| `ApiService.register()` | `POST /register` | `name`, `email`, `password`, `mpesa_phone`. |
| `ApiService.logout()` | `POST /logout` | Authenticated token; empty body. |
| `ApiService.getUser()` | `GET /user` | Loads the current user. |
| `ApiService.getTiers()` | `GET /tiers` | Loads tiers for application UI. |
| `ApiService.getLoans()` | `GET /loans` | Loads the customer loan list. |
| `ApiService.getLoan()` | `GET /loans/{id}` | Loads one loan detail. |
| `ApiService.applyLoan()` | `POST /loans` | `tier_id`, `amount`. |
| `ApiService.getRepayments()` | `GET /repayments` | Loads the repayment list. |
| `ApiService.getRepayment()` | `GET /repayments/{id}` | Loads one repayment detail. |
| `RepaymentDetailScreen._initiatePayment()` | `POST /repayments/{id}/pay` | `amount`, optional `mpesa_phone`; starts STK or records manual payment. |

The Laravel API also exposes these routes, but the inspected mobile client does not currently call them:

- `PUT /user` for profile updates.
- `GET /user/accessible-tiers` for server-provided tier access.
- `POST /loans/{loan}/pay-fee` for loan fee payment.
- `GET /repayments/{id}/pay/status` for payment-status polling.
- `GET /transactions` and `GET /transactions/{id}` for transaction history/details.
- `GET /notifications` for database notifications.

The singular repayment compatibility paths (`/repayment/{id}`, `/repayment/{id}/pay`, and `/repayment/{id}/pay/status`) are also not required by the current mobile client, which uses plural paths.

### Mobile feature flows and API interaction

#### Home data loading

`HomeScreen._refreshData()` concurrently calls:

- `LoanProvider.fetchLoans()` -> `GET /loans`.
- `LoanProvider.fetchTiers()` -> `GET /tiers`.
- `LoanProvider.fetchRepayments()` -> `GET /repayments`.

Overview metrics and recent lists are calculated/displayed locally. Provider errors are exposed through `LoanProvider.error`; screens provide loading, empty, retry, and refresh states.

#### Loan application

`ApplyLoanScreen` fetches tiers, filters them locally with `tier.id <= user.accessibleTierId`, initializes the amount to the selected tier minimum, validates the amount against the local minimum/maximum, and posts:

```json
{
  "tier_id": 1,
  "amount": 5000
}
```

Laravel independently validates tier access and amount limits in `Api\\LoanController.store()`. The mobile filtering therefore controls presentation, while the server remains authoritative.

#### Loan details and fee branch

When a loan is supplied, `LoanDetailsScreen` loads the loan list, repayment list, and individual loan detail. It displays status, principal, total payable, duration, installment data, disbursement, fees, guarantee deposits, fines, transactions, and repayment statistics.

The screen renders a fee-payment form, but the inspected mobile `ApiService` and screen code contain no call to `POST /loans/{loan}/pay-fee`. The fee UI is therefore currently incomplete from the API-integration perspective.

#### Repayment payment branch

`RepaymentDetailScreen._initiatePayment()` loads `GET /repayments/{id}`, then posts:

```json
{
  "amount": 250.00,
  "mpesa_phone": "254712345678"
}
```

Laravel behavior is:

- `mpesa_phone` supplied: initiate M-Pesa STK Push.
- `mpesa_phone` omitted/empty: record a manual payment.
- `amount` is required.
- A supplied phone must match `254[0-9]{9}`.

The UI describes this as M-Pesa/STK payment, although an empty phone value selects the manual-payment branch on the server.

`LoanProvider.payRepayment()` separately calls the same endpoint with an empty body. Laravel requires `amount`, but this provider method is not used by the current repayment detail screen, which posts its own payload directly.

#### Payment status behavior

The Laravel API provides `GET /repayments/{id}/pay/status`, but the current mobile client has no `paymentStatus()` API method and does not poll it. A response with `success == true`, `status == pending`, or a non-null `transaction_id` is treated as successful initiation; the app refreshes local loan/repayment data and navigates away without distinguishing pending, completed, failed, or timed-out states.

The mobile integration notes describe a 3-5 second polling loop for up to two minutes, but that behavior is not present in the inspected source.

### Mobile model/resource compatibility

The mobile models generally parse Laravel resource responses, including nested `/user` data. The following differences are important for the interface contract:

- **User**: compatible fields include `id`, `name`, `email`, `status`, `role`, `mpesa_phone`, `accessible_tier_id`, `accessible_tier`, and timestamps.
- **Tier**: Laravel returns `duration_periods`; the mobile model also accepts `installments` and `duration_weeks`, and does not retain Laravel `tier_type`. Duration labels may default to weeks even when the server uses months.
- **Loan**: Laravel returns `repayment_summary`, while the mobile model reads `repayment_stats`; repayment statistics can therefore default to empty/zero values. Laravel may expose singular `guarantee_deposit`, while the mobile model primarily expects `guarantee_deposits`. The mobile model expects `fee_payment_transaction`, which the current Laravel `LoanResource` does not expose.
- **Repayment**: most fields are compatible. The mobile model derives `fine`, `total`, and fallback `amount` from available response fields and accepts nullable `installment_number` for legacy records.
- **Transaction**: the mobile transaction model represents local demo data (`name`, `date`, `price_idr`, `image`) rather than Laravel transaction fields (`loan_id`, `repayment_id`, `type`, `reference`, `amount`, `status`, M-Pesa identifiers, and `processed_at`).

### Mobile-local and mock branches

The following screens currently do not represent live LendCore API interactions:

- `transaction_history_screen.dart`: hard-coded transaction history; no `/transactions` call.
- `transaction_screen.dart`, `add_transaction_screen.dart`, and `status_transaction_screen.dart`: local banking-transfer prototype backed by JSON assets and hard-coded status/recipient data; no Laravel payment is posted.
- `notifications_screen.dart`: hard-coded notifications; no `/notifications` call, and mark-read actions are placeholders.
- `profile_screen.dart`: displays provider data, but `_saveProfile()` waits and shows success without calling `PUT /user`; security/help settings are placeholders.
- `lib/data/repository/repository.dart`: bank, balance, and transaction methods use local JSON assets; only its login/profile methods interact with Laravel.

### Mobile error, loading, and session behavior

The API layer handles HTTP 401 by removing the token, HTTP 429 as a rate-limit error, and network/timeouts through retry logic. Other non-2xx responses generally surface as Dio exceptions. `AuthProvider` and `LoanProvider` expose `isLoading` and `error`; screens use progress indicators, Lottie/shimmer placeholders, retry buttons, snackbars, dialogs, empty states, and pull-to-refresh.

There is currently no centralized API error parser, payment state machine, or global navigation response for session expiration.

### Mobile integration findings

These are confirmed current-state findings from comparing the mobile source with `routes/api.php` and the Laravel resources:

1. The app branches correctly on authentication status, but pending and rejected/non-approved states share the pending-approval route.
2. Client-side tier filtering is not a substitute for server-side authorization, although Laravel performs its own validation.
3. The mobile repayment provider has a no-payload payment method even though the API requires `amount`.
4. STK initiation is treated as a successful payment action without polling the available status endpoint.
5. Empty phone input can invoke manual payment while the UI presents the operation as STK payment.
6. Loan fee payment is displayed but not wired to the available fee endpoint.
7. Transaction history and notifications are mock/local features despite corresponding API endpoints.
8. Profile editing is displayed as successful without calling the available profile-update endpoint.
9. Loan repayment-summary and guarantee-deposit field names do not consistently match the Laravel resource shape.
10. Automatic POST retries and debug logging require care around financial operations and sensitive request data.

### Mobile source references

- Mobile project: `C:\Users\HomePC\Documents\Devs\newtronic`
- Mobile API service: `C:\Users\HomePC\Documents\Devs\newtronic\lib\services\api_service.dart`
- `lib/main.dart`
- `lib/providers/auth_provider.dart`
- `lib/providers/loan_provider.dart`
- `lib/presentation/screen/splash_screen.dart`
- `lib/presentation/screen/auth/authentication_screen.dart`
- `lib/presentation/screen/main/main_navigation_screen.dart`
- `lib/presentation/screen/loans/apply_loan_screen.dart`
- `lib/presentation/screen/loans/loan_details_screen.dart`
- `lib/presentation/screen/repayments/repayments_screen.dart`
- `lib/presentation/screen/repayments/repayment_detail_screen.dart`
- `lib/data/model/`
- `lib/data/repository/repository.dart`