Supercommerce API Docs
Admin API

ClickPost automation — rollout

How to deploy automatic courier assignment and per-order shipment grouping: the pre-migration check, the deploy order, what to verify at each step, and how to turn either feature off again.

Deploying automatic courier assignment and per-order shipment grouping. Both ship off, so the deploy itself changes no behaviour — the ordering below exists so that each step is verifiable before the next one can affect a real shipment.

Source: admin/shipping-clickpost.md for what the features do. This page is only about getting them live safely.


1. Check the database before migrating

DATABASE_URL=<production> bun run db:preflight

Read-only. It reports the conditions that would abort the migration, names the offending rows, and exits non-zero so CI can gate on it.

The one likely to fire is duplicate shipment references. That is not a migration problem — it is evidence of the bug the migration exists to stop: a reused reference_number is answered by ClickPost with status 323, reported as success, returning the earlier dispatch's waybill. Any duplicates you find are shipments holding another shipment's AWB.

Resolve them by deciding which row holds the real waybill and clearing reference on the others — it is only a record of what was sent. Do not drop the index to get the migration through; it is the thing that stops this recurring silently.

2. Migrate

bun run db:migrate

Two migrations apply. Neither rewrites existing rows: columns become nullable, new columns arrive empty, and the check constraints are satisfied by every row written before them (a pre-existing shipment carries a sub-order and no order, which is exactly what "exactly one" requires).

If it fails anyway, bun run db:migrate surfaces the real Postgres error that drizzle-kit swallows.

3. Deploy

Nothing changes yet — both settings default to off.

If you run split roles, the worker role must be deployed too: the assignment job runs on a BullMQ queue (clickpost-auto-assign) whose processor only registers when APP_ROLE is not api. An API-only deploy would enqueue work nothing consumes.

Confirm the app came up and the queue registered:

redis-cli --scan --pattern 'bull:clickpost-auto-assign*'

4. Configure ClickPost

Admin → Settings → Shipping. Automatic assignment needs the platform account fully configured — the same keys manual fulfilment already uses:

clickpost.api_key, clickpost.username, clickpost.webhook_secret, clickpost.pickup_pincode, the clickpost.pickup_* block, and clickpost.default_parcel.

Anything missing and assignment records skipped and stays quiet, rather than failing an order. That is the intended behaviour, but it also means a half-configured install looks like nothing is happening.

5. Turn on assignment

Set clickpost.auto_assign_enabled = true.

From here, each new order has a courier chosen automatically. Nothing is booked and nothing is billed — an operator still confirms each shipment from the orders table.

Verify on a real order:

  • the Courier column shows a carrier shortly after the order is placed
  • the shipping tab shows the carrier and its quoted charge
  • no AWB exists yet, and the sub-order is still pending

6. Confirm one shipment by hand

Pick a single order and press Confirm shipment. This is the first time anything is billable.

Check: an AWB comes back, the sub-order stays pending, the label prints from Admin → Print Labels, and the tracking page shows the shipment. Then wait for the courier's pickup scan and confirm the order flips to fulfilled and the customer's shipped notification goes out exactly once.

Only once that round-trip works should you use bulk confirm.

7. Per-order grouping (optional)

Only if you pack a multi-vendor order as a single box. Set shipment_grouping = per_order.

Verify on a multi-vendor order: one shipment, one AWB mirrored onto every bag, one label carrying the full COD amount and every bag's items, and one tracking callback advancing all of them together.

Orders booked before the switch keep their per-bag shipments; both shapes are read correctly, so there is no backfill.


Turning it off

Both settings are live switches, and neither strands anything already in flight.

SetEffect
auto_assign_enabled = falseNo new assignments are queued. Existing assignments stay confirmable, and already-booked shipments are unaffected.
shipment_grouping = per_vendorNew orders go back to one shipment per bag. Already-consolidated parcels keep working — tracking, labels and cancellation all read the shape each shipment was booked in.

Removing the integration entirely is a one-line change: delete ClickPostShippingModule.forRoot() from apps/api/src/app.module.ts. The listener, processor, queue and endpoints all go with it, and the assignment rows become inert data that nothing reads.

What to watch after enabling

  • Assignments stuck at assigned. Nothing is wrong — they are waiting for someone to confirm. Filter the orders list by Assigned to see the queue.
  • failed assignments. Filter by Assignment failed; the reason is on the row. An unserviceable pincode is a verdict, not an outage, and is not retried.
  • Sub-orders pending with a live AWB and no movement. The courier has not scanned a pickup. Any later checkpoint fills the gap automatically, but a parcel sitting like this for days means it was never collected.

On this page