Wholesale · Deliveries

Inbound Delivery Ingestion

A user‑experience walkthrough of the asynchronous ingestion pipeline — every state, every step, and every action a user can take. Written for the UI/UX & frontend design session. No backend detail — only what the user can see and do.

7 lifecycle states 10 pipeline steps Live, no refresh needed Pause · Resume · Fix · Retry ZIP · RAR · 7z archives Non‑fatal warnings

The big picture

A user uploads a raw delivery file. The system turns it into a real Inbound Delivery by running it through a pipeline of 10 steps. The whole thing is asynchronous and live: the user submits and then watches progress update on its own — one upload is shown as one card.

Along the way the user can pause at any point, resume from where it paused, and if a step finds a problem with the data, fix it and retry. Near the end there is a grace period — a safety countdown where the user can stop the upload if they spot a mistake — before the delivery is actually created. When it finishes, a Delivery (and, when there is leftover stock, a generated Order) is created and the user gets direct links to open them.

One mental model for the designer: a card = one upload; the card shows where it is (a row of step bubbles + a status), and offers the actions that make sense for that status.

1 · Lifecycle states

The card always shows exactly one status. It drives the colour, the headline, and which buttons appear.

Queued

Submitted and waiting to start. Nothing has run yet.

Can: Pause
Running

Actively working through the steps. Progress and the current step update live.

Can: Pause
Grace

All preparation is done and a countdown is running before the delivery is created — the user's chance to stop a mistaken upload before it's committed.

Can: Pause
Stopped

Paused by the user. It stays exactly where it was and waits. The headline shows where: e.g. “paused before Create delivery”.

Can: Resume · Fix & Restart · Delete · Download
Failed

A step found a problem with the data (e.g. an unknown product, a duplicate key). The card shows the exact items that failed.

Can: Fix & Restart · Delete · Download
IBO generated

The delivery was created, but it produced an Order that still needs to be filled in. The ingestion waits here and finishes on its own (→ Succeeded) once that order is completed — no action needed to push it along.

Can: Open Delivery / Order · Download
Succeeded

The delivery was created (and any generated Order is now completed). The card carries links to the created Delivery and that Order.

Can: Open Delivery / Order · Download

A restart does not create a separate record — the same card simply bumps to a new attempt and keeps the previous run in a collapsible “Previous attempts” block.

2 · The pipeline at a glance

Ten steps, left to right. Each one shows as a bubble that fills in as it completes — ✓ done (with how long it took), ✗ failed, a highlighted bubble while running, or a grey number for a step not yet reached. The three outcomes the UI needs to render:

Successful run every step completes — the delivery is created.
✓
Parse
6.2s
✓
Unpack
5.9s
✓
Partner
6.2s
✓
Products
6.3s
✓
Keys
6.1s
✓
Reserve
6.2s
✓
Check
6.2s
✓
Upload
6.0s
✓
Grace
30s
✓
Create
0.4s
Failed run a check rejects the data — the pipeline stops at that step and shows the error; later steps never run.
✓
Parse
6.2s
✓
Unpack
5.9s
✓
Partner
6.2s
✗
Products
failed
5
Keys
—
6
Reserve
—
7
Check
—
8
Upload
—
9
Grace
—
10
Create
—
Stopped run the user paused mid‑pipeline — the running step finished, then it halted before the next one (here: paused before Check keys).
✓
Parse
6.2s
✓
Unpack
5.9s
✓
Partner
6.2s
✓
Products
6.3s
✓
Keys
6.1s
✓
Reserve
6.2s
7
Check
⏸ paused
8
Upload
—
9
Grace
—
10
Create
—

3 · Every step — what the user sees

Plain language: what each step is for, exactly what the user sees on the card as it runs, and where a step can fail.

1
Read the upload

Parse raw payload

Reads the uploaded file and pulls out the partner and the list of items with their keys.

Sees: while it runs, the header reads “step 1/10 · Parse raw payload” and the progress bar starts to fill. On success the bubble turns green ✓ with its duration, and the partner and item count it found appear in the card’s details. If the file can’t be read, or a line carries no keys at all, the bubble turns red ✗, the status flips to Failed, and the error explains what was wrong.
can fail · empty / unreadable upload
2
Prepare · check

Unpack archives

When the upload contains archives, the individual files inside are extracted so the rest of the pipeline works on real files. The async pipeline now reads ZIP, RAR and 7z archives (the archive type is detected from its contents, or its file extension as a fallback). Archives can be password‑protected — the user attaches the archive’s password to that line and the step decrypts it on the way in. (The manual / synchronous create flow still handles ZIP only.)

Sees: the bubble shows as running, then turns green ✓ with a duration; from this point on the timeline operates on the extracted files. Individual entries that can’t be used — nested too deep, password‑protected without a usable password, or an unrecognized file type (only images count as key files) — are skipped, not failed: the archive keeps going and the skipped file names are surfaced as an amber warning (see below) so the user knows exactly what was left out. Only a corrupt / wrong‑password archive, or one that yields no usable files at all, turns the bubble red ✗ → Failed, with a “Wrong archive password” or “Password‑protected archive” message telling the user to fix this line’s password and re‑upload. Hovering the bubble reveals when it started, finished and how long it took.
can fail · bad / locked archive skipped when no archive may warn · skipped entries
3
Check

Validate partner

Confirms the partner on the upload is a real, valid delivery partner.

Sees: a quick green ✓ on success, and the partner’s name is shown on the card. If the partner is unknown or missing, the bubble turns red ✗, the status flips to Failed, and the error panel names the partner problem.
can fail · unknown partner
4
Check

Resolve & validate products

Matches every line on the upload to a real, available product in the catalogue, and checks the lines are within limits.

Sees: a green ✓ once every line passes. On failure the bubble turns red ✗ → Failed and the error panel names each problem line — an unknown product, one that’s disabled or on hold, a dependent item with no name, an over‑long note, or simply too many lines — so the user knows exactly what to correct.
can fail · unknown / unavailable product
5
Prepare · check

Generate keys

Reads the actual keys out of the upload — the typed keys and the contents of each file — and checks the load stays within its limits. Whether each key is free to load is checked at the next Check keys step.

Sees: for a large load a live count of keys read ticks up; on success the bubble turns green ✓. It turns red ✗ → Failed if a file can’t be read, or if the load breaks a limit (too many keys, too many dependents, or a dependent that doesn’t line up with its base) — the error panel names each offending line to fix and retry.
can fail · unreadable file / over limits live progress
6
Prepare · check

Reserve keys

Claims every key in the load so that no other upload running at the same time can grab the same ones.

Sees: a green ✓ when the claim succeeds. If another upload is already using one of these keys, the bubble turns red ✗ → Failed and the error panel names the clashing keys (being ingested elsewhere right now) — wait until the other upload finishes (or change the keys), then Restart. A failed ingestion recovers via Restart, not Resume.
can fail · key in use elsewhere
7
Check

Check keys

Checks every key is actually free to load: the same key appearing more than once in the upload, and each key against what the system already holds.

Sees: a green ✓ when the load is clean. The bubble turns red ✗ → Failed if the upload repeats a key, or a key is already in stock, already loaded on an earlier delivery, or still downloading — the error panel lists each offending item, ready to fix and retry. Failing here also frees the keys it had reserved, so a parallel upload isn’t blocked while the user fixes this one. If the load allows duplicates and a key was already loaded before, it is let through — but the accepted keys are surfaced as an amber warning (see below) rather than a failure.
can fail · duplicate / unavailable keys may warn · duplicates accepted
8
Prepare

Upload keys

Sends the uploaded files to storage so they’re ready for the delivery.

Sees: for a load with many files a live count ticks up as batches upload, then the bubble turns green ✓ and the progress bar moves into the final stretch. A text‑only upload has no files to send, so this step is skipped. A storage hiccup here isn’t a user error — it simply retries on its own.
skipped for text‑only live progress
9
Safety window — stop a mistake

Await grace period

A countdown before the delivery is actually created. It exists so the user can stop the ingestion if they spot a mistake — a wrong upload never gets committed once they pause here.

Sees: the status shows Grace and the card displays a live ⏳ grace countdown with a shrinking bar and a “delivery in 12s” timer, while the Pause button sits front‑and‑centre. Pausing halts it before anything is created (the card then reads “paused before Create delivery”); letting the timer reach zero moves straight on to Create.
user can pause & resume here
10
The result

Create delivery

Creates the Inbound Delivery and — when the upload has leftover stock — a generated Inbound Order, then loads the keys onto PickTower.

Sees: the last bubble fills and the bar reaches 100%. The card’s details now show clickable IBD‑… (the delivery) and, when one was generated, IBO‑… (the order) — opening them in the main app. If no order was generated the status flips straight to Succeeded; if one was, the card first shows IBO generated while that order waits to be filled in, then flips to Succeeded on its own once the order is completed.

4 · Anatomy of a card

Everything the user reads on a single ingestion, top to bottom.

08ded02d Stopped paused before Create delivery 1m 55s  90%
⏳ Grace period — delivery is created when it elapses (pause to halt first) delivery in 12s
  • Header line — short id · status chip · where it is now (“step 6/10 · Reserve keys”, “paused before Create delivery”, “done”) · attempt number if it was retried · elapsed time · progress %.
  • Progress bar — coloured by status (blue running, green done, amber stopped, red failed).
  • Step bubbles — the 10‑step rail with each step’s state & duration.
  • Live “…working” line — for longer steps, a one‑line detail of what’s happening right now.
  • Grace countdown — the timer + shrinking bar shown above, while in the grace window.
  • IBO‑generated notice — a violet line shown when the created delivery generated an order: “🧾 Delivery created — the generated order still needs to be filled in & completed. Finishes automatically once it is.”
  • Stop notice — “⏸ Stop requested — the pipeline will halt before the next step”, shown while a pause is pending.
  • Warning blocks — amber notices under the timeline for non‑fatal heads‑ups (e.g. skipped archive files, already‑loaded keys accepted under allow‑duplicates); the run still completes.
  • Audit tooltips — each lifecycle marker (stop / resume / restart) shows a “by <user> · <time>” tooltip so every action is attributable.
  • Details (expand) — who created it & when, the partner name, source, and — once created — links to the Delivery and Order. Plus per‑item error details and a previous‑attempts history.

5 · Actions reference

Which buttons appear, when, and what they do for the user. Only the relevant ones show for a given status.

ActionAppears when…What it does
⏸ Stop / ⏸ Pause Queued · Running · Grace Pauses it. The step that’s already running finishes (no wasted work); it halts before the next step. In the grace window the button reads Pause.
⏸ Stopping… pause pending Disabled placeholder shown for the brief moment between clicking pause and the pipeline actually halting.
▶ Resume Stopped (mid‑pipeline) Continues from the step where it was paused — already‑completed steps are not re‑run, and the upload isn’t re‑sent. A failed ingestion isn’t resumed here — it recovers via Restart (fix + re‑upload).
▶ Resume paused in the Grace window Re‑arms the grace countdown; the delivery is created when it elapses again.
✎ Load into form Stopped · Failed Loads the upload back into the editor, highlighting the items that failed, so the user can correct them.
↺ Restart Stopped · Failed Re‑runs from step 1 using the corrected form, on the same card. The earlier run is kept as a collapsible “Previous attempts” entry.
⬇ Download payload always Downloads the stored upload exactly as it was submitted (audit / re‑use).
🗑 Delete Failed · Stopped Permanently removes the ingestion and its stored upload.
IBD‑… IBO‑… Succeeded · IBO generated Deep links that open the created Delivery and the generated Order in the main app. The IBO‑… link already appears in IBO generated — that’s the order the user goes to fill in.

6 · Key user journeys

The three flows worth designing for.

① Happy path

Submit upload→ Watch steps tick green→ Grace countdown→ Delivery created→ Open IBD‑… / IBO‑…

② Pause & resume

Running→ Pause (current step finishes)→ Stopped — “paused before X”→ Resume→ Continues from X (no re‑run)

③ Fix & retry

Step fails→ See per‑item errors→ Load into form & fix→ Restart→ Runs again (old attempt kept as history)

④ Generated order to complete

Delivery created→ IBO generated — order awaits→ User opens & completes the Order→ Succeeded (automatic)

7 · Notes for the design

Live by default

Cards update on their own as steps progress — the user never has to refresh. New uploads appear at the top.

No wasted work on pause

A pause never throws away the step in progress — it finishes, then the pipeline halts before the next one. The card shows which step it’s paused before.

Grace is the safety net

The grace countdown is the deliberate window for the user to stop a wrong upload before it’s created. It deserves a clear, prominent timer and an unmissable Pause — this is where a mistake gets caught.

Errors are item‑level

Failures name the specific lines / keys (title · message · explanation), so the UI should make them scannable and tie them to “fix & retry”.

Non‑fatal warnings

A step can also raise a warning — the run keeps going, the user just gets a heads‑up shown in amber under the step timeline. Two the user will meet: archive files skipped during Unpack, and already‑loaded keys accepted when the load allows duplicates. Warnings never block completion; design them as a distinct, calmer style than the red error blocks.

Password‑protected archives

An uploaded ZIP, RAR or 7z can be encrypted. The user supplies its password alongside the line; the pipeline decrypts it during Unpack archives. A wrong or missing password on the whole archive fails that step with a clear message — fix the password and retry — while individual encrypted or unusable entries are just skipped with a warning. (The manual create form still takes ZIP only.)

Who did what (audit)

Stop / pause, resume and restart are now recorded with the user who did them. The detail view shows a “by <user> · <time>” tooltip on each lifecycle marker, so an ingestion’s history is attributable per action.

Two outputs

Success can produce a Delivery and a generated Order. Surface both links; the Order may be absent (no overflow) — design for one‑or‑two. When an Order is generated, the card pauses in IBO generated until that order is completed, then becomes Succeeded on its own.

Empty & auth states

Before anything runs: “No ingestions yet”. The list also needs a signed‑out / loading state.

History stays

Restarting keeps the prior attempt as a collapsible “Previous attempts” block with its own timeline and errors.