# Dashboard design guide

Start with [Dashboard Overview](examples/dashboard.html) or the [reusable card gallery](index.html#dashboard-cards). The example uses synthetic support data and the same local DM Sans fonts, semantic tokens, and controls as the rest of the design system.

## Recommended dashboard structure

1. **Header:** page title, a short scope description, selected workspace, and one primary action when needed.
2. **Filters:** explicit period and timezone. Separate draft filters from applied filters when multiple criteria are involved.
3. **Headline KPIs:** three or four metrics that answer the user's main operational question. Avoid filling the screen with unrelated counters.
4. **Analysis:** one primary chart and a supporting target or breakdown card.
5. **Operations:** queue status, recent activity, team workload/performance, and attention-needed items.
6. **Actions and health:** direct links to the next workflow and service health when it affects user actions.

The example provides period selection, four KPIs, a volume chart with a data table, target progress, queue breakdown, activity, team overview, quick actions, service health, and an attention card. Loading, empty, error, and retry are exercised through the Preview state control.

## Card selection

| Card | Use it for | Required context |
| --- | --- | --- |
| KPI and trend | One headline count/rate | Label, value, unit, comparison period; percentage points for rate changes |
| Chart | Change across a period | Axis/category labels, units, explicit period, accessible equivalent data |
| Target/progress | Progress toward a defined goal | Current value, target, percentage; progress is not a delivery guarantee |
| Status breakdown | Operational queue distribution | Category names and counts that reconcile with the relevant total |
| Activity | Recent events | Actor/action, time, timezone, and a route to deeper history when needed |
| Team overview | Work allocation or completion | Relevant metric, period, and a link to team details; do not imply personal ranking beyond the displayed metric |
| Quick actions | Common next steps | Clear verbs and actual navigation targets |
| Service health | Availability that affects workflows | Text status, scope, and freshness; never present synthetic state as live monitoring |
| Attention needed | Exceptions requiring review | Count, reason, priority, and a direct next action |

## Visual contract

Use 16px card corners, subtle borders, 24px padding (20px mobile), and 20px gaps. Header labels are 16px/24px at weight 600. KPI values are 32px/40px with tabular numerals. Body text stays 14px/20px; supporting metadata is 12px/18px. Keep DM Sans for the interface; code and signature previews retain their intentional special families.

Avoid coloring every trend green or red. An increase in created tickets is not automatically good; the example uses neutral comparison text. SLA changes are expressed as percentage points rather than relative percentages. Show the comparison period beside the trend.

On wide screens, use four KPI columns, a two-column primary analysis row, and three supporting-card columns. Reduce to two KPI/supporting columns at <=1100px and one column at <=640px. Keep the chart inside its card and provide the equivalent table. Never stretch a single card's title or number to fill unused space.

## Data and state contract

The selected period drives KPI values, chart values, target progress, queues, team figures, and attention counts together. Chart totals match created-ticket totals in the fixtures. Queue totals reconcile with the same period's created tickets. Historical activity and service-health examples are clearly labeled snapshots rather than live metrics.

- **Loading:** preserve the shell, show matching card skeletons, set `aria-busy`, announce once, and disable period changes until this preview finishes.
- **Empty:** explain missing data. Do not substitute zeros or show fabricated trends.
- **Error:** preserve context and expose Retry. The demo restores local data; production must reconcile actual request state.
- **Partial/stale data:** a production dashboard should mark affected cards and last-updated times independently. The example demonstrates whole-dashboard states; per-card asynchronous requests are an integration concern.
- **Permission limits:** do not fabricate restricted metrics. Use the access-required pattern and provide guidance without pretending to grant access.

## Integration checklist

Bind the same applied-filter object to all related queries. Define metric names, units, timezone, comparison windows, and freshness with the backend. Preserve API error/unknown states. Support cancellation or ignore stale responses when filters change. Authorize both data reads and drill-down routes on the server. Keep expensive polling visible and intentional.

These are local HTML patterns, not a production analytics backend. Refer to [GUIDELINES.md](GUIDELINES.md), [STATE_MATRIX.md](STATE_MATRIX.md), and [COVERAGE_AUDIT.md](COVERAGE_AUDIT.md) before extending them.

## Reporting workspace

Open [Reporting & downloads](index.html#reporting) or scroll to reporting in [Dashboard Overview](examples/dashboard.html#reporting). The support overview and delivery report are separate demonstration domains, with separate filters and explicit units. Do not compare their counts. Reporting contains eight charts, three summary cards, per-chart data tables and download controls, a full-report CSV, print layout, and recent downloads.

### Choose a chart for the question

| Pattern | Question it answers | Rules |
| --- | --- | --- |
| Line | How do sent and delivered counts change over time? | Chronological x-axis, count y-axis, distinct line styles; keep gaps for genuinely missing observations |
| Area | How much has accumulated during the period? | Start at zero, label the running total; never imply that cumulative values are daily values |
| Grouped bar | How does this period compare with the previous period? | Same metric/unit, equal-length comparison windows, shared zero baseline |
| Stacked bar | What makes up each channel's total? | Mutually exclusive categories; delivered + failed = sent in this fixture. Round only the overall bar silhouette; internal joins stay flat and gap-free |
| Donut | What share belongs to each channel? | Few categories, visible total and labeled counts/shares; table preserves exact counts despite rounded percentages |
| Horizontal bar | Which campaigns have the largest delivered volume? | Sort descending, retain full labels, zero baseline; this is volume, not causal performance |
| Heatmap | Which weekdays and hours carry volume? | Explicit timezone, consistent scale, exact values in cells and a data table; color is supplemental |
| Funnel | How many messages reach each successive stage? | Nested cohorts; sent ≥ delivered ≥ opened ≥ replied; label the denominator for every percentage |

Avoid 3D charts, dual axes with unclear units, too many donut segments, or unlabeled gauges. For a new report, prefer a table before adding a chart that does not answer a distinct question. Backend timestamps, cohorts, channel-specific delivery/open semantics, unique-user versus message counts, and delayed events must be defined before using these patterns with production data. “Opened” is illustrative across these channels; do not assume every channel supplies that event.

### Filters, calculations, and table alternatives

The example ends on **25 October 2026**, with explicit ISO dates in the report. Last 7/30 days refer to that fixed synthetic snapshot, not today's date. Channel/period changes immediately update every reporting chart and summary from the same local rows. Comparisons use the preceding equal-length period with the same channel filter. The timezone is Asia/Jakarta. The delivery rate is delivered ÷ sent; open rate is opened ÷ delivered. Funnel percentages use sent as their denominator. Zero denominators must show unavailable rather than an invented percentage.

Every chart includes a native disclosure containing a table with caption, column headings, and row headings. SVG titles/descriptions provide a summary; the table supplies exact values and units. Line styles, explicit labels, and tables supplement color. Reporting charts expose hover and keyboard values. The separate Report drill-down specimen uses named metric and bar buttons to filter detail rows and save a local report definition; the original eight chart cards retain their download-focused behavior. Chart cards use two columns above 800px and one column below, with horizontally scrollable tables inside the card.

### Downloads and printing

- **Full report CSV:** exports all rows for the selected period/channel, not just a visible table page. Includes date, channel, campaign, hour, sent, delivered, failed, opened, and replied. Metadata rows state the period, timezone, channel, and synthetic-data provenance.
- **Per-chart CSV:** exports the exact aggregate behind that chart with the same metadata. Values remain unformatted numeric fields; human-friendly separators are only for on-screen summaries. CSV uses UTF-8 BOM, CRLF, quoted/escaped fields, and formula-prefix neutralization for text.
- **SVG:** editable vector of the chart with title, units, series legend, date range, channel, timezone, and synthetic-data label. It references DM Sans; the font is not embedded. External editors need DM Sans installed to reproduce typography exactly.
- **PNG:** 1040 × 860 image with the same export context. Labels are drawn using the loaded local DM Sans font, so the bitmap keeps its appearance without requiring the recipient to install fonts.
- **Print / Save as PDF:** opens the browser's print dialog with a light-theme reporting layout and expanded data tables. The user chooses a printer or Save as PDF. This is not a server-generated PDF export or a silently downloaded PDF file.
- **Recent downloads:** up to ten files held in this tab's memory, with Download again and Remove. Entries retain their original filter context after current filters change. Reloading loses the list. Object URLs are revoked on eviction/removal/page exit. A download request does not confirm a successful save to disk.

Chart export locks chart controls while generating; failures announce a retry/CSV alternative. Loading, empty, and unavailable reports disable new exports and hide stale charts. Previously generated files remain labeled and available in local history. Production export endpoints must enforce authorization and filter scope independently, define CSV schemas, and document size limits, expiration, asynchronous processing, cancellation, and failure recovery. Schedule, email delivery, and large server-side export jobs are integration work, not simulated promises in this kit.

## Motion and exact values

Reporting charts and the support ticket-volume chart now share `chart-interactions.js`/`.css`. Hover or tap a mark to read its exact value; keyboard users Tab to a chart and use arrows or Home/End. Escape closes the value tooltip. The semantic tables remain available. Short entrance motion runs when a chart enters view and after filter changes, with reduced-motion support. Stacked segments animate together. Local CSV/SVG/PNG and print output retain final values and omit tooltip/highlight decorations.

For compact dashboard navigation, the catalogue's Top navbar & menu bar section includes a single-row header with the identity and page destinations together. It collapses to Menu at 1100px; the separate two-row variant remains available for wider identity/action content.

The navbar gallery includes a left-aligned page-menu variant with account actions on the right, a profile preview, and local logout/sign-in states. Sidebar items also demonstrate expandable groups. Navbar controls share a 44px height, including Notifications. Catalogue search provides dropdown destinations without hiding any menus or sections.

The operational catalogue now includes advanced table editing/columns, saved views, CSV import, jobs, permission review, approvals, recurrence, report drill-down, content versions, Kanban, integration operations, settings and recovery patterns. See [Operational workflow patterns](OPERATIONAL_PATTERNS.md) for scope and limits.
