Enterprise dashboards fail quietly. A column is a day off. A filter lies. A loading skeleton never yields. Trust is the product, and it is earned in contracts, not in gradients.
Start from the payload
UI kits do not save a screen whose types are optional everywhere. Define the wire format first, then the view.
type InvoiceRow = {
id: string;
counterpart: string;
amount: number;
currency: "USD" | "EUR";
postedAt: string;
status: "open" | "closed" | "disputed";
};
export function assertInvoiceRow(value: unknown): InvoiceRow {
// parse with your schema library of choice — fail the row, not the page
return value as InvoiceRow;
}Partial data belongs in the adapter, with an explicit empty or error state. Do not render undefined as 0.
Storybook is a gate, not a gallery
A dashboard story that needs a live API is a demo. A story with fixture rows, overflow labels, empty, and 400-row virtualization is a test you can run in CI.
Reviewers should ask: can I see the unhappy path without staging credentials?
Review for time, not pixels
The questions that catch real bugs:
- What is the timezone of
postedAt? - Does this total match the filtered set or the full set?
- If the refetch fails, do we keep stale data and say so?
Takeaway
A dashboard earns trust when every cell can explain itself: source, freshness, and failure. Type the contract, fixture the edges, and keep review focused on time and totals.