Close
ThoughtSpot

Possibly the most complex problem ever solved by a fresher at ThoughtSpotmy first end-to-end feature

one liveboard
built once, parameterised Sales Overview {{Currency}} …
the publish engine this is the project
every org, in context
org · us $ 42.8k
org · emea € 39.4k
org · apac ₹ 35.2L
one liveboard in · a context-aware copy out, in every org · no files, no scripts, no tickets
scroll to enter the story
01 · context

Don't read dashboards. Just ask.

Every company keeps its numbers in a cloud data vault. What separates BI products is how answers get out.

ThoughtSpot's whole pitch: skip the queue and just ask.

The legacy school tableau · power bi · domo · sigma

Answers are built for you, a request, a queue, a specialist. Days, every time.

ThoughtSpot ask in english

Answers are pulled by you, type the question, the warehouse answers live. Two things make that possible:

① the plug Connection credentials + an address into the warehouse
② the translator Data model friendly names + formulas over raw tables, so english questions land
③ the payoff Liveboard the wall of live charts everyone reads
the whole story hangs on this chain.
the vocabulary

Five words. One stack.

Everything ahead is built from these five, and they stack in a strict order. Scroll to raise the tower, bottom to top.

  1. 01
    Warehouse

    The cloud vault where the company's data actually lives. It never leaves home.

  2. 02
    Connection

    The plug into that vault, credentials plus an address: which database, which schema.

  3. 03
    Data model

    A friendly map over raw tables, renames columns, adds formulas, so plain-english questions land.

  4. 04
    Liveboard

    ThoughtSpot's word for a dashboard: a wall of live, clickable charts everyone reads.

    just one object type, answers, tables, charts & spotter chats live here too. we're focused on liveboards.
  5. 05
    Org

    A sealed room inside one customer's ThoughtSpot, its own people, its own data, its own rules, wrapped around the whole stack.

thoughtspot analytics · for your own company

One company, its own analysts

A beauty retailer, a telco, a bank, slicing themselves into orgs: by region, brand or team. Their call, their count.

thoughtspot embedded · inside someone else's product

One SaaS company, its client companies

A hiring platform, resold: every paying client gets an org of its own, behind TalentIQ's buttons.

same machinery, higher stakes

Both run on the same quiet machinery underneath: orgs.

Sealed rooms,
locked drawers.

Every number drops through a stack of admin-controlled gates before it reaches a screen. Scroll to pull it apart, then hover a layer.

  • Orgthe sealed room
  • User groupa team in the org
  • Userone identity
  • Column securitywhich fields · cls
  • Row securitywhich rows · rls
the stack · five gates

Pick any layer to see the gate it controls, and who it lets through.

layer 01 · org

Walls off an entire market's people and data, nothing leaks between rooms.

layer 02 · user group

Grants a whole team access at once, instead of person by person.

layer 03 · user

Every request carries one identity, who's asking decides what the layers below resolve to.

layer 04 · column security · cls

Hides whole fields, cost, margin, PII, from the wrong eyes.

layer 05 · row security · rls

Narrows the same board to only the rows you're cleared for.

The walls are the feature. Sharing across them is this story.

02 · the problem

One Liveboard. Eighteen orgs. No button.

Meet a global beauty retailer, eighteen orgs, one per market, and you'd guess the name. Analysts in the US org build a Liveboard called Sales Overview, and it's good. Word travels faster than walls.

emea org · 9:04 am

“can we get Sales Overview in our org?”

apac org · 11:32 am

“same board, please. in ₹.”

latam org · 2:15 pm

“us too, and our fiscal year starts in feb.”

+ fifteen more
us org · the original Sales Overview $ 42.8k
emea org · imported as-is Sales Overview points at = us vault ✗ wrong data currency = $ ✗ paris reads dollars rows = us rules ✗ wrong eyes confidently wrong
no “move” button, export tml → import → still wired to the source org.

An imported copy says the same everywhere. The board has to mean the same.

So the US admin files a ticket. Then another. Every rollout meant chasing the SRE and data-maintenance teams to wire it up by hand. In 2025, that was the only path:

the entire cross-org workflow, 2025:

Raise a
ticket.

then wait on the sre & data teams to wire it up

Every one of those rollouts landed on the same desk. Publishing across orgs wasn't self-serve, so week after week, the requests piled onto ThoughtSpot's own SRE and data-maintenance teams.

the weekly inflow
TICKETpublish “Sales Overview” → all orgs TICKETre-map connection for EMEA org TICKETboard broke after model update TICKETre-point APAC schema TICKETroll new KPIs to 12 orgs
stacking every week
one small team
SRE + data maintenance stitching each publish by hand, running scripts against a set of broken, disconnected APIs, one org at a time
hours drained each week queue that never emptied 0 of it their actual job
no publish button, scripts and disconnected APIs, over and over.
a customer's own words

“An ugly solution… not repeatable… incoherent.”

That's a customer who had developers to burn on scripts. Teams without them exported and imported files, org by org, by hand. One team even had an AI build them a rollout tool, it broke too.

Cross-org sharing ran on exports, scripts and patience, invisible, fragile, never built for humans.

so, the brief

Build once, publish everywhere, from a screen, not a script.

october 2025 · green-lit as top priority

The fix is older than software: the HQ report.

one report, written once

Revenue: {{currency}} 4.2m
Quarter starts: {{fiscal}}

one row per office
London · £ · Jan Tokyo · ¥ · Apr São Paulo · R$ · Jan
every desk, localised

In ThoughtSpot the placeholders point at data. Swap one, and the same board reads a different org's warehouse. That's the whole mechanic.

Sharing without placeholders is photocopying. With them, it's translation.

what you sent Liveboard lands in the emea org, opens, and points at… arrives dead
Data model …a model that isn't there…
Connection …and a warehouse it has no route to
a board never travels alone, its model and connection go with it, or it lands dead.

Three moves, and that's the whole system. Chapter 04 walks all three as real screens.

01

Variables

name what changes per org, then map one value to each.

{{currency}} → $ · € · ₹
02

Parameterise

swap every hardcoded value in the object for its slot.

curr = {{currency}}
03

Publish

push once; each org opens it resolved to its own context.

✓ 18 orgs, in context

Slot by slot, someone turns the US org's copy into the company's template. Slow, careful, human work, done once. Then a publish looks like this:

the template · written once Sales Overview
currency = {{currency}}
schema = {{schema}}
rows = {{row_rule}}
US org
Sales Overview $ 42.8k
us_salesus stores only

Everything so far was one company sharing inward. ThoughtSpot's other business, Embedded, resells the same engine: each paying client company is an org of its own.

And the ground shifts. Internally, every org sits on warehouses the same company owns. In Embedded, every client brings its own account, its own credentials, a warehouse the platform doesn't control.

internal · thoughtspot analytics

Orgs sit on warehouses you own

embedded · every client an org

Each client brings its own warehouse

So a variable couldn't just swap a value, it had to swap the whole warehouse under each org. Screens cover a handful of orgs; for platforms running hundreds, I scoped the same flows as APIs for embed developers. Same idea, stretched to its limit.

where my part begins

The fun part:
nobody knew how it worked.

Half the project happened before a single screen. “Just add a publish button” hid weeks of untangling: what depends on what, what connects to what, whose journey runs through it.

The dependencies board → model → connection → warehouse, and everything that breaks up the chain.
What connects to what variables, orgs, schemas and rules, mapping every wire before drawing one.
Whose journey it is admins, analysts, embed developers, each needing a different door into the same engine.

My first full feature here, owned end to end, and the gnarliest on the board. next: actually untangling it. →

03 · the process

Untangling it

Here's the uncomfortable part: this problem exists only inside ThoughtSpot. Orgs, variables, parameterised publishing, no competitor to reference, no pattern library to borrow from, no “how X does it” deck. Nobody had drawn this map before.

With no reference, the process had to manufacture certainty.

nobody had drawn this map, so…

Where do you even start?

So the process itself stayed almost boringly simple, five moves, in order. The first three set the rules of the game. The last two were the quarter.

move 01

Cut it into flows

use case → stage → journey, for every path through the feature.

move 02

Stories & scenarios

who wants what, and why, covering every finalised flow.

move 03

Sign the tenets

principles set with stakeholders, the project's constitution.

move 04

Draw the system

flowcharts of every case, decision and dead end. many versions.

move 05

Make it real

vibecoded protos · blockframes · hi-fi, shown, torn up, rebuilt.

First I cut the project into five flows. Each had to name its use case, its stage and whose journey it was before it earned pixels.

flow 01

Create variables

name what changes per org; map one value to each.

starts in: data workspace
flow 02

Parameterise

swap the hardcoded values in a model or connection for slots.

starts in: model · connection
flow 03

Publish

push a board and its whole chain to chosen orgs.

starts in: the object itself
flow 04

Update

the board changed, roll the change to every org it lives in.

starts in: a published object
flow 05

Unpublish

pull it back out, without silently breaking anyone.

starts in: a published object
where a flow starts dictates its touchpoints.

Then I drew the machine itself, every use case, every decision, every dead end, and walked it with eng, PM and the field. One argument kept redrawing the map:

Which comes first, the variable, or the publish?

the tidy theory · setup first create variables parameterise the model publish how data teams describe the work, when you ask them in a meeting
the observed reality · publish first start a publish hit a missing variable create it in-flow finish the publish how admins actually behave, the publish is the errand, everything else is a detour
design decision

Model it variable-first, but let the publish create one in-flow. The system stays coherent, and nobody has to prepare before they're allowed to act.

That settled the rest of the machine. Four charts followed, each argued over before the next began.

four working files · the detailed flowcharts

what all that drawing actually settled
The variable comes first.

Objects are downstream of what changes per org. Get that order wrong and every screen after it argues with itself.

Charts find the exits, not the happy path.

The unpublish tree was drawn last and argued over most, because the destructive cases are where a system quietly loses trust.

Three doors, one loop.

People enter from wherever they already are. The entry can differ; the machine underneath cannot.

the way this team ships

The speed trick:
show it half-done.

Tight loops, one quarter, no reference product to copy. Engineers, PM, design and the field co-writing it in one room, so feedback landed while course changes were still cheap.

the pressure was real, and it was shared. next: the screens that came out of all this. →

04 · design

The screens

One admin, one morning, one errand, that's how we'll walk the screens. For the sake of a linear story she works top-down: variables first, then the model, then the publish itself.

monday, 9:12 am

Meet Sarah, platform admin at that beauty retailer from ch 02, the person who knows every connection string, schema and warehouse account by heart. Two liveboards, live in every market org by friday. It starts nowhere near a publish button.

the errand list create the variables← we are here parameterise the model publish everywhere

A new room in Admin. Not buried in a model, not inside a publish dialog, a first-class shelf, because variables outlive any single board.

The Variables page in Admin: a searchable table of variables with type, sensitive values, values assigned and last modified columns, and a Create Variable button
the list answers the admin's real question at a glance: what exists, what type, how many orgs covered.

Every variable is one purpose paired with one scope. Purpose is what varies, scope is who it varies for.

6 purposes · what varies
table mapping connection property time zone currency locale formula
4 scopes · who it varies for
org user user group object
9:12 am
create the variables parameterise the model publish everywhere

Watch the dialog reshape as you scroll, this is a multi-scope type, the ch 03 matrix made real. (The simpler single-scope kind comes right after.)

step 01 · name & purpose

The fork in the road

Name it, pick table mapping. Watch what's missing, no scope section at all. Table mapping is org-only by definition, so the form never asks.

step 01 · name & purpose

The fork in the road

Name it, pick a scoped type like time zone. A whole scope section unfolds mid-dialog, because this type can vary by more than org.

step 02 · scope

Decided for you

There is no step 2 here. Org is the only axis a table can vary on, so ThoughtSpot skips the choice entirely, one less decision to get wrong.

step 02 · scope

Who the value varies by

Sarah scopes it to org, and ticks sensitive information, values render masked everywhere, credentials never echo back to the screen.

step 03 · assign values

An honest empty state

The mapping table opens blank, org on the left, value on the right, one add row action. Nothing is pre-guessed; Sarah is the one who knows the warehouse map.

step 03 · assign values

An honest empty state

Same blank canvas, one extra column for scope. Nothing pre-filled, the tool waits for the person who actually knows the values.

step 03 · filled, per org

The table IS the variable

One row per org: coca cola → COKE. The same name resolving differently in every room, this little table is the whole idea, made editable.

step 03 · mixed scopes

Narrower scope wins

A column per axis: scope · who · value. The org says PRIMARY, but for Reshma specifically, RESHMA. The most specific scope always wins.

the other kind · single-scope

Some types skip the scope step entirely

A table-mapping variable is org-only by definition, so the form never shows a scope section. Same three beats, one fewer decision: pick the purpose, then fill the map, org by org.

Create variable dialog for table mapping, purpose selected, no scope section shown
01 · no scope section
Filled org map, one value per org
02 · one value per org

Get purpose and scope right and one governed board travels anywhere. No forks, no copies.

the shelf is stocked

Every value that varies now lives outside the board.

Not one variable, the exact set her two boards need across eighteen orgs. Each one a first-class object on the shelf, waiting to be wired in.

region_tabletable map · org wh_accountconnection · org report_tztime zone · org local_ccycurrency · org fmt_localelocale · user discount_capformula · org
up next · parameterise

Nineteen minutes, no script, no ticket. The variables sit on the shelf waiting, next, Sarah points the model's tables at them.

The shelf is stocked. Now Sarah points real fields at those variables, parameterising. Two things can take a variable, and where the difference lives decides which.

the logical layer

A table

Same warehouse, a different database · schema · table per org. The model stays one, the physical table it reads swaps underneath.

databaseschematable
the plumbing layer

A connection

Each org has its own warehouse, its own account, user, password, keys. The whole connection resolves per org.

accountuserpassworddatabasekeys
the rule of thumb

same warehouse, different table → parameterise the table.
a whole separate warehouse → parameterise the connection.

No new tool, no export. Select the table in Data objects, then hit Parameterise.

Data objects page with GIT_PR_COMMITS table selected and a Parameterise button

Every parameterisation is the same small loop, pick a field, bind a variable you already made, add another if you need it, repeat.

01
Empty Parameterise Table dialog with one blank Field name and Variable row
One blank row. Nothing pre-picked, so she never wonders what was decided for her.
02
Field name dropdown open showing Database, Schema, Table
Pick what varies. Only the three fields a table can actually take, database · schema · table.
03
Variable dropdown open with a search box and the list of created variables
Bind it. Every variable she made, searchable, never retyped from memory.
04
One row mapped: Database bound to a variable
Read it back. Field → variable, one line, before she moves on.
05
Three rows mapped after using Add another field
Repeat in place. + Add another field loops again without reopening the dialog.
design decision

The dialog only offers fields that can vary, and variables that already exist. Nothing gets typed by hand, so nothing can be spelled wrong at 3am in an org you've never opened.

up next · publish

The hard part is behind her. Everything that varies is wired. All that's left is to say where, and press publish.

This is the whole point of the project, and, if the model's sources are parameterised, it's the shortest screen in the story. Sarah did that work already, so publishing is now just: say where, press go.

An Apparel Tracker liveboard with the overflow menu open, showing Edit, Rename, Make a copy, Download PDF, Present, Schedule, Sync, Publish, TML and Delete, Publish is the target
no new destination to learn, publish sits in the same overflow menu as present, schedule and sync.

One screen does everything. Pick the orgs on top; the sources below tell you whether the board is ready to travel. That's it.

01
Publish Liveboard dialog: an org picker with a search box and a checkbox list, above a Parameterise sources section
It opens honest. Orgs (0) up top, the sources it depends on below, nothing assumed, nothing pre-ticked.
02
Four orgs ticked in the picker, Solidaris, Besins Healthcare, SymphonyAI and HIS, Orgs (4)
Say where. Tick the markets, or hit Select all. Four orgs today; it could be three hundred.
03
Parameterised sources expanded: HQ retail MG, Table 1 and Table 3, each with an Edit link; Unparameterised sources (0)
Sources, already green. 3 parameterised, 0 left. Anything unparameterised would land hardcoded, so it sits right here with an Edit.
04
The liveboard with a toast reading: Liveboard published successfully in 4 orgs
Press Publish. Live in all four orgs in seconds, each resolving its own currency, warehouse and context.
design decision

Cut a multi-step wizard down to one screen: orgs on top, readiness below. And that readiness list is also the fix list, so if something's blocking you, the fix is right there instead of another screen away.

Sarah's story was tidy. Plenty of admins hit publish and only then find work left, so the dialog lets them fix it without leaving.

01
Publish dialog with four orgs ticked and Unparameterised sources (4) expanded, Sales_MT, Revenue_MT and Table_field, each with a Parameterise link
Sources aren't ready. The list reads unparameterised (4), and each one carries its own Parameterise link, the same loop from earlier, nested right here. No export, no detour.
02
Back in the publish dialog: Parameterised sources (4), nothing left unparameterised
The count flips. Back in publish, the source revalidates and moves up, parameterised (4), none left to fix.
top-down

Set up, then publish

Variables and parameterisation done first; publishing is a formality. Fewer surprises.

bottom-up

Publish, then fix

Start at publish, resolve whatever's flagged inline. Fewer detours.

two doors, one destination, the flow was designed so neither order ever leaves you stuck.
the payoff

One press.
Live everywhere, in context.

Two boards, eighteen orgs, no files and no scripts. Because the values that vary were pulled out and the sources were parameterised, the last mile is a checklist and a button, the errand that used to book a week now closes before lunch.

variableson the shelf sourcesparameterised pick orgs · publish
errand · closed

Done before her coffee cooled. Two liveboards, live in every market, and Sarah never once opened a script, a file or a ticket.

Every publish implies an unpublish, and that's where the real design problems hide, you can now break work other people are standing on. Two cases, worlds apart.

simple unpublish a liveboard

Nothing leans on it

A board sits at the top of the chain. Pull it from an org and little else notices. Pick orgs, confirm, done.

the hard one unpublish a model

Everything leans on it

Models are the backbone, hundreds of objects read from them. Remove one and the blast radius is real. The user has to see it.

From the primary org, choose which orgs lose the board. The copy does the teaching, what travels out with it, and what stays.

01
Unpublish Liveboard dialog: an org picker with an info note reading Unpublishing the Liveboard removes its Models if no other objects use it in selected orgs
Pick the orgs. A quiet note explains the knock-on: its models leave too, but only if nothing else uses them.
02
Confirm dialog: This will unpublish the Liveboard from Solidaris; the dependencies will remain since dependents are built on top of them
Confirm. Dependencies stay put, they're built on top, not underneath. Low stakes, so one plain confirm is enough.

A model feeds hundreds of dependents across every org. Yank it and they all break at once, usually for people who had nothing to do with the decision. My job here: make the consequence visible, then make it a choice.

01
The GTM model page in the Data workspace, overflow menu open with Manage publishing and Unpublish
It starts on the model. In the Data workspace, Manage publishing → Unpublish, where the dependents actually live.
02
Unpublish Model, select orgs step, with a note: Unpublishing the Model will remove the underlying Tables and Connections
Pick orgs, and read the warning. The model doesn't leave alone; its tables and connections go with it. Stakes named up front.
03
Manage dependents: 203 dependent objects found on Model, in a table with type, name, org, author, last modified and views, plus an Advanced settings button
See the blast radius. Every dependent named, 203 of them, with owner and org. A list you can review, not a surprise.
04
Advanced settings: choose Do not delete dependents (break and show error) or Delete all dependents; an error message preview; notify authors and include custom message
Make the broken state a choice. Leave dependents in place with a clear error, or delete them, and notify the authors either way. The person deciding owns the fallout.
05
Unpublishing Model confirm: type DELETE in upper case to confirm
Gate the irreversible. An action this heavy shouldn't be one click, you type DELETE to prove you mean it.
06
Model unpublished from Solidaris toast on the model page
Done, per org. The model leaves that org, and everyone affected already knows why.
why this mattered most

At 300-org scale one quiet click can break hundreds of live objects for people who never touched it. So this flow refuses to be quiet: show every dependent, make the broken state an explicit choice, notify the humans who'll hit it, gate the point of no return. That's the line between safe at scale and not.

The whole system, what it builds, and what it safely takes down.

Top-down and bottom-up, one org or three hundred, every path drawn, and drawn to be safe. Which leaves one question: did it land?
05 · impact

The landing

Before the customer numbers, the one I'm proudest of: the whole system, publish, unpublish, parameterise, unparameterise and the variables admin surface, designed and handed to engineering in about four weeks.

design → handoff

Brand-new machinery underneath, a brand-new interface on top, drawn once, in one source-of-truth Figma file.

New concepts were being invented weekly, so speed was the constraint, and the edge cases still couldn't slip: five flows, every empty, loading, error and success state accounted for.
5 flowspublish · unpublish · parameterise · unparameterise · variables
1 filesingle source of truth
3 engineersbuilt straight from it

“When we decided to build the interface along with completely new machinery underneath, the mountain looked steep.”

engineering lead, looking back from ship day
oct 2025green-lit
26.2first beta
26.4variables live
26.6publishing live

The rollout that used to book a week now takes one to two minutes.

hours → 1–2 minto roll content out, after
322 orgsserved by one publish, no issues
variables created
438
values assigned
12,577
first 90 days · each variable gets used ~30 times over, they're lived in, not created-and-forgotten.

My first end-to-end feature ownership. What got noticed wasn't only the UX, it was the turnaround: on a project with constant pivots, a designer who could re-cut a flow overnight unblocked engineering instead of gating it.

Thanks for making quick changes whenever any UX change was required to unblock.

- the shipping engineer

Full of ideas and always ready to take on new challenges, took all the inputs and came up with great UX. Love the energy.

- the engineering lead

Publishing didn't stop at Liveboards, and it didn't stop at GA. Shipping the foundation kicked off a whole roadmap of follow-on work, still shipping on the same three-layer system:

after 26.6 · built on the same foundation
01 Unparameterisation The reverse flow, cleanly pulling a table, connection or object back out of the parameterised system.
02 Variables, refined Revisited the variable designs post-launch against real usage, sharper scoping, clearer states.
03 Beyond Liveboards Extended Publish to Answers, Charts and Spotter chats, not just Liveboards.
+ Still shipping More of the roadmap is being built on this same system today.