ഇvana sajan pallivathukkal
vision's payments record with its surfaces laid around it: the view switcher and filter rows above, the cohort filter open across three courses, a modal setting slack access for several learners at once, a row's action menu offering change cohort, assign unit, re-sync and remove access, and a selection bar reading ten selected

internal tooling · airtribe

vision

the whole company's payments ran through a google sheet. moving them into airtribe's internal sales and operations product, in three phases, without the sheet ever going dark.

role
product designer
team
four: two product designers, one backend, one frontend
context
airtribe · internal sales and operations
year
2026

product thesis

every enrolment, instalment and refund the company took lived in one google sheet, and finance, delivery and onboarding all read from it. the brief was to replace it. the harder fact was that nobody was unhappy with it: it was fast, it was visible, and it had never once asked anyone for permission.

role and ownership

two product designers ran this end to end. i took the ground research, the problem framing, the conversations with every team that touches a payment, and the design decisions below; we split the ui screens, and the other designer led the handoff. one backend and one frontend engineer alongside. no researcher and no ux writer, so the column list, the payment states and the dropdown copy are decisions rather than inherited requirements.

vision is airtribe's internal operations dashboard, none of it learner-facing. payments sit at the seam: sales records what a learner paid and how, and enrolment, slack access, onboarding and invoicing all key off that record.

the question

what does a product have to do before someone gives up a spreadsheet they trust?

the sales sheet the product replaced, with every cell's contents redacted: columns of struck-out rows, cleared payments banded in green, refund flags cutting across in red
the sales sheet, redacted. green is a cleared payment, red a refund flag, and that is the only thing in the file findable at a glance.
the onboarding sheet: a legible header row of close to thirty column names above rows of colour-coded cells whose contents have been destroyed
the onboarding sheet, redacted. close to thirty columns for one person, two adjacent and both called remarks, one called problematic leaner, spelled exactly like that.

what the decisions were based on

primary research with the teams

sessions with the sales and lxd people who lived in the sheet, before anything was designed. the column list came out of those, not out of the schema.

clarity session data

how people moved through the existing screens rather than how they described it. this is what made the filter overflow visible before anyone complained.

algolia search data

what people searched for, which told us which fields were being filtered by hand because no filter existed yet.

testing with the same people

every phase went back to the teammates who would use it. onboarding changed most: unused columns were deleted, and several that were really a sequence of tasks became a checklist.

the decisions that shaped the screen

01

a table, by default

why

the sales team had spent years in a grid. opening on cards or a form would have made every one of them slower on day one, which is when a replacement earns trust or loses it.

tradeoff

a table is the least forgiving layout there is, and it commits you to solving density everywhere else: filters, views, permissions, overflow.

result

nobody needed a re-learning period. the work went into making the table hold more than a sheet could.

the payments record in vision: a view switcher reading all and onboarding, four rows of filters, and a table of payment rows with inline track dropdowns
02

views instead of one table

why

by phase 3 a payment carried slack access, dashboard access, an lxd comment and the onboarding sheet as well. one table meant both teams scrolled past two thirds of it to reach their own third.

tradeoff

views split a shared surface, and a shared surface was half of why the sheet was trusted. so they overlap deliberately, and an all view stays available.

result

sales, lxd and all, with the columns inside each one governed by role and permission rather than by preference.

a payment row's action menu open on re-sync, move enrollment, assign unit, re-register payment and delete, with delete set apart in red
03

friction proportional to consequence

why

a typo in a comment costs nothing; a change to a payment status moves money and triggers access downstream. a spreadsheet treats both identically.

tradeoff

every piece of friction is a slower edit for someone who knew exactly what they were doing.

result

each column is either directly editable or behind an action button that names what is about to happen, and that menu is role-dependent. change logs sit alongside, so a row can be asked who last touched it.

the re-register payment dialog, step one of two: the lead and payment date fixed at the top, then agent, total sale value, payment type and cohortthe logs panel over the payments table: every change by date, who made it, the field, and the old value struck through beside the new one

an action that says what it does

re-registering a payment moves money, so it is a dialog in two steps: the details, then the date it should count for. the lead and the original payment date stay pinned at the top, where they cannot be edited by accident.

who touched it, and what it was before

every change to the table, searchable by lead and filterable by agent, field and date. the old value is struck through beside the new one, so a disputed row is answered in one look rather than a slack thread.

the onboarding view: a different filter set and a different column set, with a row's action menu open on change cohort, assign unit, re-sync and remove access
the same rows under the other view. onboarding gets its own filters and columns, career service, ctc, profile, the two track assignments, and none of the payment machinery it never touches. that is where the scroll went.

three phases, in the order they shipped

  1. phase 1 · the sales sheet

    the payments record, moved into vision as a table.

    sales first, because it is the team that creates the record rather than one of the teams that reads it

  2. phase 2 · widened for lxd

    a confirmed lead goes to lxd for final payment, slack access and dashboard access, so the record widened to carry them.

    this is why a payments row now holds an lxd comment and two access states: the sheet had already put them there

  3. phase 3 · the onboarding sheet

    onboarding folded in on the same pattern, and the combined table became too long to be one table.

    this is the phase that produced views, and the phase where testing deleted columns rather than adding them

scroll the run →

staged rather than migrated at once. the sheet was live money the whole time.

what one payment record has to hold

a payment is an amount, the instrument it arrived by, where that instrument is now, and what each downstream team may do next. the statuses are not a pipeline, they are the states a real payment gets stuck in. the row spans sales, finance and delivery, for people who each care about a third of it.

paid in one shot
→ cleared, or still pending verification
part payment
→ part paid by airtribe, or awaiting the rest
credit card, no cost emi
→ will pay by credit card, then cleared
credit card, cost emi
→ same path, different maths
loan, no cost emi
→ pushed for loan, documents, approval, disbursement
loan, cost emi
→ or rejected, which is its own state and not a failure of the form

it also carries slack access, onboarding status, an lxd comment and dashboard access. phase 2: other teams' columns inside a sales record, because that is where the sheet had put them.

measure

  • payment types6
  • payment statuses11
  • fields on the record~18
  • teams reading the same row3

the decisions the screen had to make

constrain anything with a definitive answer

every field with a finite set of correct answers became a dropdown. this is what made filtering possible at all: you cannot filter a column eleven people have spelled eleven ways, and the sheet had several.

colour is for spotting, not reading

only the anomalies carry colour: likely to refund, confirmed but not paid, loan rejected. the ordinary states do not, because if everything is coloured nothing is.

sync is a state, not a success message

reconciling with the sheet resolves six ways: created, pulled in, already in sync, not found or not permitted, failed, or ambiguous. ambiguous is the one that matters, because a person at 6pm has to be told which record they are looking at and which they are not.

a rejected loan is a state, not an error

loan rejected, access removed, awaiting documents and waiting for disbursement are ordinary places a payment sits. as error states they would say the agent had done something wrong.

the same learner, twice, on purpose

a learner who re-enrols is a second payment record, not a correction of the first, so duplicates by name are legitimate and cannot be merged away. the latest carries a live badge; the older ones stay readable.

the same name leads two different places

the same lead opens the opportunities page for sales and the learner profile for lxd. the row is shared; the job you are doing with it is not.

the flaw we shipped

first direction

a name and an email are never read apart, so we merged them into one cell: name on the line, email as a subline. it tested well with the sales team and gave back a column on a table that needed the room.

what happened

it broke a workflow nobody had shown us. the people granting slack access take the whole column at once: one drag, about five minutes for a cohort. as a subline there was nothing to select, so it became copying by hand, about fifty minutes. we had researched the team that writes the record and missed the team that reads it a hundred rows at a time.

what changed

the email came back out as its own column, and the rule came with it: a column is not a field, it is a workflow. every merge candidate now gets a second question, not is it read beside its neighbour, but is it ever selected, sorted, exported or copied alone.

rows selected across the table, a bar reading ten selected with copy ten emails and update slack access, and the dialogue that collects the selected addresses as chips
the repair. select the rows, take all ten addresses in one click, or set slack access for all of them in one dialogue. fifty minutes of copying is now the fastest path in the product.

filters, and a chicken and egg problem

an opportunity carries about twenty five fields across three lifecycle axes people mistake for one: a status, a stage, and a separate lead status. showing all of them was the overflow; burying them two clicks deep would have made the product slower than the sheet at the task the sheet was worst at.

so the filter set stopped being fixed. a new user gets recommended filters, then the bar shows what they last used, and the rest expand in place. a combination worth keeping becomes a named view. search gained include and exclude, to stop a query quietly returning the wrong queue.

the old filter bar: twenty-nine filter controls wrapping onto four rows
before. twenty-nine filters over four rows, between the search box and the table they govern, and the same twenty-nine for everyone.
the new filter bar: nine filters over two rows, four of them active and showing their values, with more filters, save filter view and a saved view selector
after. nine, and they are this person's nine. an active filter prints its value and counts the rest, so the bar states the query rather than the fields. the other twenty expand in place.

email templates, for managers and agents

the same product, a different muscle. templates are what the sales team sends from, and the design question is not the editor, it is the line between the two roles: what a manager can author and what an agent can only send. it is the same question the permissions work below asks at the level of the whole product.

who is allowed to see what

almost nobody should see the whole row, so access runs on four axes that are deliberately not the same thing: department, role, permission group, and who you report to. a title is not a permission.

permissions are namespaced into eleven categories and compose into named groups rather than being handed out one at a time. it took the longest to argue for, and it is what makes every other decision on this page enforceable: views, editable columns and the action menu all read from it.

the team members table: department, role, manager and permission group as four separate columns, with a row's action menu open on edit, login as, block access and remove
four columns because they are four separate questions. six of the eight rows here carry a role and a permission group that do not match. blocking and removing are different things, which matters when somebody leaves and their records must not.
building a permission group: a category sidebar, namespaced permission checkboxes, and a review dialogue listing every permission selected before the group is created
opportunity management alone holds ten permissions, through to manage descendant's opportunities, which reads the reporting line to decide whose records you can touch. the group is listed back in full before it exists, and again before anyone is given it.

a spreadsheet's real advantage is not that it is flexible. it is that nobody has ever had to ask it for permission.

outcome

the sales sheet is no longer the source of truth. three spreadsheets across two departments are now one table carrying the whole lead lifecycle, first payment through to onboarding into the lms. all three phases shipped, alongside the email template flow, the cohort filter and the filters and search redesign.

views and role-based permissions cut scroll depth in half, and accidental edits dropped once a row could be asked who last touched it. the sales team moved off the sheet with no re-learning period. onboarding ended with fewer columns than it started with. the one workflow the design broke, bulk-copying emails, went from five minutes to fifty before it was caught.

want the full story?

the rest of vision, the opportunities pages, the learner profile, the email templates and the permission work, sits behind an airtribe nda, as do the research sessions and the phases that were tested and cut. i can walk through it privately.

reflection

the first phase went on matching the sheet rather than beating it, and everything after on the two things it structurally could not do. i think that order was the whole job. the sync states are the proof of how long it takes: the product had to say already in sync for months before anyone agreed it was the source of truth.