Files
edr-platform/apps/edr-freight-api/src/modules/audit/audit-endpoints.ts

681 lines
67 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Freight API — every state-changing endpoint (POST / PUT / PATCH / DELETE).
*
* Shape: "<METHOD> <path>": [title, method, entity]
*
* Keyed by method + path rather than path alone: 50 paths serve more than one
* method (PATCH and DELETE on /api/contracts/:id, for example), so a path-only
* key would collide and drop those endpoints.
*
* Paths include the global prefix `api` (see app.setGlobalPrefix in src/main.ts).
* Titles come from each route's @ApiOperation summary, falling back to a
* humanized handler name where a route has none.
*
* Excludes the AI Assist and Account entities.
* Generated from the controllers under src/ — 512 endpoints.
*/
/** [title, method, entity] for one auditable route. */
export type AuditEndpointMeta = readonly [title: string, method: string, entity: string];
export const AUDIT_ENDPOINTS: Readonly<Record<string, AuditEndpointMeta>> = {
// Approval Rule
"POST /api/approval-rules": ["Create an approval rule step", "POST", "Approval Rule"],
"PATCH /api/approval-rules/:id": ["Update an approval rule", "PATCH", "Approval Rule"],
"DELETE /api/approval-rules/:id": ["Soft-delete an approval rule", "DELETE", "Approval Rule"],
"POST /api/approval-rules/:id/move-order": ["Move an approval step up or down within its chain", "POST", "Approval Rule"],
"POST /api/approval-rules/reorder": ["Bulk reorder approval steps within a chain", "POST", "Approval Rule"],
// Booking
"POST /api/bookings": ["Create a new freight booking (DRAFT)", "POST", "Booking"],
"POST /api/bookings/:bookingId/allocate-containers": ["Allocate containers to vehicles", "POST", "Booking"],
"PATCH /api/bookings/:id": ["Update booking", "PATCH", "Booking"],
"DELETE /api/bookings/:id": ["Soft-delete DRAFT booking", "DELETE", "Booking"],
"POST /api/bookings/:id/cancel": ["Cancel booking", "POST", "Booking"],
"POST /api/bookings/:id/cancel-hold": ["Customer cancels an unpaid hold (SELECTED_FOR_BATCH → CANCELLED);", "POST", "Booking"],
"POST /api/bookings/:id/clearance/declaration": ["GL ET uploads customs declaration on booking (GENERAL customs)", "POST", "Booking"],
"POST /api/bookings/:id/clearance/delivery-order": ["Upload Booking Delivery Order", "POST", "Booking"],
"POST /api/bookings/:id/clearance/documents": ["Customer uploads clearance documents (fieldname = document key)", "POST", "Booking"],
"POST /api/bookings/:id/clearance/draft-declaration": ["GL ET sends a draft customs declaration (multi-file) with an estimated price for the customer to review", "POST", "Booking"],
"POST /api/bookings/:id/clearance/draft-declaration/accept": ["Customer accepts the draft customs declaration — unlocks the real customs declaration step for GL Ethiopia", "POST", "Booking"],
"POST /api/bookings/:id/clearance/draft-declaration/change": ["Customer requests a change to the draft customs declaration with a reason — GL Ethiopia sends a corrected draft (repeatable)", "POST", "Booking"],
"POST /api/bookings/:id/clearance/duty": ["GL ET sets duty/tax on booking with notice attachment", "POST", "Booking"],
"POST /api/bookings/:id/clearance/duty-slip": ["Customer uploads duty/tax payment slip on booking", "POST", "Booking"],
"POST /api/bookings/:id/clearance/export-release": ["Confirm Booking Export Release", "POST", "Booking"],
"POST /api/bookings/:id/clearance/finalize": ["GL finalizes clearance (requires 100% approved) → CLEARANCE_READY", "POST", "Booking"],
"POST /api/bookings/:id/clearance/finalize-pre-clearance": ["GL ET finalizes import pre-clearance on booking", "POST", "Booking"],
"POST /api/bookings/:id/clearance/output-documents": ["GL uploads customs output documents (IM4/EX3/…)", "POST", "Booking"],
"POST /api/bookings/:id/clearance/proceed": ["Customer requests operation with a schedule day", "POST", "Booking"],
"POST /api/bookings/:id/clearance/release-order": ["Upload Booking Release Order", "POST", "Booking"],
"POST /api/bookings/:id/clearance/review": ["GL reviews a clearance document (Approve | Query)", "POST", "Booking"],
"POST /api/bookings/:id/clearance/ro-amendment": ["Request Booking RO Amendment", "POST", "Booking"],
"POST /api/bookings/:id/clearance/transit-assignee/assign": ["GL Djibouti picks the transit officer from the roster — unblocks the customs declaration; calling again reassigns", "POST", "Booking"],
"POST /api/bookings/:id/clearance/transit-assignee/request": ["GL ET asks GL Djibouti to name the transit officer — required before the import customs declaration", "POST", "Booking"],
"POST /api/bookings/:id/clearance/transit-permit": ["Upload Booking Transit Permit", "POST", "Booking"],
"POST /api/bookings/:id/confirm-submit": ["Confirm submit after price change", "POST", "Booking"],
"POST /api/bookings/:id/consolidation": ["Request freight consolidation", "POST", "Booking"],
"DELETE /api/bookings/:id/consolidation": ["Remove consolidation pairing", "DELETE", "Booking"],
"POST /api/bookings/:id/contract/generate": ["Generate contract PDF from template", "POST", "Booking"],
"POST /api/bookings/:id/contract/sign": ["Apply digital signature (customer or staff)", "POST", "Booking"],
"POST /api/bookings/:id/customer-cancel": ["Customer cancels their own booking before payment — no cancellation fee", "POST", "Booking"],
"POST /api/bookings/:id/customer-truck-assignment": ["Customer assigns external truck and driver for terminal pickup", "POST", "Booking"],
"POST /api/bookings/:id/customer-trucks": ["Add a customer self-haul truck carrying 12 of the booking containers", "POST", "Booking"],
"PATCH /api/bookings/:id/customer-trucks/:assignmentId": ["Edit a not-yet-arrived customer truck (plate/driver/type + containers)", "PATCH", "Booking"],
"DELETE /api/bookings/:id/customer-trucks/:assignmentId": ["Remove a not-yet-arrived customer truck from a booking", "DELETE", "Booking"],
"POST /api/bookings/:id/customer-trucks/:assignmentId/depart": ["Register an import truck leaving: containers loaded + weighed gross (staff)", "POST", "Booking"],
"POST /api/bookings/:id/customer-trucks/:assignmentId/load": ["Truck_dispatch: load selected containers onto a truck (staff)", "POST", "Booking"],
"POST /api/bookings/:id/customer-trucks/bulk": ["Bulk add customer trucks from array payload (Excel parsed)", "POST", "Booking"],
"POST /api/bookings/:id/customer/sign": ["Customer digital signature (deprecated — use POST contract/sign)", "POST", "Booking"],
"POST /api/bookings/:id/documents": ["Upload documents for a booking (DRAFT only)", "POST", "Booking"],
"PATCH /api/bookings/:id/export-handover-mode": ["Export only: choose direct truck-to-train (no warehouse, no GRN) or warehouse first", "PATCH", "Booking"],
"POST /api/bookings/:id/generate-grn": ["Generate a GRN over the received containers (all received, or a subset) — one GRN per batch", "POST", "Booking"],
"POST /api/bookings/:id/generate-price": ["Generate price preview (DRAFT or CHANGES_REQUESTED)", "POST", "Booking"],
"POST /api/bookings/:id/government-expedite": ["Expedite government booking to PAID / ELIGIBLE for scheduling", "POST", "Booking"],
"POST /api/bookings/:id/marketing/approve": ["Staff contract signature and fully execute (use contract/sign STAFF preferred)", "POST", "Booking"],
"POST /api/bookings/:id/operation/review": ["Operations reviews an operation request: ACCEPT (→ batch pool),", "POST", "Booking"],
"POST /api/bookings/:id/operations/complete": ["Mark completed", "POST", "Booking"],
"POST /api/bookings/:id/operations/start-transit": ["Mark in transit", "POST", "Booking"],
"POST /api/bookings/:id/reject": ["Customer reject price estimate", "POST", "Booking"],
"POST /api/bookings/:id/staff/accept": ["Staff accept intake → set contract validity window + start approval chain", "POST", "Booking"],
"POST /api/bookings/:id/staff/reject": ["Staff final reject", "POST", "Booking"],
"POST /api/bookings/:id/staff/request-changes": ["Staff return booking for customer updates", "POST", "Booking"],
"POST /api/bookings/:id/submit": ["Customer submit booking", "POST", "Booking"],
"POST /api/bookings/:id/wagon-cancellations": ["Request a partial wagon cancellation on a PAID booking — opens the cancellation-fee invoice; wagons are released only once the fee settles", "POST", "Booking"],
"POST /api/bookings/:id/wagon-cancellations/preview": ["Preview the fee/credit of a partial wagon cancellation (no writes)", "POST", "Booking"],
"POST /api/bookings/wagon-cancellations/:cancellationId/rebook": ["Rebook a wagon-cancellation credit: pick a shipment day only — the new booking is created under the contract and marked PAID (freight already paid; contract must still be valid)", "POST", "Booking"],
"POST /api/bookings/wagon-cancellations/:cancellationId/withdraw": ["Withdraw a fee-pending wagon cancellation (owner, or staff with the void permission)", "POST", "Booking"],
"POST /api/bookings/consolidation-approvals/:approvalId/approve": ["Approve a shared wagon: both bookings leave the gate and continue to Operations together.", "POST", "Booking"],
"POST /api/bookings/consolidation-approvals/:approvalId/reject": ["Reject a shared wagon: both bookings go back to GL for changes with the reason.", "POST", "Booking"],
"POST /api/bookings/:id/paired-decision": ["Apply a staff decision (accept / cancel / operationAccept / requestChanges) to BOTH halves of a consolidated pair, all-or-nothing.", "POST", "Booking"],
// Cargo
"POST /api/cargoes": ["Create a new cargo", "POST", "Cargo"],
"PATCH /api/cargoes/:id": ["Update a cargo", "PATCH", "Cargo"],
"DELETE /api/cargoes/:id": ["Delete a cargo", "DELETE", "Cargo"],
"POST /api/cargoes/:id/deliver": ["Mark cargo as delivered", "POST", "Cargo"],
"POST /api/cargoes/:id/load": ["Load cargo into a container", "POST", "Cargo"],
"POST /api/cargoes/:id/unload": ["Unload cargo from container", "POST", "Cargo"],
// Cargo Type
"POST /api/cargo-types": ["Create a cargo type", "POST", "Cargo Type"],
"PATCH /api/cargo-types/:id": ["Update a cargo type", "PATCH", "Cargo Type"],
"DELETE /api/cargo-types/:id": ["Soft-delete a cargo type", "DELETE", "Cargo Type"],
"POST /api/cargo-types/:id/move-order": ["Move a cargo type up or down in display order", "POST", "Cargo Type"],
"POST /api/cargo-types/reorder": ["Bulk reorder cargo types by ID list", "POST", "Cargo Type"],
// Company
"POST /api/companies": ["Create a new company (customer, freight_forwarder, dj_freight_forwarder, transporter)", "POST", "Company"],
"POST /api/companies/:companyId/documents": ["Upload documents for a company (onboarding)", "POST", "Company"],
"POST /api/companies/:companyId/profiles": ["Add a profile (employee) to a company", "POST", "Company"],
"PATCH /api/companies/:id": ["Update a company", "PATCH", "Company"],
"DELETE /api/companies/:id": ["Soft-delete a company", "DELETE", "Company"],
"POST /api/companies/change-requests/:id/approve": ["Approve a pending profile change request (applies the changes)", "POST", "Company"],
"POST /api/companies/change-requests/:id/reject": ["Reject a pending profile change request with a note", "POST", "Company"],
"POST /api/companies/change-requests/:id/request-changes": ["Ask for specific changes on a pending request without rejecting it (row stays open, next edit appends to it)", "POST", "Company"],
"POST /api/companies/company-profile": ["Create a single operational profile for the current user's company. The role starts pending and does not become the active mode", "POST", "Company"],
"POST /api/companies/company-profiles": ["Add operational profile(s) (importer/exporter/forwarder) to the current user's company", "POST", "Company"],
"POST /api/companies/company-profiles/:profileId/license": ["Add business-license document(s) to a profile. For an approved company", "POST", "Company"],
"DELETE /api/companies/company-profiles/:profileId/license/:fileId": ["Remove a business-license file (staged for review on an approved company)", "DELETE", "Company"],
"POST /api/companies/company-profiles/:profileId/license/:fileId/replace": ["Replace a business-license file with a newly uploaded one (staged for", "POST", "Company"],
"POST /api/companies/company-profiles/:profileId/reapply": ["Resubmit a rejected operational role for approval (→ pending)", "POST", "Company"],
"PATCH /api/companies/company-profiles/:profileId/status": ["Update a company profile's approval status", "PATCH", "Company"],
"POST /api/companies/create": ["Create a company with its associated external profile (onboarding)", "POST", "Company"],
"POST /api/companies/documents/:fileId/request-change": ["Ask the customer to correct one uploaded document", "POST", "Company"],
"POST /api/companies/fetch-etrade-info": ["Fetch company info from eTrade by TIN", "POST", "Company"],
"POST /api/companies/identity/fayda/complete": ["Bind a completed Fayda verification to the company's owner or Power of Attorney", "POST", "Company"],
"PATCH /api/companies/onboarding-step": ["Persist the user's current onboarding wizard step", "PATCH", "Company"],
"POST /api/companies/onboarding/complete": ["Mark the current user's onboarding as complete", "POST", "Company"],
"POST /api/companies/onboarding/start": ["Begin onboarding: create a draft company + profile + role(s) so later steps can save incrementally", "POST", "Company"],
"POST /api/companies/poa-delegation": ["Upload the Power of Attorney delegation letter, replacing any existing one", "POST", "Company"],
"DELETE /api/companies/poa-delegation/:fileId": ["Remove the Power of Attorney delegation letter (staged for review on an approved company)", "DELETE", "Company"],
"PATCH /api/companies/profile": ["Update profile (flattened settings page)", "PATCH", "Company"],
"PATCH /api/companies/identity/poa-declared": ["Answer whether anyone holds power of attorney for this company — the question that decides whose identity is verified.", "PATCH", "Company"],
// Compliance
"POST /api/compliance": ["Create a compliance record", "POST", "Compliance"],
"PATCH /api/compliance/:id": ["Update a compliance record", "PATCH", "Compliance"],
"DELETE /api/compliance/:id": ["Soft-delete a compliance record", "DELETE", "Compliance"],
// Consignment
"POST /api/consignments": ["Create a new consignment", "POST", "Consignment"],
// Container
"POST /api/containers": ["Create a new container", "POST", "Container"],
"PATCH /api/containers/:id": ["Update a container", "PATCH", "Container"],
"DELETE /api/containers/:id": ["Delete a container", "DELETE", "Container"],
"POST /api/containers/:id/assign-wagon": ["Assign container to a wagon", "POST", "Container"],
"POST /api/containers/:id/unassign-wagon": ["Unassign container from wagon", "POST", "Container"],
// Container Type
"POST /api/container-types": ["Create a container type", "POST", "Container Type"],
"PATCH /api/container-types/:id": ["Update a container type", "PATCH", "Container Type"],
"DELETE /api/container-types/:id": ["Soft-delete a container type", "DELETE", "Container Type"],
"POST /api/container-types/:id/move-order": ["Move a container type up or down in display order", "POST", "Container Type"],
"POST /api/container-types/reorder": ["Bulk reorder container types by ID list", "POST", "Container Type"],
// Contract
"POST /api/contracts": ["Create a new contract (DRAFT) with routes + cargo scope", "POST", "Contract"],
"PATCH /api/contracts/:id": ["Update contract", "PATCH", "Contract"],
"DELETE /api/contracts/:id": ["Soft-delete DRAFT contract", "DELETE", "Contract"],
"POST /api/contracts/:id/approval-steps/:stepId/approve": ["Approve one approval step in sequence", "POST", "Contract"],
"POST /api/contracts/:id/approval-steps/:stepId/reject": ["Reject one approval step — to the customer (terminal → REJECTED) or, via returnToStepId, back to an earlier approver (chain re-runs from there)", "POST", "Contract"],
"POST /api/contracts/:id/booking-requests": ["Customer submits a shipment request on a GENERAL customs contract", "POST", "Contract"],
"POST /api/contracts/:id/bookings": ["Create a shipment booking under a contract — Path A (customer) or Path B (GL Ethiopia)", "POST", "Contract"],
"POST /api/contracts/:id/bookings/:bookingId/complete": ["Complete an initiated booking after Operations finalized its clearance — cargo + binding day, window and departure checks, pricing and invoicing", "POST", "Contract"],
"POST /api/contracts/:id/bookings/initiate": ["Initiate a bare booking instance under an import/export contract (ONE_TIME or GENERAL) — no cargo, no date; enters per-booking clearance (AWAITING_DOCUMENTS). ONE_TIME customs instances are opened by the customer (or GL); GENERAL customs comes from a shipment request", "POST", "Contract"],
"POST /api/contracts/:id/cancel": ["Customer cancels their own contract (blocked while a booking is live)", "POST", "Contract"],
"POST /api/contracts/:id/clearance/declaration": ["GL ET uploads customs declaration documents (multi-file)", "POST", "Contract"],
"POST /api/contracts/:id/clearance/delivery-order": ["GL DJ uploads Delivery Order (import) with vessel arrival + DO collected dates", "POST", "Contract"],
"POST /api/contracts/:id/clearance/documents": ["Customer uploads clearance documents (fieldname = document key)", "POST", "Contract"],
"POST /api/contracts/:id/clearance/documents/:fileKey/replace": ["GL replaces a clearance document in place (reason required) — the previous version is kept in the file history and the new one needs approving", "POST", "Contract"],
"POST /api/contracts/:id/clearance/duty": ["GL ET sets duty/tax requirement and advises amount with notice attachment", "POST", "Contract"],
"POST /api/contracts/:id/clearance/duty-slip": ["Customer uploads duty/tax payment slip on contract", "POST", "Contract"],
"POST /api/contracts/:id/clearance/duty/dispute": ["Customer disputes the advised duty/tax with a reason — reopens the step so GL Ethiopia can re-advise (repeatable)", "POST", "Contract"],
"POST /api/contracts/:id/clearance/export-release": ["GL ET confirms export release after declaration", "POST", "Contract"],
"POST /api/contracts/:id/clearance/finalize": ["GL ET finalizes clearance → CLEARANCE_READY_FOR_BOOKING (legacy)", "POST", "Contract"],
"POST /api/contracts/:id/clearance/finalize-export-clearance": ["GL ET finalizes export clearance after post-booking transit permit upload", "POST", "Contract"],
"POST /api/contracts/:id/clearance/finalize-pre-clearance": ["GL ET finalizes import pre-clearance — unlocks Djibouti DO upload", "POST", "Contract"],
"POST /api/contracts/:id/clearance/ops-finalize": ["Operations finalizes self-clearance → customer may create the booking", "POST", "Contract"],
"POST /api/contracts/:id/clearance/ops-review": ["Operations reviews a customer self-clearance document (Approve | Query)", "POST", "Contract"],
"POST /api/contracts/:id/clearance/output-documents": ["GL uploads customs output documents (IM4/EX3/…) pre-booking", "POST", "Contract"],
"POST /api/contracts/:id/clearance/release-order": ["GL DJ uploads Release Order + vessel departure date (export)", "POST", "Contract"],
"POST /api/contracts/:id/clearance/review": ["GL ET reviews a clearance document (Approve | Query)", "POST", "Contract"],
"POST /api/contracts/:id/clearance/ro-amendment": ["GL DJ requests port amendment when RO vessel window is too short", "POST", "Contract"],
"POST /api/contracts/:id/clearance/transit-assignee/assign": ["GL Djibouti picks the transit officer from the roster — unblocks the customs declaration; calling again reassigns", "POST", "Contract"],
"POST /api/contracts/:id/clearance/transit-assignee/request": ["GL ET asks GL Djibouti to name the transit officer — required before the customs declaration", "POST", "Contract"],
"POST /api/contracts/:id/clearance/transit-permit": ["GL ET uploads import transit permit documents (multi-file)", "POST", "Contract"],
"POST /api/contracts/:id/confirm-submit": ["Confirm submit after a price change", "POST", "Contract"],
"POST /api/contracts/:id/contract/generate": ["Generate contract document → CONTRACT_READY", "POST", "Contract"],
"POST /api/contracts/:id/contract/send-signing-otp": ["Send the sudo-mode signing OTP to the contract company's registered phone (server picks the number)", "POST", "Contract"],
"POST /api/contracts/:id/contract/sign": ["Apply digital signature (customer or staff/director/ceo)", "POST", "Contract"],
"PUT /api/contracts/:id/document/articles": ["Edit this contract\\'s document articles only (per-contract; never touches the six shared templates)", "PUT", "Contract"],
"POST /api/contracts/:id/documents": ["Upload intake documents for a contract (DRAFT only)", "POST", "Contract"],
"POST /api/contracts/:id/generate-price": ["Generate unit-rate breakdown (no totals at contract phase)", "POST", "Contract"],
"POST /api/contracts/:id/milestones/:code/complete": ["GL marks a pre-booking (contract) milestone complete", "POST", "Contract"],
"POST /api/contracts/:id/renew": ["Create a renewal draft linked via renewalOfId", "POST", "Contract"],
"POST /api/contracts/:id/resume": ["Staff lift a suspension — contract returns to its prior status", "POST", "Contract"],
"POST /api/contracts/:id/staff/accept": ["Staff accept → set validity window + start approval chain", "POST", "Contract"],
"POST /api/contracts/:id/staff/reject": ["Staff reject contract", "POST", "Contract"],
"POST /api/contracts/:id/staff/request-changes": ["Staff return contract for customer updates", "POST", "Contract"],
"POST /api/contracts/:id/submit": ["Customer submit contract (freezes contract_rate_snapshots)", "POST", "Contract"],
"POST /api/contracts/:id/suspend": ["Staff freeze a signed contract (reversible, any post-signature step)", "POST", "Contract"],
"POST /api/contracts/:id/validate-shipment": ["Pre-create validation + authoritative price preview: full booking price breakdown (rail, first/last mile, surcharges), overweight lines and 20ft weight-pairing errors for a shipment payload (no booking created)", "POST", "Contract"],
"POST /api/contracts/booking-requests/:reqId/accept": ["GL marks a shipment request accepted + links the created booking", "POST", "Contract"],
"POST /api/contracts/booking-requests/:reqId/cancel": ["Customer cancels their own pending shipment request", "POST", "Contract"],
"POST /api/contracts/booking-requests/:reqId/reject": ["GL rejects a shipment request", "POST", "Contract"],
"POST /api/contracts/bookings/:bookingId/documents": ["GL uploads post-booking operational documents (DO/RO/T1/…)", "POST", "Contract"],
"POST /api/contracts/bookings/:bookingId/duty": ["GL ET advises duty & tax amount + declaration serial", "POST", "Contract"],
"POST /api/contracts/bookings/:bookingId/duty-slip": ["Customer uploads the duty/tax payment slip", "POST", "Contract"],
"POST /api/contracts/bookings/:bookingId/final-invoice": ["GL DJ raises the post-offload final invoice (amount + invoice document)", "POST", "Contract"],
"POST /api/contracts/bookings/:bookingId/final-invoice-slip": ["Customer attaches the payment slip for the final invoice", "POST", "Contract"],
"POST /api/contracts/bookings/:bookingId/final-invoice/approve": ["Customer approves the drafted final invoice — unlocks the payment slip", "POST", "Contract"],
"POST /api/contracts/bookings/:bookingId/final-invoice/confirm": ["GL (ET or DJ) confirms the payment slip — settles the final invoice", "POST", "Contract"],
"POST /api/contracts/bookings/:bookingId/incidents": ["GL DJ logs a cargo exception with photo evidence", "POST", "Contract"],
"POST /api/contracts/bookings/:bookingId/milestones/:code/complete": ["GL / Ops / Terminal marks a post-booking milestone complete", "POST", "Contract"],
"POST /api/contracts/bookings/:bookingId/risk": ["GL ET assigns a customs risk level (GREEN/YELLOW/RED)", "POST", "Contract"],
"POST /api/contracts/bookings/:bookingId/second-duty": ["GL ET advises (or skips) the post-arrival additional duty/tax round (import)", "POST", "Contract"],
"POST /api/contracts/bookings/:bookingId/second-duty-slip": ["Customer attaches the additional duty/tax payment slip", "POST", "Contract"],
"POST /api/contracts/bookings/:bookingId/station-assign": ["GL station manager routes the shipment + binds staff", "POST", "Contract"],
"POST /api/contracts/bookings/:bookingId/t1-close": ["Close (accept) the T1 set — GL ET after arrival (import) / GL DJ after gate pass (export)", "POST", "Contract"],
"POST /api/contracts/bookings/:bookingId/t1-documents": ["GL Djibouti uploads T1 transit documents (multi-file) after wagon allocation; locked once the train departs", "POST", "Contract"],
"POST /api/contracts/bookings/:bookingId/transport-document": ["GL ET uploads export transit permit documents (multi-file)", "POST", "Contract"],
"POST /api/gl-exchange/:entityId": ["Share a document with the other GL desk", "POST", "Contract"],
"PATCH /api/gl-exchange/documents/:documentId": ["Uploader edits a shared document (title, visibility, file)", "PATCH", "Contract"],
"DELETE /api/gl-exchange/documents/:documentId": ["Uploader removes a shared document", "DELETE", "Contract"],
"POST /api/contracts/:id/bookings/:bookingId/complete-consolidated": ["Complete this booking and its chosen shared-wagon partner together (all-or-nothing). Each booking is priced and invoiced separately — only the wagon is shared.", "POST", "Contract"],
// Contract Template
"POST /api/contract-templates": ["Create a bulk contract template for a (cargo type, customs option) pair", "POST", "Contract Template"],
"PATCH /api/contract-templates/:code": ["Update template metadata (name, title, recitals, active flag)", "PATCH", "Contract Template"],
"DELETE /api/contract-templates/:code": ["Delete a staff-created bulk template (system templates refuse)", "DELETE", "Contract Template"],
"POST /api/contract-templates/:code/articles": ["Add an article to the template", "POST", "Contract Template"],
"PUT /api/contract-templates/:code/articles": ["Replace the full ordered article list (used for reorder)", "PUT", "Contract Template"],
"PATCH /api/contract-templates/:code/articles/:articleId": ["Update an article's title or body", "PATCH", "Contract Template"],
"DELETE /api/contract-templates/:code/articles/:articleId": ["Remove an article from the template", "DELETE", "Contract Template"],
"POST /api/contract-templates/:code/preview": ["Render an HTML preview of the template against mock contract data", "POST", "Contract Template"],
// Driver
"POST /api/drivers": ["Create a new driver", "POST", "Driver"],
"PATCH /api/drivers/:id": ["Update a driver", "PATCH", "Driver"],
"DELETE /api/drivers/:id": ["Delete a driver", "DELETE", "Driver"],
"POST /api/drivers/:id/documents": ["Upload driver documents (code driver_docs)", "POST", "Driver"],
"DELETE /api/drivers/:id/documents/:fileId": ["Delete a driver document", "DELETE", "Driver"],
// Dropdown Setting
"POST /api/dropdown-settings": ["Create a new dropdown setting", "POST", "Dropdown Setting"],
"PATCH /api/dropdown-settings/:id": ["Update a dropdown setting's metadata", "PATCH", "Dropdown Setting"],
"DELETE /api/dropdown-settings/:id": ["Soft-delete a dropdown setting", "DELETE", "Dropdown Setting"],
"POST /api/dropdown-settings/:id/options": ["Append a single option to a setting", "POST", "Dropdown Setting"],
"PUT /api/dropdown-settings/:id/options": ["Replace the full option list for a setting", "PUT", "Dropdown Setting"],
"PATCH /api/dropdown-settings/options/:optionId": ["Update a single option", "PATCH", "Dropdown Setting"],
"DELETE /api/dropdown-settings/options/:optionId": ["Soft-delete a single option", "DELETE", "Dropdown Setting"],
// EIMS Invoice
"POST /api/invoices/:id/eims/register": ["Register the invoice with MoR EIMS. Idempotent — an invoice that already has an IRN is returned unchanged", "POST", "EIMS Invoice"],
"POST /api/invoices/:id/eims/resolve": ["Resolve an unacknowledged submission: record the IRN confirmed with MoR, or discard it. Clears the system-wide block", "POST", "EIMS Invoice"],
"POST /api/invoices/:id/eims/verify": ["Verify the invoice's stored IRN against EIMS", "POST", "EIMS Invoice"],
"POST /api/invoices/:id/eims/cancel": ["Cancel the invoice", "POST", "EIMS Invoice"],
"POST /api/invoices/:id/eims/receipt/sales": ["Register a sales receipt with MoR EIMS against a registered invoice", "POST", "EIMS Invoice"],
"POST /api/invoices/:id/eims/receipt/withholding": ["Register a withholding receipt with MoR EIMS against a registered invoice", "POST", "EIMS Invoice"],
// Exchange Setting
"PATCH /api/exchange-settings": ["Set the USD→ETB fallback by hand (used only while CBE is unreachable)", "PATCH", "Exchange Setting"],
// Facility
"POST /api/facilities": ["Create a new facility", "POST", "Facility"],
"PATCH /api/facilities/:id": ["Update a facility", "PATCH", "Facility"],
"DELETE /api/facilities/:id": ["Delete a facility (soft delete)", "DELETE", "Facility"],
// Fayda Verification
"POST /api/fayda/verification/start": ["Start a VeriFayda 2.0 verification session", "POST", "Fayda Verification"],
// File Upload Setting
"POST /api/file-upload-settings": ["Create a new file upload setting", "POST", "File Upload Setting"],
"PATCH /api/file-upload-settings/:id": ["Update a file upload setting's metadata", "PATCH", "File Upload Setting"],
"DELETE /api/file-upload-settings/:id": ["Soft-delete a file upload setting", "DELETE", "File Upload Setting"],
"POST /api/file-upload-settings/:id/fields": ["Append a single field to a setting", "POST", "File Upload Setting"],
"PUT /api/file-upload-settings/:id/fields": ["Replace the full field list for a setting", "PUT", "File Upload Setting"],
"PATCH /api/file-upload-settings/fields/:fieldId": ["Update a single field", "PATCH", "File Upload Setting"],
"DELETE /api/file-upload-settings/fields/:fieldId": ["Soft-delete a single field", "DELETE", "File Upload Setting"],
// First Mile
"POST /api/first-mile": ["Create a first-mile leg", "POST", "First Mile"],
"PATCH /api/first-mile/:id": ["Update a first-mile leg", "PATCH", "First Mile"],
"DELETE /api/first-mile/:id": ["Soft-delete a first-mile leg", "DELETE", "First Mile"],
"POST /api/first-mile/:id/distances": ["Set per-vehicle actual distances (does not generate an invoice)", "POST", "First Mile"],
"POST /api/first-mile/:id/invoice": ["Generate the first-mile delivery-fee invoice", "POST", "First Mile"],
"POST /api/first-mile/:id/vehicles": ["Set the vehicles assigned to a first-mile pickup (multi-truck)", "POST", "First Mile"],
"POST /api/first-mile/accept/:reference": ["Accept a paid booking and create a first-mile leg", "POST", "First Mile"],
// Fuel
"POST /api/fuel/purchases": ["Record fuel purchase", "POST", "Fuel"],
// GPS Tracking
"POST /api/gps/devices": ["Register a GPS tracker", "POST", "GPS Tracking"],
"PATCH /api/gps/devices/:id": ["Update a GPS tracker (name / assigned vehicle)", "PATCH", "GPS Tracking"],
"DELETE /api/gps/devices/:id": ["Delete a GPS tracker", "DELETE", "GPS Tracking"],
// Import Operation
"POST /api/import-operations/customs/:bookingId/declaration": ["Batch 12: record declaration serial number", "POST", "Import Operation"],
"POST /api/import-operations/customs/:bookingId/documents": ["Batch 12: upload IM4/IM5/T1/permit/payment-slip documents", "POST", "Import Operation"],
"POST /api/import-operations/customs/:bookingId/duties-taxes-paid": ["Batch 12: mark duties and taxes paid", "POST", "Import Operation"],
"POST /api/import-operations/customs/:bookingId/notify-duties-taxes": ["Batch 12: notify duties and taxes", "POST", "Import Operation"],
"POST /api/import-operations/customs/:bookingId/release-permitted": ["Batch 12: mark import release permitted", "POST", "Import Operation"],
"POST /api/import-operations/customs/:bookingId/risk": ["Batch 12: assign customs risk", "POST", "Import Operation"],
"POST /api/import-operations/djibouti-incidents": ["Batch 8: report a Djibouti import incident / exception", "POST", "Import Operation"],
"POST /api/import-operations/empty-container-returns": ["Batch 16: create an empty container return record", "POST", "Import Operation"],
"POST /api/import-operations/empty-container-returns/:id/status": ["Batch 16: advance empty container return workflow", "POST", "Import Operation"],
"POST /api/import-operations/empty-container-returns/load-on-train": ["Load returned empties onto an export train (1×40ft or 2×20ft per wagon)", "POST", "Import Operation"],
// Incident
"POST /api/incidents": ["Report an incident", "POST", "Incident"],
"PATCH /api/incidents/:id": ["Update an incident", "PATCH", "Incident"],
"DELETE /api/incidents/:id": ["Delete an incident", "DELETE", "Incident"],
// Interchange Document
"PATCH /api/interchange-documents/:id/acknowledge": ["Acknowledge an interchange document", "PATCH", "Interchange Document"],
"PATCH /api/interchange-documents/:id/dispute": ["Dispute an interchange document", "PATCH", "Interchange Document"],
"POST /api/interchange-documents/generate-from-schedule": ["Generate interchange document from a train schedule handover", "POST", "Interchange Document"],
// Last Mile
"POST /api/last-mile": ["Create a last-mile leg", "POST", "Last Mile"],
"PATCH /api/last-mile/:id": ["Update a last-mile leg", "PATCH", "Last Mile"],
"DELETE /api/last-mile/:id": ["Soft-delete a last-mile leg", "DELETE", "Last Mile"],
"POST /api/last-mile/:id/detention-times": ["Set each truck\\'s own detention window (arrived at destination / returned)", "POST", "Last Mile"],
"POST /api/last-mile/:id/distances": ["Set per-vehicle actual distances (does not generate an invoice)", "POST", "Last Mile"],
"POST /api/last-mile/:id/invoice": ["Generate the delivery-fee invoice for a last-mile leg", "POST", "Last Mile"],
"POST /api/last-mile/:id/proof-of-delivery": ["Record proof of delivery (signature + photos) and complete the leg", "POST", "Last Mile"],
"POST /api/last-mile/:id/vehicles": ["Set the vehicles assigned to a last-mile delivery (multi-truck)", "POST", "Last Mile"],
"POST /api/last-mile/:id/warehouse-gate-times": ["Set each truck\\'s warehouse gate arrival/departure times", "POST", "Last Mile"],
"POST /api/last-mile/accept/:reference": ["Accept a paid booking and create a last-mile leg", "POST", "Last Mile"],
// Last Mile Request
"POST /api/last-mile-requests/:id/approve": ["Truck & Machinery chief approves the request — the advance defaults to the live last-mile rate; LM contract becomes signable and the advance invoice follows the customer signature", "POST", "Last Mile Request"],
"POST /api/last-mile-requests/:id/contract/sign": ["Customer agrees and signs the LM contract — then the advance invoice is issued", "POST", "Last Mile Request"],
"POST /api/last-mile-requests/:id/reject": ["Truck & Machinery chief rejects the request with a reason", "POST", "Last Mile Request"],
"POST /api/last-mile-requests/:id/submit": ["Customer confirms which containers go via EDR last-mile", "POST", "Last Mile Request"],
// Locomotive
"POST /api/locomotives": ["Create a locomotive", "POST", "Locomotive"],
"PATCH /api/locomotives/:id": ["Update a locomotive", "PATCH", "Locomotive"],
"POST /api/locomotives/:id/decommission": ["Decommission a locomotive", "POST", "Locomotive"],
"DELETE /api/locomotives/:id/permanent": ["Permanently delete a locomotive (irreversible; refused if any train references it)", "DELETE", "Locomotive"],
// Logo Setting
"PUT /api/logo-settings": ["Replace the company logo", "PUT", "Logo Setting"],
"DELETE /api/logo-settings": ["Clear the company logo (documents fall back to their text mark)", "DELETE", "Logo Setting"],
// Maintenance
"POST /api/maintenance/costs": ["Record maintenance cost", "POST", "Maintenance"],
"POST /api/maintenance/intervals": ["Define/adjust a service interval (e.g. oil change every 10,000 km)", "POST", "Maintenance"],
"DELETE /api/maintenance/intervals/:id": ["Deactivate a service interval (stops auto-scheduling)", "DELETE", "Maintenance"],
"POST /api/maintenance/parts": ["Create part", "POST", "Maintenance"],
"PATCH /api/maintenance/parts/:id": ["Update part", "PATCH", "Maintenance"],
"DELETE /api/maintenance/parts/:id": ["Delete part", "DELETE", "Maintenance"],
"POST /api/maintenance/schedules": ["Schedule maintenance", "POST", "Maintenance"],
"PATCH /api/maintenance/schedules/:id": ["Update maintenance schedule", "PATCH", "Maintenance"],
"POST /api/maintenance/warranties": ["Create warranty", "POST", "Maintenance"],
"DELETE /api/maintenance/warranties/:id": ["Delete warranty", "DELETE", "Maintenance"],
"POST /api/maintenance/work-orders": ["Create work order", "POST", "Maintenance"],
"PATCH /api/maintenance/work-orders/:id": ["Update work order", "PATCH", "Maintenance"],
"DELETE /api/maintenance/work-orders/:id": ["Delete work order", "DELETE", "Maintenance"],
// Notification Inbox
"PATCH /api/notifications/:id/read": ["Mark one of my notifications as read", "PATCH", "Notification Inbox"],
"POST /api/notifications/read-all": ["Mark all my notifications as read", "POST", "Notification Inbox"],
// Organization User
"PUT /api/backoffice/organizations/:orgId/employee-users/:userId/roles": ["Replace org-scoped roles assigned to an employee user", "PUT", "Organization User"],
"POST /api/backoffice/organizations/:orgId/users": ["Create an organization user without assigning positions", "POST", "Organization User"],
// OTP
"POST /api/otp/send": ["Send OTP", "POST", "OTP"],
"POST /api/otp/verify": ["Verify OTP", "POST", "OTP"],
// Password Reset
"POST /api/auth/forgot-password/request": ["Send a password-reset code to the account's email AND phone", "POST", "Password Reset"],
"POST /api/auth/forgot-password/resolve-link": ["Validate a staff-issued reset link and return its set-password ticket", "POST", "Password Reset"],
"POST /api/auth/forgot-password/verify": ["Exchange a valid reset code for a single-use set-password ticket", "POST", "Password Reset"],
"POST /api/backoffice/customers/:companyId/reset-password": ["Send a password-reset link to a customer's primary contact", "POST", "Password Reset"],
// Payment
"POST /api/billing/invoices/:id/confirm-offline": ["Finance confirms a USD invoice paid by bank transfer — slip file required, settles the full balance", "POST", "Payment"],
"POST /api/billing/my-invoices/:id/confirm": ["Confirm an OTP-debit payment (CAC Bank) for one of the customer's invoices", "POST", "Payment"],
"POST /api/billing/my-invoices/:id/pay": ["Initiate payment for one of the customer's invoices", "POST", "Payment"],
"POST /api/internal/payments/bill-query": ["Live still-payable check + payer name for a CBE bill (called while CBE is on the line)", "POST", "Payment"],
"POST /api/internal/payments/mark-paid": ["Apply a payment.succeeded / payment.failed event from the payment service (idempotent)", "POST", "Payment"],
"POST /api/payments/initiate": ["Initiate payment for an invoice", "POST", "Payment"],
"POST /api/payments/redirect-success/:bookingId": ["Success-redirect ack: mark payment processing + invoice PAYMENT_PROCESSING (webhook remains source of truth)", "POST", "Payment"],
"POST /api/billing/invoices/:id/memo": ["Issue a credit or debit memo against a registered invoice (MoR DEB/CRE). Filing-equivalent — the auto-submit sweep picks it up like any other issued invoice.", "POST", "Payment"],
// Payment Setting
"PATCH /api/payment-settings/manual": ["Enable or disable manual invoice settlement for ETB and/or USD", "PATCH", "Payment Setting"],
// Priority Config
"POST /api/priority-configs": ["Create a priority config", "POST", "Priority Config"],
"PATCH /api/priority-configs/:id": ["Update a priority config", "PATCH", "Priority Config"],
"DELETE /api/priority-configs/:id": ["Soft-delete a priority config", "DELETE", "Priority Config"],
"POST /api/priority-configs/:id/move-order": ["Move a priority config up or down in display order", "POST", "Priority Config"],
"POST /api/priority-configs/reorder": ["Bulk reorder priority configs by ID list", "POST", "Priority Config"],
// Priority Rule Change Request
"POST /api/priority-rule-change-requests": ["Submit a priority-rule change for approval", "POST", "Priority Rule Change Request"],
"POST /api/priority-rule-change-requests/:id/approve": ["Approve and apply a pending change", "POST", "Priority Rule Change Request"],
"POST /api/priority-rule-change-requests/:id/reject": ["Reject a pending change", "POST", "Priority Rule Change Request"],
// Procurement
"POST /api/procurement/acquisitions": ["Create an asset acquisition", "POST", "Procurement"],
"PATCH /api/procurement/acquisitions/:id": ["Update an asset acquisition", "PATCH", "Procurement"],
"DELETE /api/procurement/acquisitions/:id": ["Delete an asset acquisition", "DELETE", "Procurement"],
"POST /api/procurement/disposals": ["Create an asset disposal", "POST", "Procurement"],
"DELETE /api/procurement/disposals/:id": ["Delete an asset disposal", "DELETE", "Procurement"],
"POST /api/procurement/vendors": ["Create a vendor", "POST", "Procurement"],
"PATCH /api/procurement/vendors/:id": ["Update a vendor", "PATCH", "Procurement"],
"DELETE /api/procurement/vendors/:id": ["Delete a vendor", "DELETE", "Procurement"],
// Rate
"POST /api/rates": ["Create a rate (DRAFT)", "POST", "Rate"],
"PATCH /api/rates/:id": ["Update a DRAFT rate", "PATCH", "Rate"],
"DELETE /api/rates/:id": ["Soft-delete a rate", "DELETE", "Rate"],
"POST /api/rates/:id/approve": ["CEO approves a rate", "POST", "Rate"],
"POST /api/rates/:id/submit": ["Submit rate for CEO approval", "POST", "Rate"],
// Rate Change Request
"POST /api/rate-change-requests": ["Propose a change to a LIVE rate", "POST", "Rate Change Request"],
"POST /api/rate-change-requests/:id/approve": ["Approve a rate change and put it into effect", "POST", "Rate Change Request"],
"POST /api/rate-change-requests/:id/reject": ["Reject a rate change — the rate keeps its current value", "POST", "Rate Change Request"],
// Route
"POST /api/routes": ["Create route", "POST", "Route"],
"PATCH /api/routes/:id": ["Update route", "PATCH", "Route"],
"DELETE /api/routes/:id": ["Deactivate route", "DELETE", "Route"],
"DELETE /api/routes/:id/permanent": ["Permanently delete a route (irreversible; refused while any train schedule references it)", "DELETE", "Route"],
// Schedule
// NOTE: duplicate route — also declared in modules/scheduling-reschedule/scheduling-reschedule.controller.ts:52.
// Two controllers register this same path; Nest serves whichever module loads first.
"POST /api/train-scheduling/schedules/:id/maintenance": ["Reschedule train for maintenance (new departure + rebalance)", "POST", "Schedule"],
"POST /api/train-scheduling/schedules/:id/reschedule/execute": ["Execute a confirmed reschedule plan", "POST", "Schedule"],
"POST /api/train-scheduling/schedules/:id/reschedule/preview": ["Preview reschedule / government preempt plan", "POST", "Schedule"],
// Service Type
"POST /api/service-types": ["Create a service type", "POST", "Service Type"],
"PATCH /api/service-types/:id": ["Update a service type", "PATCH", "Service Type"],
"DELETE /api/service-types/:id": ["Soft-delete a service type", "DELETE", "Service Type"],
"POST /api/service-types/:id/move-order": ["Move a service type up or down in display order", "POST", "Service Type"],
"POST /api/service-types/reorder": ["Bulk reorder service types by ID list", "POST", "Service Type"],
// Shipping Line (rule-engine lookup list — a code/label bookings reference,
// not an account)
"POST /api/shipping-lines": ["Create a shipping line", "POST", "Shipping Line"],
"PATCH /api/shipping-lines/:id": ["Update a shipping line", "PATCH", "Shipping Line"],
"DELETE /api/shipping-lines/:id": ["Soft-delete a shipping line", "DELETE", "Shipping Line"],
// Shipping Line Booking
"POST /api/shipping-line-bookings/initiate": ["Initiate a bare booking (no contract). Starts at AWAITING_DOCUMENTS so the shipping line can upload its documents for Operations to approve.", "POST", "Shipping Line Booking"],
"POST /api/shipping-line-bookings/:id/cancel": ["Cancel one of the signed-in shipping line's own bookings. Allowed only before the booking is priced.", "POST", "Shipping Line Booking"],
"POST /api/shipping-line-bookings/:id/price-preview": ["Authoritative price quote for the completion payload — same compute as /complete, saved as the booking's breakdown + rate snapshots (refreshed on every re-preview). Persists nothing else.", "POST", "Shipping Line Booking"],
"POST /api/shipping-line-bookings/:id/complete": ["Complete an approved (CLEARANCE_READY) booking: cargo + binding shipment day.", "POST", "Shipping Line Booking"],
// Shipping Line Credit
"POST /api/shipping-line-credits/invoice": ["Bill a batch of unbilled credits as one invoice. All credits must belong to the same shipping line.", "POST", "Shipping Line Credit"],
"POST /api/shipping-line-credits/:creditId/cancel": ["Write off an unbilled credit. Once billed, cancel the invoice instead.", "POST", "Shipping Line Credit"],
"POST /api/shipping-line-credits/invoices/:invoiceId/mark-paid-request": ["Request recording a full offline payment against a credit invoice (awaits chief approval).", "POST", "Shipping Line Credit"],
"POST /api/shipping-line-credits/invoices/:invoiceId/cancel-request": ["Request voiding a credit invoice — its credits return to the unbilled pool (awaits chief approval).", "POST", "Shipping Line Credit"],
"POST /api/shipping-line-credits/invoice-actions/:approvalId/approve": ["Approve a pending invoice request — executes the offline settlement or the cancellation.", "POST", "Shipping Line Credit"],
"POST /api/shipping-line-credits/invoice-actions/:approvalId/reject": ["Reject a pending invoice request — nothing is changed.", "POST", "Shipping Line Credit"],
// Shipping Line Company (carrier with a portal login, registered by staff)
"POST /api/shipping-line-companies": ["Register a shipping line company and send its activation link", "POST", "Shipping Line Company"],
"POST /api/shipping-line-companies/:id/resend-activation": ["Resend a shipping line company's activation link", "POST", "Shipping Line Company"],
// Signature
"PUT /api/me/signature": ["Create or update the reusable saved signature", "PUT", "Signature"],
// Stamp Setting
"PUT /api/stamp-settings": ["Replace the company stamp", "PUT", "Stamp Setting"],
"DELETE /api/stamp-settings": ["Clear the company stamp (invoices fall back to the plain seal)", "DELETE", "Stamp Setting"],
// Support Chat
"POST /api/support/agent/conversations": ["Start chatting with a company (returns the thread if one exists)", "POST", "Support Chat"],
"POST /api/support/agent/conversations/:id/messages": ["Reply as an agent, optionally with attachments", "POST", "Support Chat"],
"POST /api/support/agent/conversations/:id/read": ["Mark a thread read (agent side)", "POST", "Support Chat"],
"POST /api/support/conversation/messages": ["Send a message as the customer (optionally with attachments), opening the thread if needed", "POST", "Support Chat"],
"POST /api/support/conversation/read": ["Mark my company's thread read (customer side)", "POST", "Support Chat"],
// Support Content
"PATCH /api/support-content/documents/:slug": ["Replace a document's payload, recording a new version", "PATCH", "Support Content"],
"POST /api/support-content/documents/:slug/versions/:version/restore": ["Restore a version — re-saves it as a new version, never destructive", "POST", "Support Content"],
"POST /api/support-content/media": ["Upload an image or video for a help section", "POST", "Support Content"],
// Train
"POST /api/trains": ["Register a new train", "POST", "Train"],
"PATCH /api/trains/:id": ["Update a train", "PATCH", "Train"],
"DELETE /api/trains/:id": ["Delete a train", "DELETE", "Train"],
// Train Build
"POST /api/train-builder": ["Build a train: code + yard + 2+ locomotives (+ optional wagons)", "POST", "Train Build"],
"DELETE /api/train-builder/:id": ["Disband the train (release wagons and locomotives)", "DELETE", "Train Build"],
"POST /api/train-builder/:id/activate": ["Reactivate a deactivated train back to AVAILABLE", "POST", "Train Build"],
"POST /api/train-builder/:id/deactivate": ["Deactivate the train (park it) — only allowed with no active schedule", "POST", "Train Build"],
"PATCH /api/train-builder/:id/details": ["Edit the train's name and fixed import/export run numbers", "PATCH", "Train Build"],
"PUT /api/train-builder/:id/locomotives": ["Replace the locomotive set (minimum 1, same yard)", "PUT", "Train Build"],
"POST /api/train-builder/:id/reorder-wagons": ["Persist a drag-reorder of the full consist", "POST", "Train Build"],
"POST /api/train-builder/:id/wagons": ["Append AVAILABLE wagons from the train's yard to the consist", "POST", "Train Build"],
"DELETE /api/train-builder/:id/wagons/:wagonId": ["Detach one wagon from the consist", "DELETE", "Train Build"],
"POST /api/train-builder/:id/wagons/:wagonId/maintenance": ["Detach one wagon and move it to MAINTENANCE status", "POST", "Train Build"],
"PATCH /api/train-builder/:id/yard": ["Relocate the train — its locomotives and wagons move to the new yard with it", "PATCH", "Train Build"],
// Train Schedule
"POST /api/train-scheduling/bookings/:bookingId/allocate": ["Staff: place a paid booking onto a fitting train (notifies customer on date change)", "POST", "Train Schedule"],
"POST /api/train-scheduling/bookings/:bookingId/expire": ["Staff: expire a reservation and free its capacity", "POST", "Train Schedule"],
"POST /api/train-scheduling/bookings/:bookingId/mark-paid": ["Staff: mark a reserved booking paid and allocate it now", "POST", "Train Schedule"],
"POST /api/train-scheduling/bookings/:bookingId/move-schedule": ["Re-point a booking to another OPEN same-route schedule", "POST", "Train Schedule"],
"POST /api/train-scheduling/bulk/preview": ["Preview a bulk train schedule", "POST", "Train Schedule"],
"POST /api/train-scheduling/bulk/schedules": ["Create a bulk train schedule", "POST", "Train Schedule"],
"POST /api/train-scheduling/bulk/schedules/:id/assign-bookings": ["Assign bulk bookings to a train schedule", "POST", "Train Schedule"],
"POST /api/train-scheduling/bulk/schedules/:id/cancel": ["Cancel bulk train schedule", "POST", "Train Schedule"],
"POST /api/train-scheduling/container/preview": ["Preview a container train schedule", "POST", "Train Schedule"],
"POST /api/train-scheduling/container/schedules": ["Create a container train schedule", "POST", "Train Schedule"],
"POST /api/train-scheduling/container/schedules/:id/assign-bookings": ["Assign container bookings to a train schedule", "POST", "Train Schedule"],
"POST /api/train-scheduling/container/schedules/:id/cancel": ["Cancel container train schedule", "POST", "Train Schedule"],
"PATCH /api/train-scheduling/global-rules": ["Update global train scheduling rules (singleton)", "PATCH", "Train Schedule"],
"POST /api/train-scheduling/preview": ["Preview a mixed-capable train schedule", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/adjust-consist": ["Permanently trim free wagons off / couple yard wagons onto the schedule's built train (weight & length limits incl. tolerance enforced, every change logged)", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/arrive": ["Mark a dispatched train arrived (move assets to destination yard, free assets)", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/assign-bookings": ["Assign bookings to a train schedule (mixed-capable)", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/assign-unassigned-booking": ["Assign one linked unallocated booking to wagons (preserves existing assignments)", "POST", "Train Schedule"],
"PATCH /api/train-scheduling/schedules/:id/booking-window": ["Open or close a schedule booking window", "PATCH", "Train Schedule"],
"DELETE /api/train-scheduling/schedules/:id/bookings/:bookingId": ["Unassign a booking from a train schedule", "DELETE", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/bookings/:bookingId/load": ["Confirm a booking's cargo loaded at its origin yard (any direction; train must be at that yard)", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/bookings/:bookingId/unload": ["Confirm a booking's cargo unloaded at its destination yard — per-booking arrival, may precede the train's final arrival", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/checkpoints": ["Log the train passing a station (final station triggers arrival)", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/confirm-loading": ["Confirm cargo loaded on the train (any direction; unblocks import-Djibouti dispatch)", "POST", "Train Schedule"],
"PATCH /api/train-scheduling/schedules/:id/container-items/:itemId": ["Update a container number on a wagon slot", "PATCH", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/dispatch": ["Dispatch a scheduled train", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/doc-review-complete": ["Staff finished document review early — run the batch/payment phase now (applies to the whole route-day group)", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/finalize": ["Finalize a draft train schedule", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/import-djibouti/depart": ["Depart loaded import train from Djibouti", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/import-djibouti/documents": ["Upload/check an import Djibouti-side document", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/import-djibouti/gatepass-granted": ["Mark import Djibouti gatepass permission granted", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/import-djibouti/load-list": ["Generate import load list / marshalling document summary", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/import-djibouti/loaded-on-train": ["Confirm import cargo loaded on train at Djibouti", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/import-djibouti/ready-for-loading": ["Mark import train ready for loading at Djibouti", "POST", "Train Schedule"],
"PATCH /api/train-scheduling/schedules/:id/import-loading-status": ["Mark import bookings loaded/unloaded on this schedule (tracking only, does not affect dispatch)", "PATCH", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/intercity/:bookingId/load": ["Confirm intercity cargo loaded (train must be at the booking's origin yard)", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/intercity/:bookingId/unload": ["Confirm intercity cargo unloaded at the booking's destination yard (completes the booking)", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/intercity/accept": ["Accept intercity bookings onto this train (opens their pay window; capacity re-checked per booking)", "POST", "Train Schedule"],
"PATCH /api/train-scheduling/schedules/:id/loading-status": ["Mark bookings loaded/unloaded on this schedule (any direction, pre-dispatch only)", "PATCH", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/pin-wagons": ["Pin physical wagons to train set slots", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/run-allocation": ["Run wagon-level allocation for all eligible linked bookings", "POST", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/run-batch": ["Manually run the batch fill for a schedule", "POST", "Train Schedule"],
"PATCH /api/train-scheduling/schedules/:id/schedule-date": ["Reschedule a train's departure date — only before the booking window opens, and only if the new date still leaves room for the booking lead window", "PATCH", "Train Schedule"],
"PATCH /api/train-scheduling/schedules/:id/train-number": ["Edit a departure's train number and voyage number — allowed only until the train is dispatched", "PATCH", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/switch-government-booking": ["Switch out commercial bookings to allocate a government booking in their place", "POST", "Train Schedule"],
"DELETE /api/train-scheduling/schedules/:id/wagons/:trainSetWagonId": ["Remove an empty wagon slot from a train", "DELETE", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/wagons/:wagonId/move-load": ["Move a wagon's whole load to another wagon (empty → move/repin, loaded → swap loads)", "POST", "Train Schedule"],
"PATCH /api/train-scheduling/schedules/:id/window-rule": ["Override the booking-window rule for one schedule (open/close hour, duration, doc-review, payment, lead days) — only before the window opens", "PATCH", "Train Schedule"],
"POST /api/train-scheduling/schedules/:id/merge": ["Merge another train into this schedule: its wagons join this consist, a same-day schedule on it is absorbed, and the emptied train is deactivated", "POST", "Train Schedule"],
"PATCH /api/train-scheduling/schedules/:id/checkpoints/:sequenceNo": ["Edit a logged leg", "PATCH", "Train Schedule"],
// Transit Agent
"POST /api/transit-agents": ["Create a transit agent", "POST", "Transit Agent"],
"PATCH /api/transit-agents/:id": ["Update a transit agent", "PATCH", "Transit Agent"],
"DELETE /api/transit-agents/:id": ["Soft-delete a transit agent", "DELETE", "Transit Agent"],
// Truck Type
"POST /api/truck-types": ["Create a truck type", "POST", "Truck Type"],
"PATCH /api/truck-types/:id": ["Update a truck type", "PATCH", "Truck Type"],
"DELETE /api/truck-types/:id": ["Soft-delete a truck type", "DELETE", "Truck Type"],
// User Trade Access
"PUT /api/user-trade-access/:userId": ["Set the trade directions a backoffice user may see", "PUT", "User Trade Access"],
// Vehicle
"POST /api/vehicles": ["Create a new vehicle", "POST", "Vehicle"],
"PATCH /api/vehicles/:id": ["Update a vehicle", "PATCH", "Vehicle"],
"DELETE /api/vehicles/:id": ["Delete a vehicle", "DELETE", "Vehicle"],
// Wagon
"POST /api/wagons": ["Create a new wagon", "POST", "Wagon"],
"PATCH /api/wagons/:id": ["Update a wagon", "PATCH", "Wagon"],
"DELETE /api/wagons/:id": ["Delete a wagon", "DELETE", "Wagon"],
"POST /api/wagons/:id/assign-train": ["Assign wagon to a train", "POST", "Wagon"],
"DELETE /api/wagons/:id/permanent": ["Permanently delete a wagon (irreversible; refused if it has movements, containers or train-set slots)", "DELETE", "Wagon"],
"POST /api/wagons/:id/unassign-train": ["Unassign wagon from train", "POST", "Wagon"],
"POST /api/wagons/bulk-status": ["Set the status of multiple wagons (audited in wagon_status_logs)", "POST", "Wagon"],
"POST /api/wagons/bulk-transfer": ["Transfer multiple wagons to a destination yard", "POST", "Wagon"],
// Wagon Transfer Request
"POST /api/wagon-transfer-requests": ["File a count-only wagon-transfer request", "POST", "Wagon Transfer Request"],
"POST /api/wagon-transfer-requests/:id/cancel": ["Withdraw a request that has not moved any wagon yet (use close-short once wagons have moved)", "POST", "Wagon Transfer Request"],
"POST /api/wagon-transfer-requests/:id/close-short": ["OCC: end the request with fewer wagons than asked for — what moved stays, the requester is told the shortfall", "POST", "Wagon Transfer Request"],
"POST /api/wagon-transfer-requests/:id/fulfill": ["OCC: pick wagons and execute the transfer", "POST", "Wagon Transfer Request"],
"POST /api/wagon-transfer-requests/bulk-fulfill": ["OCC: accept-and-execute a subset of pending requests (auto-picks available wagons; the rest stay PENDING)", "POST", "Wagon Transfer Request"],
// Wagon Type
"POST /api/wagon-types": ["Create a wagon type", "POST", "Wagon Type"],
"PATCH /api/wagon-types/:id": ["Update a wagon type", "PATCH", "Wagon Type"],
"DELETE /api/wagon-types/:id": ["Soft-delete a wagon type", "DELETE", "Wagon Type"],
// Warehouse
"POST /api/warehouse-allocation-rules": ["Create a warehouse allocation rule", "POST", "Warehouse"],
"PATCH /api/warehouse-allocation-rules/:id": ["Update a warehouse allocation rule", "PATCH", "Warehouse"],
"DELETE /api/warehouse-allocation-rules/:id": ["Delete a warehouse allocation rule", "DELETE", "Warehouse"],
"POST /api/warehouse-allocation/preview": ["Preview the yard/warehouse/zone a booking would be allocated to", "POST", "Warehouse"],
"POST /api/warehouse-fee-rules": ["Create a storage / demurrage fee rule", "POST", "Warehouse"],
"PATCH /api/warehouse-fee-rules/:id": ["Update a fee rule", "PATCH", "Warehouse"],
"DELETE /api/warehouse-fee-rules/:id": ["Delete a fee rule", "DELETE", "Warehouse"],
"POST /api/warehouse-fees/accrual/:inventoryId/acknowledge": ["Acknowledge / snooze an item fee-accrual alert", "POST", "Warehouse"],
"DELETE /api/warehouse-fees/accrual/:inventoryId/acknowledge": ["Remove an accrual acknowledgement (re-surface for alerts)", "DELETE", "Warehouse"],
"POST /api/warehouses": ["Create warehouse", "POST", "Warehouse"],
"PATCH /api/warehouses/:id": ["Update warehouse", "PATCH", "Warehouse"],
"POST /api/warehouses/:warehouseId/yards": ["Create a yard within a warehouse", "POST", "Warehouse"],
// Warehouse Fee Invoice
"POST /api/last-mile/:id/generate-truck-detention-invoice": ["Generate a truck-detention invoice for a last-mile leg (per truck per day)", "POST", "Warehouse Fee Invoice"],
"PATCH /api/warehouse-fee-invoices/:id/cancel": ["Cancel a warehouse fee invoice", "PATCH", "Warehouse Fee Invoice"],
"POST /api/warehouse-fee-invoices/:id/pay": ["Record a payment against a warehouse fee invoice", "POST", "Warehouse Fee Invoice"],
"POST /api/warehouse-fee-invoices/:id/pay-online": ["Initiate Telebirr/Waafi payment for a warehouse fee invoice", "POST", "Warehouse Fee Invoice"],
"POST /api/warehouse-inventory/:id/generate-fee-invoice": ["Generate a warehouse fee invoice from Batch 5 fee calculation", "POST", "Warehouse Fee Invoice"],
// Warehouse Inspection Report
"PATCH /api/warehouse-inspection-reports/:id": ["Update an inspection report", "PATCH", "Warehouse Inspection Report"],
"POST /api/warehouse-inspection-reports/:id/attachments": ["Upload inspection images / documents", "POST", "Warehouse Inspection Report"],
"POST /api/warehouse-inventory/:inventoryId/inspection-reports": ["Create an inspection / damage report for an inventory item", "POST", "Warehouse Inspection Report"],
// Warehouse Inventory
"POST /api/warehouse-inventory/:id/deliver": ["Deliver import goods to the customer + capture proof of delivery", "POST", "Warehouse Inventory"],
"PATCH /api/warehouse-inventory/:id/dispatch": ["Mark loaded inventory DISPATCHED (left the terminal)", "PATCH", "Warehouse Inventory"],
"POST /api/warehouse-inventory/:id/gate-clearance": ["Final terminal release / gate clearance (blocked while fees unpaid)", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/:id/load": ["Load READY_FOR_LOADING inventory onto a wagon", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/:id/move": ["Move inventory to another warehouse/yard/zone", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/:id/ready-for-loading": ["Mark reserved inventory READY_FOR_LOADING", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/:id/ready-for-pickup": ["Mark inspected IMPORT inventory READY_FOR_PICKUP", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/:id/release": ["Issue a DO / release order for ready-for-pickup inventory", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/:id/store": ["Mark received inventory as STORED (optional explicit warehouse/yard/zone)", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/auto-load-ready": ["Auto-load READY_FOR_LOADING inventory with PAID bookings", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/auto-unload-arrived": ["Bulk auto-unload all arrived bookings into the warehouse", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/bookings/:bookingId/approve-delivery": ["Approve delivery — customer records their full name (signature optional)", "POST", "Warehouse Inventory"],
"PATCH /api/warehouse-inventory/bookings/:bookingId/double-handling": ["Record Yes/No double handling after unloading (Yes applies the double-handling fee rule)", "PATCH", "Warehouse Inventory"],
"POST /api/warehouse-inventory/bookings/:bookingId/request-handover-signature": ["Ask the customer to sign the handover (creates one if none, then notifies)", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/bookings/:bookingId/unload": ["Unload a single arrived booking into a location", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/bulk-dispatch-export": ["Bulk-dispatch loaded EXPORT inventory (LOADED → DISPATCHED)", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/bulk-mark-inspected": ["Bulk mark received inventory inspection PASSED (EXPORT → READY_FOR_LOADING)", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/export/auto-unload-at-djibouti": ["Unload all eligible export items assigned to an arrived Djibouti-side train", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/handovers/:handoverId/sign": ["Customer signs one handover (EDR last-mile: one signature per truck)", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/import/auto-unload-arrived-bookings": ["Unload all eligible assigned bookings of an ARRIVED import train (→ UNLOADED)", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/receive": ["Receive inventory at a warehouse location", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/receive-bulk": ["Bulk-receive selected eligible PAID bookings into a location", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/reserve": ["Reserve stored inventory for a PAID booking", "POST", "Warehouse Inventory"],
"POST /api/warehouse-inventory/train/:scheduleId/load": ["Load selected inventory items onto their allocated wagons for a train", "POST", "Warehouse Inventory"],
// Warehouse Yard
"PATCH /api/warehouse-yards/:id": ["Update warehouse yard", "PATCH", "Warehouse Yard"],
"POST /api/warehouse-yards/:yardId/zones": ["Create a zone within a yard", "POST", "Warehouse Yard"],
// Warehouse Zone
"PATCH /api/warehouse-zones/:id": ["Update warehouse zone", "PATCH", "Warehouse Zone"],
// Weight Limit Rule
"POST /api/weight-limit-rules": ["Create a weight limit rule", "POST", "Weight Limit Rule"],
"PATCH /api/weight-limit-rules/:id": ["Update a weight limit rule", "PATCH", "Weight Limit Rule"],
"DELETE /api/weight-limit-rules/:id": ["Soft-delete a weight limit rule", "DELETE", "Weight Limit Rule"],
// Yard
// Yard Position (desk↔yard mapping — an input to yard access scoping, so
// every change to it is evidence of who widened or narrowed someone's reach)
"PUT /api/yard-positions/yard/:yardId": ["Replace a yard's whole position set", "PUT", "Yard Position"],
"PUT /api/yard-positions/position/:positionId": ["Replace a position's whole yard set", "PUT", "Yard Position"],
"POST /api/yards": ["Create a yard", "POST", "Yard"],
"PATCH /api/yards/:id": ["Update a yard", "PATCH", "Yard"],
"DELETE /api/yards/:id": ["Soft-delete a yard", "DELETE", "Yard"],
"POST /api/yards/:id/move-order": ["Move a yard up or down in display order", "POST", "Yard"],
"POST /api/yards/reorder": ["Bulk reorder yards by ID list", "POST", "Yard"],
// Yard Distance
"POST /api/yard-distances": ["Create a yard distance", "POST", "Yard Distance"],
"PATCH /api/yard-distances/:id": ["Update a yard distance", "PATCH", "Yard Distance"],
"DELETE /api/yard-distances/:id": ["Soft-delete a yard distance", "DELETE", "Yard Distance"],
};