[T07] Import Manufactured Numbers — Summary

Summary

Tenant-scoped exit bookend of the manufactured-numbers async import flow. Mirrors E06's and E08's summary screens. Operator arrives here from C05's terminal-state redirect; the job is already in COMPLETED / FAILED / CANCELLED. Screen renders a pure post-flight reconciliation view: created counts, idempotent no-ops, duplicate-sequence warnings, and rows imported without a tag (the C02 follow-up queue).

Actor & Context

Actor: stock operator (tenant-admin assistant), same actor as T06.

Frequency: once per T06 import, plus occasional re-opens via the "Recent imports" list on T06.

Precondition:

  • User has TENANT_ADMIN permission.

  • The import job referenced by the route’s :uuid exists and is in a terminal state.

Entry point: redirected from C05 on terminal-state via the 't06' caller key. Route: /inventory/numbers/onboard/imports/{uuid}/summary. Also reachable from the T06 "Recent imports" list (read-only re-open).

Main Flow

  1. Mount + load. Page calls GET /api/imports/{uuid}/results once. Does NOT poll. Does NOT render a progress bar.

  2. Header. "Import complete" / "Import cancelled" / "Import failed", filename, finished-at timestamp, NumberType name, "N rows processed" counter.

  3. Right-rail "About this screen" panel. Same pattern as E06 / C05. Copy describes what the summary represents and what to do next (e.g. "rows that landed without a tag are ready for C02 scanning").

  4. Body — per-row reconciliation. Tabbed sections, in this order:

    • Created (N) — rows newly inserted as MANUFACTURED. Count + drill-down list (sequence, number, barcode if present, paired-tag indicator).

    • Already on file (N) — rows where (numberTypeId, sequence) already existed. Idempotent no-ops; informational. (per AF-4 in T06)

    • Duplicate sequence in file (N) — rows where (numberTypeId, sequence) collided with another row in the same upload. Drill-down lists the file-row numbers and the offending sequence value. Count rendered as a warning, not an error — the first occurrence imported successfully; the duplicates were skipped.

    • Imported without a tag (N) — rows that imported successfully but have tag_id NULL (barcode column was empty per AF-2 in T06). Deep-link button: Pair tags now — opens C02 with the NumberType pre-selected so the operator can immediately continue.

    • Other issues (N) — catch-all for any FK-mismatch or row-validation issues that surfaced during PROCESSING (rare given the fixed schema).

  5. Bottom actions. Open number stock (links to T02 filtered to the imported NumberType) + Import another file (returns to T06 upload).

Alternative Flows

  • AF-1 — Cancelled job. Header reads "Import cancelled" + the same per-row breakdown for whatever was processed before cancel. The "Created" count reflects what was committed; the "Imported without a tag" tab still surfaces partial results so the operator knows what’s already in stock.

  • AF-2 — Failed job (FAILED). Header reads "Import failed" + reason + Try again button returning to T06 upload. Per-row results render if any rows committed before the failure.

  • AF-3 — Re-open via Recent imports. Read-only mode; same layout, no Try again affordance unless the underlying job was FAILED.

  • AF-4 — Direct deep-link. URL pasted by another user with no caller-key context. Page loads identically — it does not depend on localStorage.importCaller (that key was consumed by C05 on its terminal redirect, not by T07).

Acceptance Criteria

  • Use-case page authored (this page).

  • Status design-todo → in-design → handoff-ready after Claude Design pass and Coordination Backlog resolution.

  • :design-url: populated.

  • Cross-references C05, T06, C02, T02.

  • Page does not poll; renders results from a single GET /api/imports/{uuid}/results call.

  • Reconciliation key is (numberTypeId, sequence).

  • Duplicate-sequence rows are surfaced as a warning section, not a hard error.

  • "Imported without a tag" section deep-links to C02 with the NumberType pre-selected.

  • Failure-mode rendering matches the E06 / E08 precedent (CANCELLED / FAILED headers).

API Surface

Call Purpose

GET /api/imports/{uuid}/results

Drives the entire summary screen. Response includes per-row outcomes bucketed by category (created / alreadyOnFile / duplicateSequenceInFile / importedWithoutTag / otherIssues) plus the job’s terminal state and finished-at.

GET /api/imports/{uuid}

Job metadata for the header (filename, NumberType, started-at, finished-at, terminal state). May be folded into /results server-side.

(delegates to C02 / T02 for follow-up navigation)

Bottom-action deep-links.

Out of Scope

  • The mapping middle steps — C05.

  • The upload screen — T06.

  • Editing committed rows — that is T02 / T03 / T04 / C02, not T07.

  • Polling for in-flight progress — by contract, T07 only renders post-terminal state. C05 owns PROCESSING.

Design Anchors

Design Decisions

  • Reconciliation key is (numberTypeId, sequence) (2026-05-07). The number column is the printed face value (operator-facing), but reconciliation runs on sequence because that’s the manufacturer’s stable identifier per type and the column the manufacturer treats as authoritative. Two rows can share a number legitimately across NumberTypes (e.g. bib 42 exists once per type); two rows cannot share (numberTypeId, sequence).

  • Duplicate-sequence is a warning, not a hard error (2026-05-07). When the file contains two rows with the same (numberTypeId, sequence), the first is committed and subsequent are skipped. Surfaced in the summary’s "Duplicate sequence in file" section. Rationale: matches the rest of the import flow’s "row-level issues are surfaced, not blocking" pattern; lets the operator decide whether to clean up the file and re-import or accept the existing imports.

  • Pair-tags-now deep-link (2026-05-07). The "Imported without a tag" section’s primary affordance is a deep-link to C02 with the NumberType pre-selected. Rationale: the operator’s natural next step after importing tagless stock is to scan tags onto it; making that one click rather than three reduces friction. (C02's URL accepts a ?numberTypeId=N query param to pre-select; this is implementation detail for the Track 3 frontend, but the contract is named here.)

  • Pure post-flight view (2026-05-07). Same rule as E06's summary: T07 does NOT poll, does NOT render a progress component, and never reverts to "in-flight" rendering. C05 owns PROCESSING end-to-end; on completion C05 redirects here, this screen calls GET /api/imports/{uuid}/results once, and renders the reconciliation view. Implies arrival on this screen is always post-terminal-state.

  • Read-only re-open is identical to first-load (2026-05-07). Re-opening a past import via "Recent imports" renders the same layout. The only behaviour change is the Try again button, which is only present when the job’s terminal state is FAILED regardless of how the user arrived.

Notes

Backend dependency: relies on ImportType.NUMBER_ONBOARDING returning a results DTO bucketed by the categories listed above. The bucketing is a Track 3 backend deliverable — see plan § Track 3.

Resolved Decisions

Q-E5 (the question parked during initial authoring) was resolved by Coordination Decision CD-8 in the number/tag UI orchestration on 2026-05-07. Took the proposed Default lean:

  • Q-E5 (defer to manufacturer export): T07 stays a pure post-flight reconciliation view — no "next available sequence" hint on the header. That hint lives instead on T08 — Manufacturer Data File Export, where it sits next to the sequence-pivot inputs operators use when scoping the next manufacturer order (US #735).