# EDR Freight — How the System Works (Step by Step) A plain-language walkthrough of the whole customer journey: **Onboarding → Contract → Clearance → Booking → Schedule → Delivery** Every step shows its branches. Read the arrows (`→`) as "then". Read **IF** blocks as the different paths. --- ## 1) Onboarding > Goal: register the company so it can make bookings. The wizard has **9 steps** in this order. ``` 1. Nationality 2. Role/Operation 3. Company info 4. Personnel (GM) 5. Contact person 6. Verify phone (OTP) 7. Power of Attorney (optional) 8. Documents 9. Business license per profile ``` ### Step 1 — Pick nationality ``` Foreign OR Ethiopian ``` (stored on the company: `nationality = "foreign" | "ethiopian"`) ### Step 2 — Pick operation type(s) You may pick **more than one**. Each one becomes its own *profile* with its own approval + license. ``` Importer OR Exporter OR Freight Forwarder (importer | exporter | freight_forwarder) ``` ### Steps 3–7 — Fill company + people - **Company:** TIN (auto-looked-up from eTrade), name, email, phone, address (region/zone/woreda/kebele/house), VAT, FAN. - **Personnel:** General Manager name / email / phone. - **Contact person:** name / phone (+ optional position, email). - **Verify:** SMS OTP sent to the contact phone — must enter the 6-digit code. - **Power of Attorney:** all optional. ### Step 8 — Upload company documents → **THIS IS WHERE THE PATH SPLITS** The required documents depend **only on nationality** (NOT on operation type). ``` IF Ethiopian → upload: • TIN Certificate • Commercial License • National ID IF Foreign → upload: • TIN Certificate • Investment License • National ID • Passport ``` All are required (1 file each, pdf/jpg/png, ≤10 MB). ### Step 9 — Business license per profile For **each** operation type you picked, upload that profile's business/trade license (1+ files each). ### After onboarding finishes ``` Company status → "Pending" (backoffice must approve) Each profile status → "Pending" Backoffice approves each profile one by one → profile status = "active", gets a reference (e.g. IM-00001 / EX-00001) → only then can that profile create contracts/bookings ``` **Branch summary** | Nationality | Company documents required | |-------------|----------------------------| | Ethiopian | TIN Certificate · Commercial License · National ID | | Foreign | TIN Certificate · Investment License · National ID · Passport | > Operation type changes **nothing** in the document set — only adds one business-license card per profile. --- ## 2) Contract > Goal: agree the terms (route, cargo, price) and sign. Only an **active profile** can do this. ### Create — the wizard (4 steps) ``` Step 0 Setup operation direction (import/export/intercity), contract kind (ONE_TIME vs GENERAL), new vs renewal, service type, currency, first/last mile, customs-clearing on/off, equipment return Step 1 Cargo+Route container sizes OR bulk commodity, hazardous/reefer flags, origin & destination yard, extra routes (GENERAL only) Step 2 Documents required onboarding docs + any contract-specific uploads Step 3 Review check everything, see quotation, submit (or save draft) ``` Two key choices made here decide later paths: ``` contract kind: ONE_TIME (one shipment at a time) GENERAL (ship many times over a validity window) customs clearing: ENABLED → Path B (Global Logistics clears for you) DISABLED → Path A (you self-clear) — for IMPORT/EXPORT (DOMESTIC/intercity → no clearance at all) ``` ### Status journey (happy path) ``` DRAFT → SUBMITTED (customer submits; prices frozen) → PENDING_APPROVAL (staff accepts intake, sets validity window) → APPROVED (approval chain signs: LINE_STAFF → DIRECTOR → CEO) → CONTRACT_READY (staff generates the contract PDF) → SIGNED_CUSTOMER (customer signs) → counter-sign by staff/director/ceo … then it SPLITS ↓ ``` ### The counter-sign split → which path? ``` IF customs clearing ENABLED (IMPORT/EXPORT) → PATH B status → AWAITING_CLEARANCE_DOCUMENTS IF customs clearing DISABLED (IMPORT/EXPORT) → PATH A (self-clear) status → AWAITING_CLEARANCE_DOCUMENTS IF DOMESTIC / intercity (no clearance) → NO CLEARANCE status → CONTRACT_ACTIVE (GENERAL) or FULLY_EXECUTED (ONE_TIME) → customer can book a shipment right away (skip to section 4) ``` **Side branches at any review stage** ``` staff requests changes → CHANGES_REQUESTED → customer edits → SUBMITTED again staff rejects → REJECTED customer/staff cancels → CANCELLED GENERAL contract later → renew → RENEWAL_DRAFT (copies the old contract) ``` --- ## 3) Clearance > Only happens for IMPORT/EXPORT contracts. Two paths. The loop is the same idea: > **customer uploads → reviewer approves or queries → customer re-uploads → … → finalize.** ### Who reviews? ``` PATH A (self-clear, customs DISABLED) → reviewed by OPERATIONS team PATH B (customs, customs ENABLED) → reviewed by GLOBAL LOGISTICS (GL) ``` ### The status sub-states ``` AWAITING_CLEARANCE_DOCUMENTS customer must upload CLEARANCE_UNDER_REVIEW reviewer is checking CLEARANCE_READY_FOR_BOOKING (Path B) done — GL will make the booking SELF_CLEARED (Path A) done — customer will make the booking ``` ### The review loop (both paths) ``` 1. Customer uploads all required documents → status = CLEARANCE_UNDER_REVIEW → each document = PENDING 2. Reviewer goes document by document: APPROVE → that document = APPROVED QUERY → that document = QUERIED (note required) → contract drops back to AWAITING_CLEARANCE_DOCUMENTS (only the queried doc needs re-uploading; approved ones stay) 3. Customer re-uploads the queried document → back to step 2 4. When ALL required documents are APPROVED → finalize (below) ``` ### PATH A — self-clear (Operations) ``` documents the CUSTOMER uploads (examples): import: customs declaration (IM4/IM5), import release, duty/tax receipt, delivery order, supporting doc export: customs declaration (EX3/EX8), export release, transit (T1), supporting doc no output documents in Path A. Operations finalize (POST .../clearance/ops-finalize) requires: every required doc APPROVED → clearanceStatus = SELF_CLEARED → contract status = CONTRACT_ACTIVE (GENERAL) or FULLY_EXECUTED (ONE_TIME) → CUSTOMER creates the booking (section 4) ``` ### PATH B — customs (Global Logistics) ``` documents the CUSTOMER uploads (examples): import container: commercial invoice, packing list, import license, certificate of origin, freight cost, bill of lading, VGM*, release order* export container: booking confirmation, invoice, packing list, shipping instruction, bank permit, export license, VGM letter*, railway bill, delegation letter (* = required) then GL uploads OUTPUT documents (container only): import: IM4 (required), IM5 (optional), transit screenshot export: EX3 (required), EX8, export release, T1 GL finalize (POST .../clearance/finalize) requires: every required customer doc APPROVED AND every required output doc uploaded → clearanceStatus = CLEARANCE_READY_FOR_BOOKING → GL (not the customer) creates the booking (section 4) ``` ### Cycles (GENERAL contracts) A **cycle** is one clearance round. ONE_TIME contracts have a single cycle (#1). GENERAL contracts open a new cycle each time they need clearance before the next shipment. > Clearance (section 3) is **pre-booking**. After GL creates the booking, the work continues as **GL Phase 2** — see section 4b. --- ## 4) Booking > Goal: turn a cleared/executed contract into an actual shipment. **Who creates it depends on the path.** ``` PATH A / DOMESTIC → the CUSTOMER creates the booking PATH B (customs) → GLOBAL LOGISTICS creates the booking on the customer's behalf ``` ### The gate (who's allowed) ``` IF contract has customs clearing (Path B): only GL, and only when clearanceStatus = CLEARANCE_READY_FOR_BOOKING IF no customs (Path A / DOMESTIC): customer (or staff), and only when contract is FULLY_EXECUTED / CONTRACT_ACTIVE ``` ### Booking wizard (customer self-booking — 7 steps) ``` 0 Operation type import / export / intercity (+ FF variants) 1 Contract type ONE_TIME vs GENERAL ; new vs renewal 2 Service & mile service type, currency (USD/ETB), first/last mile, equipment return, customs agent / customs on-off 3 Cargo details container list (type, qty, VGM) OR bulk weight, hazardous / refrigerated flags 4 Route origin & destination yard; scheduledDate REQUIRED for ONE_TIME (estimate only), NOT set for GENERAL (a day is chosen later) 5 Documents per-booking document uploads 6 Review notes, submit ``` ### Booking status journey ``` DRAFT → generate price → SUBMITTED (if price changed: PRICE_CHANGED_PENDING_CONFIRM → confirm → SUBMITTED) → PENDING_APPROVAL (staff accept intake) → APPROVED / CONTRACT_READY (approval chain) → SIGNED_CUSTOMER → counter-sign … SPLIT ↓ IF clearance applies → AWAITING_DOCUMENTS → DOCUMENTS_UNDER_REVIEW → CLEARANCE_READY IF no clearance → FULLY_EXECUTED directly ``` > The booking has its **own** document clearance loop, mirroring the contract one > (upload → APPROVED/QUERIED → re-upload → finalize). Re-uploading a queried doc > resets it to PENDING. Booking proceeds only when all required docs are APPROVED. ### Pricing & payment ``` price generated from rule engine + live rates, converted to chosen currency (USD/ETB) customer pays (Telebirr) once the booking is FULLY_EXECUTED / SELECTED_FOR_BATCH payment status: PENDING → VERIFICATION_IN_PROGRESS → PAID (or FAILED) ``` --- ## 4b) Global Logistics — Phase 2 (after the booking exists) > Customs (Path B) shipments keep moving through GL after booking. This phase is > a **milestone timeline** plus a set of **structured GL actions**. The customer > only watches and, when asked, pays / uploads a duty slip. ### Milestone timeline When GL creates the booking, the system seeds the **post-booking milestones** for that direction (import ~15, export ~11). Each is `PENDING → COMPLETED`. ``` Import (post-booking): WAGON_REQUESTED → FREIGHT_PAYMENT_SETTLED → WAGON_ALLOCATED → GATEPASS_GRANTED → READY_FOR_LOADING → LOADED → DEPARTED_FROM_DJIBOUTI → ARRIVED_ETHIOPIA → OFFLOADED → T1_CLOSED → RISK_ASSIGNED → IMPORT_RELEASE_GRANTED → IMPORT_PROCESS_COMPLETED → STORAGE_INVOICE_RAISED → EXIT_NOTE_GENERATED Export (post-booking): WAGON_REQUESTED → FREIGHT_PAYMENT_PENDING → FREIGHT_PAYMENT_SETTLED → WAGON_ALLOCATED → CARGO_ARRIVED → READY_FOR_LOADING → LOADED → DEPARTED_TO_DJIBOUTI → ARRIVED_AT_DJIBOUTI → GATEPASS_GRANTED → OFFLOADED ``` Each milestone has an **owner**: ET (GL Ethiopia), DJ (GL Djibouti), OPS (Operations), CUST (customer). Backoffice shows the timeline with a **Complete** button on the next pending step; the customer portal shows the same timeline **read-only**. ### GL actions (the structured part) Plain "Complete" covers most steps. These carry extra data, so they have their own UI cards on the backoffice **milestones page** (`GlActionsPanel`): ``` Station routing → route shipment to a station yard (+ bind GL staff) (GL US-02) Customs risk → assign GREEN / YELLOW / RED → completes RISK_ASSIGNED Duty & tax → GL advises amount + declaration serial → completes DUTY_TAXES_ADVISED → customer uploads slip → DUTY_TAX_PAID GL documents → upload DO / RO / T1 / import release / interchange / final declaration → auto-completes the matching milestone Cargo exception → log SEAL_BROKEN / CONTAINER_OPENED / CONTAINER_DAMAGED / FLUID_LEAKING with photos → alert GL Ethiopia (GL US-07) ``` **Doc-triggered milestones:** uploading the mapped document completes the milestone automatically — no separate click: | Upload (code) | Completes milestone | Who | |---------------|---------------------|-----| | `delivery_order` | DO_COLLECTED | GL DJ | | `release_order` | RELEASE_ORDER_SECURED | GL DJ | | `t1_transport_document` | T1_CLOSED | GL ET | | `import_release` | IMPORT_RELEASE_GRANTED | GL ET | | `full_in_interchange` | OFFLOADED | GL DJ | | `final_declaration` | IMPORT_PROCESS_COMPLETED | GL ET | | `duty_tax_receipt` | DUTY_TAX_PAID | **Customer** | ### ET ↔ DJ handoff ``` DEPARTED_FROM_DJIBOUTI (import) → lead returns to GL Ethiopia + Operations DEPARTED_TO_DJIBOUTI (export) → lead moves to GL Djibouti ``` Ownership region is encoded per-milestone in the catalog; notifications fire on handoff (notification module pending). ### What the customer does in Phase 2 ``` watch the timeline (read-only) pay duty/tax → upload payment slip (only when GL advised it) pay freight → Pay button on the booking when batch-selected that's all — every other step is GL / Ops / Terminal ``` ### Where it lives (Phase 2) | Area | Files | |------|-------| | Milestone seed/advance | `api/.../contracts/clearance-milestone.service.ts`, `clearance-milestone.catalog.ts` | | GL actions (risk/duty/station/docs/incident) | `api/.../contracts/gl-operations.service.ts`, `dto/gl-operations.dto.ts`, `entities/clearance-incident.entity.ts` | | Endpoints | `api/.../contracts/contracts.controller.ts` (`bookings/:id/risk` · `/duty` · `/station-assign` · `/documents` · `/incidents` · `/duty-slip`) | | Backoffice UI | `backoffice/.../pages/contracts/BookingMilestonesPage.tsx`, `components/contracts/ClearanceMilestoneTimeline.tsx`, `components/contracts/gl-actions/*` | | Portal UI | `portal/.../bookings/BookingDetailPage/components/ShipmentTrackingCard.tsx` | ### Still out of scope (per design doc §18) Demurrage auto-calc & storage invoicing, finance AP closure, multimodal (sea/air + MTO/OBL/HBL), truck waybill PDF + POD signing. `STORAGE_INVOICE_RAISED` and `EXIT_NOTE_GENERATED` exist as **manual milestones** only — no fee engine yet. --- ## 5) Schedule (Operations) > Goal: put the booking on a train (or dispatch by road). Day-level pooling — the > customer picks a **day**, the batch engine assigns the actual **train** later. ``` 1. Customer requests operation pick a day that has an OPEN departure → OPERATION_REQUEST_PENDING 2. Operations review the request → one of: ACCEPT → FULLY_EXECUTED (enters the train batch pool) (road service instead → ROAD_DISPATCH_PENDING, section 6) REQUEST_CHANGES → OPERATION_CHANGES_REQUESTED (note required; customer resubmits) ADJUST_PRICE → OPERATION_PRICE_PENDING_CONFIRM (customer confirms new price → pool, or rejects → changes requested) 3. Batch engine (cron) groups bookings by (origin yard, destination yard, day): allocates to open train schedules by priority score → SELECTED_FOR_BATCH, assigns trainScheduleId, sets payment deadline 4. Payment (if not already paid) → PAID 5. IN_TRANSIT → COMPLETED ``` ### Wagon math ``` wagons per booking = sum over containers of (qty × wagonsPerUnit), rounded up ``` --- ## 6) Delivery / Last mile ``` IF road service: ACCEPT → ROAD_DISPATCH_PENDING (skips the train pool) billed by KM, dispatched by truck (First-Mile operations) IF first/last mile chosen at booking: pickup + delivery addresses captured; equipment return = WITH / WITHOUT last-mile statuses: PAYMENT_PENDING → READY_TO_TRANSIT → IN_TRANSIT → RECEIVED_TO_PORT ``` --- ## The whole thing on one page ``` ONBOARD nationality ─┬─ Ethiopian → TIN + Commercial License + National ID └─ Foreign → TIN + Investment License + National ID + Passport pick profiles (importer/exporter/FF) → upload license per profile → backoffice approves profile → profile ACTIVE CONTRACT wizard (setup → cargo+route → docs → review) → SUBMITTED → staff accept → approval chain → CONTRACT_READY → customer sign → counter-sign → SPLIT: customs ENABLED (import/export) → PATH B clearance customs DISABLED (import/export) → PATH A clearance DOMESTIC → no clearance, ready to book CLEARANCE (import/export only) loop: upload → approve/query → re-upload → finalize PATH A: Operations review → SELF_CLEARED → CUSTOMER books PATH B: GL review + GL output docs → READY_FOR_BOOKING → GL books BOOKING created by CUSTOMER (Path A / domestic) or GL (Path B) price → pay → (its own doc clearance if applicable) → ready to schedule GL PHASE 2 (customs/Path B, after booking) milestone timeline: wagon → pay → allocate → load → depart → handover → arrive → offload → T1 close → risk → release → complete GL actions: station routing · risk (G/Y/R) · duty advise · DO/RO/T1 upload · incident customer: watch read-only · upload duty slip · pay freight SCHEDULE request a day → Operations accept → batch engine → train assigned → pay → IN_TRANSIT → COMPLETED (road service → ROAD_DISPATCH_PENDING → truck) ``` --- ### Where this lives in the code (quick map) | Area | Key files | |------|-----------| | Onboarding | `portal/.../components/onboarding/OnboardingWizardDialog.tsx`, `api/.../companies/companies.service.ts`, `api/src/seed/file-upload-settings.seeder.ts` | | Contract | `portal/.../contracts/new-contract-form/`, `api/.../contracts/contract-transition.service.ts`, `entities/contract.entity.ts` | | Clearance | `api/.../contracts/contract-clearance.service.ts`, `contract-clearance.util.ts`, `portal/.../contracts/ContractClearancePanel.tsx` | | Booking | `portal/.../bookings/new-booking-form/`, `api/.../bookings/booking-transition.service.ts`, `contract-booking.service.ts` | | Schedule | `api/.../train-scheduling/booking-batch.service.ts`, `backoffice/.../operations/FirstMilePage.tsx` |