# OJSTO v12 Operational Hardening Build

This build focuses on closing practical gaps before a real staging run.

## What changed

1. **Customer portal isolation**
   - Customer users now only list shipments for their own `customer_id`.
   - Customer shipment show checks ownership through `PortalAccessService`.

2. **Courier portal isolation**
   - Courier users only list shipments assigned to their own `courier_id`.
   - Courier update/show now denies access to other couriers' shipments.

3. **Excel import hardening**
   - `ShipmentExcelRowValidator` now returns a stable shape: `valid/errors`.
   - Customer/Admin Excel import now requires a customer context.
   - CSV import maps old headers like `receiver mobile`, `ref`, `cod`, `gov`, `area` to the new schema.
   - Production XLSX import should still be wired through Laravel Excel, but the row contract is now stable.

4. **Shipment creation consistency**
   - `ShipmentCreatorService` accepts old and new field names.
   - Admin portal, customer portal, and Excel import all use the same central creation service.

5. **Accounting locks**
   - New `AccountingLockService` prevents editing/deleting shipment financials after settlement/invoicing.
   - This is a key guard against losing money after COD settlement.

## Still missing before production

- Full XLSX implementation with Laravel Excel.
- Full invoice PDF rendering.
- Complete old-system report parity.
- Full permission screen for admins to edit roles/permissions from UI.
- End-to-end UAT on a real staging database.
