Case study · Reporting cluster

Query Builder

Self-service reporting on a modernizing data platform

Context

Query Builder was the self-service reporting experience for the newer, modernizing data platform at athenahealth. Where the legacy reporting library gave users access to standard and saved reports, Query Builder gave them the ability to construct reports themselves — selecting the data fields they wanted, defining the filters that narrowed the view, and running the resulting query.

The users were experienced with reporting but not with data platforms. The design had to make constructing a query feel like a reporting activity, not a database activity.

Query Builder was one of my first pieces of work on the reporting product line. It also became the surface where cross-team design collaboration with adjacent product-line teams shaped the direction.

Visual — Query Builder in context
Query Builder in context — self-service reporting alongside the legacy library and the newer data platform.

Role

Lead UX/UI Designer, sole designer on Query Builder. Product ownership sat with Product Management. My work went beyond receiving requirements — SME conversations, problem framing, interaction design, cross-team alignment, RITE-based validation.

My manager was a thinking partner and, during the later platform-adaptation work, a co-explorer as we both learned the newer platform's capabilities and constraints.

Starting point — a direction I wasn't convinced by

A design direction for the query-configuration experience existed before I joined. I wasn't convinced by it. I spent time with subject-matter experts, my product owner, my manager, and existing research to understand the actual pain points around constructing queries. The problems users described were more specific than the prior direction was addressing:

The through-line was reasoning-in-context. Users wanted to construct a query and evaluate the result within the same experience — not build a query, run it, discover it was wrong, and start over.

I developed a different interaction direction around that reasoning.

Interaction direction

The core pattern:

The mental model was: configure on one side, see the effect on the other, iterate against the live view. The pattern kept users' attention on the reporting question rather than on the mechanics of query construction.

Select Columns
Select Filters
Save Query Run Query
Available Attributes
Order
  • Order ID
  • Order Date
  • Order Status
Product
  • Product Name
  • SKU
  • Category
Customer
  • Segment
  • Region
  • Tier
Metrics
  • Quantity
  • Revenue
  • Discount
Selected Columns · Drag to reorder
  • ⋮⋮Order DateRemove
  • ⋮⋮Product NameRemove
  • ⋮⋮RegionRemove
  • ⋮⋮QuantityRemove
  • ⋮⋮RevenueRemove
Preview
10 of 342 rows · updated on run
Order Date Product Name Region Quantity Revenue
Jul 3, 2026Studio ChairWest2$540.00
Jul 5, 2026Loft DeskCentral1$389.00
Jul 9, 2026Studio ChairNorth4$1,080.00
Jul 12, 2026Reading LampWest3$207.00
Jul 15, 2026Oak SideboardNorth1$1,240.00
Jul 18, 2026Loft DeskSouth2$778.00
Jul 21, 2026Reading LampCentral5$345.00
Jul 24, 2026Studio ChairWest1$270.00
Jul 27, 2026Oak SideboardSouth2$2,480.00
Jul 30, 2026Loft DeskNorth3$1,167.00
Select Columns · Reconstructed interface using synthetic data. No original customer data shown.

Complex filtering and configuration

Filtering was where the interaction design got hardest — and where a single, uniform control would have been the wrong answer.

Some filter needs were simple: pick a value, apply a filter. Others were substantially more complex — different attribute types require different configuration controls to be usable. A date range needs a period selector. A categorical attribute needs a multi-value selector. Forcing every filter into one uniform control would either flatten these into an unusable lowest common denominator or force users through configuration steps that didn't fit what they were trying to do.

The interaction foundation was the same — searchable, categorized filter attributes on one side; configured filters on the other; results below — but the specific control used to configure each filter adapted to the type of attribute.

Select Columns
Select Filters
Save Query Run Query
Available Filters
Order
  • Order Date
  • Order Status
Product
  • Category
  • SKU
Customer
  • Region
  • Segment
Metrics
  • Revenue Range
Configured Filters
Order Date
Remove
From Jan 2026 To Aug 2026
Product Category
Remove
Furniture × Lighting × Décor × + Add value
Customer Region
Remove
North × West × + Add value
Preview
8 of 47 rows · filters applied
Order Date Product Name Region Quantity Revenue
Feb 14, 2026Studio ChairNorth2$540.00
Mar 6, 2026Reading LampWest4$276.00
Apr 2, 2026Reading LampWest3$207.00
May 11, 2026Studio ChairNorth1$270.00
Jun 19, 2026Loft DeskNorth1$389.00
Jul 8, 2026Reading LampWest2$138.00
Jul 24, 2026Studio ChairWest1$270.00
Aug 3, 2026Loft DeskNorth1$389.00
Select Filters · Reconstructed interface using synthetic data. No original customer data shown.

The reference shown here includes two of the control patterns that emerged from the design work: a period selector for a date attribute, and a categorical multi-select for taxonomies with a manageable list of values. Adjacent product teams later needed variations of this — including more complex Boolean-style composition, and a hierarchical multi-select for a domain-specific measure taxonomy with a much deeper tree structure. Those variations shared this same interaction foundation but used control types fitted to their domains.

The columns-versus-filters reshape

The most useful design realization came from working with adjacent product-line teams whose users had different data requirements from the reporting team's users.

My initial model had assumed the attributes users needed for output columns and the attributes they needed for filters came from largely the same set. It's a tidy assumption. It turned out to be wrong.

Some attributes were meaningfully filterable but not useful as output columns — they were how you narrowed the data but not what you wanted to see. Others were useful as columns but not as filters. Forcing them into a unified configuration model would have produced two subtly wrong experiences instead of one right one.

The design evolved. Column selection and filter selection separated into distinct workflows, while the broader interaction foundation — the configuration-to-workspace pattern — stayed intact.

That specific realization was the concrete instance of a broader shift I had to make in my own thinking: from "Query Builder is one unified configuration workflow" to "Query Builder is a coordinated set of distinct configuration workflows that together form one coherent experience."

Visual — Query Builder evolution
Before/after evolution: initial unified column+filter model → adjacent requirements exposing the assumption → revised model with separated Columns and Filters workflows sharing the same interaction foundation.

Cross-team collaboration

The query-configuration problem existed across multiple product-line teams at athenahealth, and organizational awareness of that overlap pre-existed my involvement. I co-led a cross-team design collaboration with a designer from an adjacent product line — both of us officially designated as design co-leads for the effort. We pair-owned the design direction, worked through UX-level frictions between ourselves before they surfaced to the wider group, and informed the broader cross-functional team.

We aligned on a shared interaction foundation for query configuration. We also deliberately chose not to standardize everything — three specific capabilities (Boolean-style filtering, hierarchical multi-select, and different entry points into the query experience across each product surface) were preserved as domain-specific by explicit agreement rather than by drift.

The deeper discipline this work asks of designers — the judgment about when to align, when to preserve difference, and what to reshape in your own solution — I've written about separately in Your Users Don't Care How Your Teams Are Organized.

For this case study, the outcome that matters most is that the interaction foundation was designed to hold consistency across surfaces without flattening the domain complexity each surface required.

Adapting through the platform shift

Partway through the work, the organization's analytics direction shifted toward a newer analytics platform. Rather than treating this as a rebuild, we made a deliberate design choice: the platform would be embedded within the athenaOne experience so that customers didn't have to leave the product they used every day to encounter reporting. The platform change would be technical, not experiential.

For Query Builder, this meant translating the interaction direction into the newer platform's capabilities. That translation was not free. The platform had strengths but also constraints — some interactions we had designed for could be achieved directly, others required working within the platform's out-of-the-box control set, and some required conversations with the platform vendor's technical team to identify how specific interaction needs could be met.

The technical collaboration I remember most concretely:

The design pattern held through the translation. What changed was implementation, not the underlying interaction model.

RITE validation

We tested the Query Builder direction through RITE usability testing.

The core interaction — the configuration surface, the workspace, the live-preview logic, the separated column/filter workflows — held up in testing. Refinements after RITE were mostly small: layout and spacing decisions to expose more filter controls within a single viewport, and adjustments that made the active-filter state easier to scan.

The design didn't need to be rethought. It needed to be tightened. That's what post-RITE iteration usually looks like when the underlying model is right.

Additional design context

Query Builder was also the surface for a specific user flow that connected reporting into the broader product experience: a user could land on an insights page, click a metric in a visualization, drill down into the underlying data, and open the drill-down result in Query Builder to refine the query further. The drill-down flow shipped first; the standalone from-scratch query-building experience followed.

The pattern was: reporting is not a destination users go to; it's a set of capabilities users reach for from wherever they are in the product. The Query Builder pattern needed to hold together whether it was reached from a metric drill-down, from a saved query, or from the standalone experience.

What I took from this work

Query Builder didn't have the same validated-but-not-shipped arc as Report Library 2.0 — the interaction direction carried forward into what production actually built on the newer platform. What survived was less the specific screens and more the reasoning-in-context pattern, the columns-vs-filters separation, and the cross-team consistency work.