Ticket Backlog
Inflow vs outflow per week with the running open backlog, showing whether the queue is draining or growing.
Support backlog · 10-week trend
144
open tickets · 186 in / 225 out last wk
- Created
- Resolved
- Open backlog
Open backlog fell -21.3% WoW to 144 — driven by faster resolution.
| Week | Created | Resolved | Open backlog |
|---|---|---|---|
| Mar 30, 2026 | 164 | 178 | 204 |
| Apr 6, 2026 | 172 | 184 | 192 |
| Apr 13, 2026 | 179 | 186 | 185 |
| Apr 20, 2026 | 248 | 192 | 241 |
| Apr 27, 2026 | 256 | 201 | 296 |
| May 4, 2026 | 241 | 228 | 309 |
| May 11, 2026 | 228 | 239 | 298 |
| May 18, 2026 | 219 | 237 | 280 |
| May 25, 2026 | 206 | 234 | 252 |
| Jun 1, 2026 | 198 | 231 | 219 |
| Jun 8, 2026 | 192 | 228 | 183 |
| Jun 15, 2026 | 186 | 225 | 144 |
Jira Service Desk · synced hourly
Demo data is illustrative. Replace with your own typed data prop.
How it computes
Open-backlog flow: each week's backlog rolls forward by tickets created minus resolved.
backlogᵢ = startingBacklog + Σ₁ⁱ(createdⱼ − resolvedⱼ); WoW = (curr − prior) / priorAssumptions
- Starting backlog is given, not inferred.
- Weekly created/resolved flows are additive and independent.
- The most recent week drives the week-over-week read.
Honest about
- Backlog is allowed to go negative when resolutions outpace inflow — it isn't clamped, so the number stays honest.
- The week-over-week delta is divide-by-zero guarded.
- The driver read is binary (inflow outpacing vs faster resolution), not a decomposition.
Use it with your data
Data contract
Passed via the data prop — an object: validated at runtime, so a bad shape degrades to the error state rather than crashing.
| Field | Type | Required |
|---|---|---|
| startingBacklog | number | yes |
| weeks | array | yes |
Static props
import { SupportTicketBacklog } from "@/components/blocks/support-ticket-backlog/support-ticket-backlog";
<SupportTicketBacklog data={myData} />Client fetch (SWR)
const { data, isLoading, error } = useSWR("/api/metric", fetcher);
// route isLoading/error through <ChartStates>, then:
<SupportTicketBacklog data={data} />Server component (RSC)
const data = await fetch(url, {
next: { revalidate: 3600 },
}).then((r) => r.json());
<SupportTicketBacklog data={data} />Map arbitrary rows
import { mapRows } from "@/lib/sextant/column-map";
const out = mapRows(rows, { /* contractKey: "yourColumn" */ }, dataSchema);
if (out.ok) <SupportTicketBacklog data={out.data} />;Make it yours
Every customization below is an optional prop — omit them all and you get the defaults shown above. Recolor, reformat, restyle, or drop the card chrome without forking the component.
Recolor or rename a series (created, resolved, backlog)
<SupportTicketBacklog
series={{ created: { color: "var(--chart-3)", label: "…" } }}
/>Format numbers (currency / locale)
const eur = new Intl.NumberFormat("de-DE", {
style: "currency",
currency: "EUR",
notation: "compact",
});
<SupportTicketBacklog valueFormatter={(n) => eur.format(n)} />Replace or hide the narrative
<SupportTicketBacklog narrative="Your own one-liner." />
// …or hide it entirely:
<SupportTicketBacklog narrative={false} />Restyle any region
<SupportTicketBacklog
className="max-w-xl"
classNames={{ body: "bg-muted/20" }}
/>Drop the card chrome (headless plot)
import { SupportTicketBacklogPlot } from "@/components/blocks/support-ticket-backlog/support-ticket-backlog";
// Just the chart body — bring your own card/layout:
<SupportTicketBacklogPlot data={data} config={config} />