Jailson Brito
← Home

OnTracksy

Draws a timeline of how every ticket moves through your workflow.

A browser extension that draws a timeline of how every ticket moves through a workflow, so stalled work is obvious. Works with Jira, or standalone without it.

The problem

A ticket board shows status, not history. “In Progress” for six days looks the same as “In Progress” since yesterday.

OnTracksy renders each ticket as a lane, one segment per state, sized by how long it stayed there — a stalled ticket is visually obvious without reading fifteen tickets one at a time.

It doesn’t solve every kind of timeline. A trip itinerary, for instance, is one sequence of things happening one after another — a single track, nothing to compare side by side. OnTracksy’s value shows up specifically when several things are moving through the same set of states at once and you need to see them together: a sprint board, a hiring pipeline, a queue of support tickets. One track alone doesn’t need this; a dozen tracks changing state in parallel do.

It works two ways: connected to Jira, or fully local, with no login and no data leaving the browser.

OnTracksy's timeline view, showing twenty tickets as lanes with coloured segments for In Progress, In Review, and Blocked states across a two-week sprintOnTracksy's timeline view, showing twenty tickets as lanes with coloured segments for In Progress, In Review, and Blocked states across a two-week sprint

Approach and methodology

Standalone and Jira-connected were always meant to be one product, not two with a shared name — so the design question going in was how to support both without either mode becoming a second-class citizen of the other. The answer was pushing every tool-specific concern (auth, fetching, pagination) behind a single interface, and keeping the timeline-building logic on the other side of it completely ignorant of which mode is running. Architecture below shows the shape that produced.

Built solo over about four months, with dedicated accessibility and security review passes rather than something bolted on at the end. Development itself was agentic: the repo’s own process docs define a model-tiering scheme — a planning pass on a stronger model, an orchestrating pass on a mid-tier one, mechanical work on a faster one — plus named roles for specific jobs, like a dedicated code reviewer and a dedicated end-to-end spec author. Every change runs against the actual built and loaded extension through a Playwright/BDD suite before it counts as done, regardless of which tier wrote it.

Architecture

OnTracksy adapter architectureA framework-free core timeline engine sits behind a single adapter interface. A Jira Cloud adapter and a local-only static adapter both implement that interface, feeding the same timeline builder, rendered by one Angular Material UI layer shared by both modes.

libs/core — framework-free

TimelineBuilder

StateTracker

Jira Cloud REST API

JiraAdapter

Manually-entered data

StaticAdapter

ToolAdapter interface

Angular Material timeline UI
(shared by both modes)

OnTracksy adapter architectureA framework-free core timeline engine sits behind a single adapter interface. A Jira Cloud adapter and a local-only static adapter both implement that interface, feeding the same timeline builder, rendered by one Angular Material UI layer shared by both modes.

libs/core — framework-free

TimelineBuilder

StateTracker

Jira Cloud REST API

JiraAdapter

Manually-entered data

StaticAdapter

ToolAdapter interface

Angular Material timeline UI
(shared by both modes)

Both Jira-connected and standalone modes implement the same adapter interface, so one core pipeline serves both.

A Jira Cloud adapter and a local-only static adapter both implement one ToolAdapter interface, feeding the same timeline-building pipeline — that’s the whole trick behind shipping standalone and Jira-connected modes as one product instead of two. The shape that both sides have to satisfy, from the real interface (libs/core/src/models/adapter.interface.ts):

export interface ToolAdapter {
  getSprints(): Promise<Sprint[]>;
  getSprint(sprintId: string): Promise<Sprint>;
  getSprintTickets(sprintId: string): Promise<Ticket[]>;
  getTicket(ticketId: string): Promise<Ticket>;
  getTicketHistory(ticketId: string): Promise<Ticket>;
}

Trimmed to the data-shape methods — the real interface also declares authenticate and refreshToken, which imply an OAuth exchange. What actually ships rides the browser’s own Jira session cookie instead (see Limitations), so those two are left out here rather than shown and left unexplained.

Standalone Jira-connected
Data source Data you provide — a static, already-complete snapshot Jira Cloud REST API, fetched live
Login None Your existing Jira session cookie — no separate account
Updates None — a fixed point in time Polling (see Limitations — no webhooks)
Leaves the browser Never Only requests to your own Jira instance

No content script, either mode. The extension opens as a full browser tab, and Jira-connected mode requests narrow permissions at runtime rather than at install — avoiding the broad “read your browsing history” warning a content-script-based extension would trigger.

Results

The bet was that one framework-free core could serve two very different audiences — teams already living in Jira, and people who just want a private, local timeline — without becoming two separate products. That held: the standalone extension, the Jira-connected extension, and a Jira Marketplace app all run on the same core today.

None of the three has a public listing yet. The Chrome Web Store and Edge Add-ons submissions, and the Jira Marketplace listing, are release tasks still ahead — store assets, a business entity, and a few other non-code steps — not a code gap. Closed beta reflects that plainly: the extension works end to end, there just isn’t a public install link to it yet.

Limitations

  • Polling only, no real-time webhooks — a deliberate scope cut, not an oversight.
  • Two accepted accessibility trade-offs, both documented rather than silently shipped: the drag/resize handles on a timeline segment are pointer-only and marked aria-hidden rather than half-working with a keyboard; the lane list’s row/cell markup doesn’t sit inside a proper table/grid ancestor, deferred rather than rushed.
  • An API-key Jira auth path exists in the code but was never wired to a UI. The only authentication that ships rides the browser’s own Jira session cookie.
  • No Firefox support. Trello/Asana/GitHub adapters are anticipated by the interface, none implemented.

Work in progress

An Insights panel — flow metrics, time-in-status breakdowns — is fully built and sitting behind a feature flag, off by default.

The Jira Marketplace app is far along but hasn’t had a formal “done” pass yet.

The remaining work is mostly the non-code kind: store listings, a registered business entity, and the paperwork a Marketplace vendor account requires — the checklist Results points at, not another feature.