busy-office-ui
Menu

Pattern: record detail

Who uses it: whoever owns this record, checking its status or adding to its history — a buyer, an approver, anyone who clicked in from a list row. How often: every time a list row is opened — this is the default landing for "tell me about this one," many times a day across a team. What "done" looks like: the current state is read in one glance, without opening anything else. The composed detail screen behind any list row: record cards, a status timeline, and an audit trail stacked in a feed — all standard components, generic to any ERP. This example is a purchase order; the shape is the same for an invoice, a change request, or a leave request. Not once the record stops fitting in one scan — when a reader has to hunt for a section, it wants anchor navigation and a sticky action bar, which is object page. Same content, different reading problem.

The screen

Purchase order PO-88213 Approved
Vendor
Umbrella Logistics
Cost center
CC-4021
Payment terms
Net 30
Total
$12,400.00
Requested
Purchase Order #88213 Approved
  1. SKU-3391 · Standing desk (×4)
  2. SKU-1180 · Monitor arm (×8)
Approved by J. Kim · 12 Aug 2026, 10:15
Goods Receipt #GR-88 Partial
  1. SKU-3391 · 4 of 4 received
  2. SKU-1180 · 5 of 8 received
Awaiting the remaining 3 monitor arms.
Add record

Status

  1. Completed: Requested
    R. Vance · 10 Aug
  2. Completed: Approved
    J. Kim · 12 Aug
  3. Receiving
    partial · 5 of 8
  4. Not started: Invoiced

Audit trail

  1. R. Vance raised PO-88213
  2. J. Kim approved"Within CC-4021 budget."
  3. M. Okafor changed 2 fields on receipt
    Fields changed on this receipt
    FieldOldNewChange
    Qty received 3 5 Modified
    Status Partial Partial Modified

The document frame — measured, not asserted

An ERP document screen is read far more often than it is edited, so the chrome above the content is a recurring tax. The shape here is one identity line — what the document is, which one, what state it is in, and the actions — then the facts, then the content:

Region 1440px 390px Note
Identity line36px68pxone row on desktop; actions wrap to a second row on a phone
Facts strip124px277pxfive facts, auto-fit — this is content, not chrome, and it scrolls
Facts strip before127px331pxsix facts: Status was repeated here and in the line above

Zero new components. The identity line is a split cluster holding the type badge, the record number and a status badge — all shipped. A dedicated document-header component would be a second way to do what a cluster already does.

Two rules worth keeping: status lives in the identity line, not in the facts — it was in both, which cost 54px at phone width for a fact the reader had already seen; and put the actions in the line, not in a bar of their own, because a separate action bar is another band of chrome competing for the same vertical space. The detail form uses the same line; before this it had no identity region at all, so nothing on screen said which purchase order you were editing.

Anatomy

  1. Breadcrumb — breadcrumb; where this record sits, and how users get back to the filtered list.
  2. Facts strip — key-value facts (.bo-kv) for the header facts (vendor, cost centre, total): display data, never readonly inputs.
  3. Record feed — one card per related document (order, receipt, invoice) in chronological order.
  4. Status timeline + audit trail — timeline and audit trail: where it is now, and every state change with actor and timestamp. This is the human-monitoring signal: the actor column is where an agent's own changes become visible to the human owning the record.

Follows the review-screen anatomy contract — this is the short-record shape; see that page for when to reach for object page or approval instead.

Data contract

RequestReturns / on failure
GET /po/:idthe full screen. 404 → the not-found screen, same as any deep link to a record that no longer exists
POST /po/:id/recordsone new card fragment appended to the feed
GET /po/:id/audit?after=…newer audit entries for polling; empty body when nothing changed. 5xx/timeout: the per-section alert in States, not a page-level failure — the facts strip and feed already rendered and must stay readable

The AI-manages / human-monitors split, stated: any actor — human or agent — can append to the feed or the audit trail through the same endpoints; the human's channel is the audit trail's actor column, where an automated change is as visible as a person's.

States

StateWhat ships
Loadingskeleton cards in the feed; the facts strip renders from the record itself, so it never blanks
Empty feedthe record exists with no related documents yet — say so and offer the first action
Error loading a sectiona per-section alert; one failed audit fetch must not blank the record
Read-onlyno composer, no action buttons — the timeline and facts are the whole screen
Stale (someone else acted)poll or push the timeline fragment; a decided record showing "awaiting approval" is the failure mode to avoid
No JSfully functional — this page has no JS dependency. Every card, the status timeline, the audit trail and the field-diff table are static markup; the composer's "Add" control has no <form> wrapper or script wiring either way, so it is illustrative only, never a working control, regardless of JS

Components used

complexity 1 of 4

↑↓ move Enter open Esc close