ifnex/01_Documents/IFNEX_ADR.md
Kazem Alghasi 78d21942db docs(architecture): document shipment review workflow and ADRs
Add comprehensive Architecture Decision Records (ADRs) detailing the
new shipment review state machine, review history domain, and customer
resubmission logic. This documentation establishes the separation
between operational shipment status and the review lifecycle.

Additionally, perform repository cleanup by removing obsolete Postman
collections, environment files, test scripts, and unused migrations.

- Add ADR-001 through ADR-005 regarding review workflow and state.
- Add shipment review handoff documentation.
- Remove redundant Postman resources and local environment configs.
- Remove `test_pdf_generation.php` and `resubmit-test.json`.
- Remove unused `shipment_packages` migration.
- Rename and reorganize one-off maintenance scripts.
2026-10-03 06:20:32 +03:30

278 lines
6.8 KiB
Markdown

# 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.