# IFNEX Logistics — Architecture Decisions ## ADR-001 — Shipment Review Workflow ### Context The current order workflow uses `Shipment.status` for operational, approval, and payment-related states simultaneously. Current flow: `pending_approval → approved → payment → processed → ...` There is currently no independent representation for: * review decision * requested customer changes * review history * customer resubmission ### Decision Introduce an independent Review State and Review History domain without immediately removing or redesigning the existing `ShipmentStatus` enum. ### Transitional model `Shipment.status` remains backward-compatible: * `pending_approval` * `approved` * `cancelled` * operational statuses * legacy `pending_payment` A new `Shipment.review_state` represents: * `pending` * `changes_requested` * `approved` * `rejected` ### Target workflow ```text Create Order ↓ review_state = pending status = pending_approval ↓ Staff Review ├── Request Changes │ ↓ │ review_state = changes_requested │ ↓ │ Customer Edit │ ↓ │ Resubmit │ ↓ │ review_state = pending │ ├── Approve │ ↓ │ review_state = approved │ status = approved │ └── Reject ↓ review_state = rejected status = cancelled ``` ### Consequences This allows the current client workflow to work without immediately breaking existing code that depends on `ShipmentStatus`. Long term, approval/review state can be fully separated from operational Shipment status. --- ## ADR-002 — Shipment Review History ### Decision Create a dedicated `shipment_reviews` domain instead of storing review reasons and decisions directly on `shipments` or using `ShipmentStatusHistory` as a substitute. A review record should contain at minimum: ```text id shipment_id revision_no decision reason notes reviewed_by reviewed_at created_at updated_at ``` The review record represents one submission/review cycle. ### Rationale `ShipmentStatusHistory` records operational status transitions. Review decisions are a different domain concern and require reviewer identity, reason, notes, and revision context. --- ## ADR-003 — Customer Revision / Resubmission ### Decision Customer correction must not be implemented as a blind PATCH against the Shipment. A resubmission updates the current shipment aggregate transactionally while creating a new review revision. The aggregate includes: ```text Shipment ShipmentPackage[] ShipmentItem[] ``` ### Required behavior Resubmission must: 1. validate the complete order payload; 2. recalculate volumetric and chargeable weight server-side; 3. recalculate pricing server-side; 4. update Shipment fields; 5. synchronize Packages; 6. synchronize Items; 7. create a new review revision; 8. return the shipment in `pending` review state. AWB remains unchanged because the customer is revising the same order. --- ## ADR-004 — Request Changes vs Reject ### Decision These are distinct actions. ### Request Changes * order remains active; * customer may edit; * customer may resubmit; * reason is mandatory; * shipment remains operationally pre-approval. ### Reject * order is terminated; * shipment becomes cancelled; * customer cannot continue the same review cycle. API concepts: ```text POST /staff/orders/{shipment}/request-changes POST /staff/orders/{shipment}/approve POST /staff/orders/{shipment}/reject POST /customer/orders/{shipment}/resubmit ``` --- ## ADR-005 — Payment State ### Decision Do not derive payment state from `Shipment.status`. The current implementation remains temporarily compatible with: ```text Approved → payment available ``` but the target architecture is: ```text Shipment Operational Status Review State Payment State ``` as separate domains. `ShipmentStatus::isPaid()` must eventually be removed or deprecated because states such as `cancelled`, `failed`, and `returned` cannot safely imply payment completion. --- ## ADR-006 — Order Detail API Contract Laravel is the canonical source of the Order Detail API contract. Target response structure: ```text shipment ├── status ├── review ├── sender ├── receiver ├── packages[] ├── items[] ├── financial ├── documents[] └── tracking_events[] ``` WordPress must consume the canonical Laravel structure rather than relying on legacy flattened fields. Known current contract mismatches: * Laravel returns `sender.*`, WordPress expects `sender_name`, `sender_phone`, etc. * Laravel returns `receiver.*`, WordPress expects flattened receiver fields. * Laravel returns tracking event keys `date`, `description`, `location`; WordPress expects `event_date`, `event_description`, `event_time`. These mismatches must be corrected during API/UI hardening. --- ## ADR-007 — Commitment Documents `CommitmentForm` is the reusable template. `ShipmentCommitmentForm` represents the requirement/instance for a particular shipment. For the current client: * physical delivery is the primary process; * online upload is optional; * signed-document upload must not block approval/payment unless explicitly required by business policy. Required documents should eventually be instantiated/snapshotted per shipment instead of dynamically resolving the current active templates. --- ## ADR-008 — Operational Finance Boundary IFNEX is not intended to become a full accounting system. IFNEX should provide logistics-relevant financial information: * wallet * customer receivable/debt status * order financial status * payment transactions * credit/settlement information * audit trail A deeper accounting system should be integrated externally through API rather than recreated inside IFNEX. --- ## ADR-009 — Production Hardening Findings The following findings require later hardening: 1. `ShipmentStatus::isPaid()` is semantically unsafe. 2. `Shipment::isDelivered()` compares an Enum-cast field with a string. 3. `StaffOrderController` lacks explicit role/permission authorization. 4. Order Detail sender/receiver API contract is inconsistent with WordPress. 5. Tracking event API contract is inconsistent with WordPress. 6. PDF download uses a different user-meta token key from the standard Bridge token. 7. Commitment-form shipment requirements are not currently snapshotted. 8. Customer signed-document uploads currently use public storage semantics. 9. `ShipmentPackage` and `ShipmentItem` are not included in the current detailed customer order response. 10. Payment state is coupled to Shipment status. 11. Price calculation and discount consumption require a clear distinction between preview and committed pricing. 12. Existing status/schema migration history should be preserved; do not rewrite historical migrations.