Case studies / Tigg Accounting · Design before Jun 2026; build Jun – Sep 2026
Repair supported import errors in Tigg, before posting
Tigg's old importer listed errors by row number and offered one way forward: fix the file in Excel and upload it again. I designed a replacement where people map their own columns with the gaps shown, then fix, filter and bulk-edit rows in a grid before anything is posted.
Role
Timeline
Team
Platform
Not mine
Measured outcome
the key decision
Block Next on the unmapped field itself, then repair typed cells in a grid, so supported errors are fixed in Tigg instead of back in Excel.
how deep do you want to go?
Row 14, somewhere in Excel
A distributor sends a sheet of 42 delivery lines. Someone at the shop has to turn it into delivery notes in Tigg. With the old importer, they downloaded a template, copied the data into it, uploaded it and waited. The screen then said something like 38 records validated, 4 records have errors, and printed a list:
Row: 14 Rate must be a number
Row: 22 Warehouse not found
The only ways forward were Confirm Upload and Reupload New File. To fix row 22, you left Tigg, opened the file, found the row, guessed what "not found" meant, saved, uploaded the whole file again, and had every row checked again.
The bad part wasn't the error messages. The file was the only place anything could be fixed. So the question I worked on was where repair should happen, not how to word the errors better. My answer was a workspace inside Tigg: upload once, map your own columns with the gaps shown, then fix, filter and bulk-edit the rows in a grid before anything is posted.
My part, and the part I didn't build
This is a design-only case. I'm the only UI/UX designer at Tigg (BIC Technology). For bulk import I did the market research, ideation and interaction design, and drew every state on two Figma pages in the file "Tigg New Features":
- 🟢 Bulk Import: the final design, marked Ready for dev.
- 🔴 Bulk Import: an archive of ideas I explored and kept because they might be useful later.
Both pages were finished before the build began on 2 June 2026.
The senior frontend engineer built the whole frontend: the upload drawer, the mapping page, the editable grid, and how an import stays alive between edits. The backend team built the service behind it; the CEO owns the product; QA tests releases. Wherever this case says "the build", it means the senior frontend engineer's work, and decisions my frames didn't cover are credited to them.
- Jun 2025Additions to the old importerAs an intern I added a few import types to the older importer: my only code in this area.
- Before 2 Jun 2026Design: 🟢 final page and 🔴 archive
- 2 Jun 2026Build begins (senior frontend engineer)
- 20 Jul 2026Tagged releaseDelivery Note and Goods Received Note import.
- 4 Aug 2026Tagged releaseInventory Adjustment import, on the same pages.
- Sep 2026Product/Service import on UATBuilt on the same pattern. Not in a release tag yet.
What I knew, and how
The research was small and practical.
- Inside the old importer. In June 2025 I added Product Category, Account Group and opening-balance import to it. Looking back, every template I added was another fixed header contract, and every error another line in a Row: N list.
- Problem signals from QA, support and the CEO, which is how user problems mostly reach me at Tigg. Second-hand, and not logged as import tickets.
- Market research and ideation. This is where editing in a spreadsheet-like grid came from. I didn't keep a record of the products I looked at then, so I don't name them here.
I didn't run interviews or usability tests, and there was no data on import failures. The comparison below was done later, in September 2026, from public help-centre documentation, to place the design in its market. It is not what I studied at the time.
Mapping columns is standard. Repairing values inside the product is rare in accounting software; it's mostly dedicated import tools that let you edit a cell, see it re-checked and fix many rows at once.
Where an import actually fails
"Bad UX" was my own summary of the old importer. Looked at closely, it had five separate causes, and each needed a different fix.
| Cause | What it did to people | What the design had to do |
|---|---|---|
| Fixed header contract | A sheet headed "Item", "Qty" or "Godown" failed, or had to be reworked to match the template first | Map their columns to Tigg's fields, and suggest matches |
| Errors cut off from the data | A list keyed by row number; the value itself was in another program | Put each error on its cell |
| No partial progress | Nothing survived between attempts | An import you can leave and come back to |
| No repair tools | One wrong warehouse across 40 rows meant 40 edits in Excel | Select, filter and change many rows at once |
| Hidden, settings-dependent rules | Whether location or warehouse was required depended on the organisation's settings, which a fixed template can't show | Show what is required for this organisation, while mapping |
Two facts about the data shaped everything else.
- The required fields are not fixed. Billing locations, warehouses and automatic product codes switch fields on and off per organisation. The same template can be complete for one business and incomplete for another. So the mapping page, not the template, has to say what is missing.
- One document spans several rows. A delivery note with three items is three lines in the sheet but one document in the books. Posting has to treat the document as the unit.
Local vocabulary matters too: businesses in Nepal say "Godown" for a warehouse, and "VAT Applicable" is a required field on delivery notes.
Proto-personas, assumption-based and not research participants: an accountant onboarding a client's item list, and an operations clerk posting a distributor's sheet of deliveries.Explorations, and the page I kept for them
I don't delete ideas that lose; I move them to a second page. The 🔴 Bulk Import page holds:
- a top-bar summary of total, valid and error rows, with Import, Selected and Filter actions;
- one table with a Pending, Ready and Imported lifecycle, where imported rows stay visible next to rows that aren't posted yet;
- a separate Fields Selected state and an alternative default screen;
- earlier versions of the input, dropdown and date editors, and of the filter states.
Asset to add
Figma export: Tigg New Features → 🔴 Bulk Import → the top-bar summary frame (total / valid / error rows with Import, Selected, Filter) and the Pending / Ready / Imported table, 2x PNG, side by side
In retrospect, the lifecycle table put posted and unposted rows side by side. Posting creates real accounting transactions that can't be undone, so that mix is risky. The final page focuses on the rows that still need attention before posting.
One honest detail: a frame on the final page is labelled "Supposed to be DN GRN Screen but is Invoice screen for now". I drew the pattern over an invoice screen while designing for delivery notes. The design was a pattern first.
Mapping: show the gap where it is
After upload comes the Map Fields page, with two panels. Mapped shows each Tigg field, the Excel column chosen for it and a sample of the sheet's values, so a match can be checked by content, not just by heading. Unmapped shows what's left. Both carry a count. A required field that is still unmapped is amber.
The first-time state arrives with matches suggested, so "Godown" lands on Warehouse Name without anyone typing. A column can be used only once.
Asset to add
Figma export: Tigg New Features → 🟢 Bulk Import → frame 'Required still unmapped but clicked next' (red selects and the named message), 2x PNG
Asset to add
Figma export: 🟢 Bulk Import → frame 'Nothing Mapped', 2x PNG
Asset to add
Figma export: 🟢 Bulk Import → frame 'Some Mapped', 2x PNG
Repair in the grid, not in the file
Once mapping passes, the rows open in a full-width grid: the Excel like Editing frame. For the errors it supports, this replaces the trip back to Excel.
Four ideas carry the grid:
- Every cell has a type: text, number, date, or a dropdown for customer, product or warehouse. Free text is where import errors come from; a typed editor prevents an error instead of reporting it.
- Errors belong to cells. The wrong value is tinted and carries its own message (shown on hover in the build), not a line in a list at the bottom.
- Find the bad rows fast. One control counts and filters at once: Total rows, Valid, Errors. Under the headers, a filter row narrows further, including "errors in this column" (Filter, Filter Selected).
- Fix many rows once. Select rows and a bar appears: Bulk edit (8 rows): column, value, Apply (Rows Selected, Bulk Update). The bar states its scope first, and the value input takes the column's type. Auto fill empty carries one value to other rows.
Asset to add
Figma export: 🟢 Bulk Import → frame 'Excel like Editing', 2x PNG
Asset to add
Figma export: 🟢 Bulk Import → frame 'Bulk Update' (with 'Rows Selected' visible), 2x PNG
When nothing is left to fix, the All Clean frame takes over: valid equals total, and posting is available. Posting asks for confirmation, because it "will create actual transactions and cannot be undone".
One import, step by step
Here is one fictional import from a distributor's sheet: upload, a blocked Next, repair in the grid, and posting. Step through it with the buttons or the arrow keys.
Import a delivery sheet, step by step
Step 1 / 8
One file, dropped once
The upload drawer takes an Excel file, with a template download beside the drop zone for anyone who wants it. The file is read and its headings go to mapping.
- File
- himal-deliveries.xlsx
- Rows read
- 42
- Template
- Available
Arrow keys work too
All steps as a table
| # | State | What happens |
|---|---|---|
| 1 | Upload | One file, dropped once. The upload drawer takes an Excel file, with a template download beside the drop zone for anyone who wants it. The file is read and its headings go to mapping. |
| 2 | Some Mapped | Matches suggested, gaps counted. Most columns are matched on arrival: 'Godown' lands on Warehouse Name. Two required fields have no match because the sheet calls them 'Qty' and 'VAT?'. They are amber. |
| 3 | Blocked at mapping | Next is pressed with gaps. The two selects turn red in place and the message names them. Nothing reaches the grid yet, so one missing mapping never becomes 42 row errors. |
| 4 | Required mapped | Two choices, and Next opens. The user picks 'Qty' for Quantity and 'VAT?' for VAT Applicable. Only an optional field is left, which is allowed. |
| 5 | Has errors | Rows open in the grid, errors on their cells. Eight rows name a warehouse that doesn't exist: 'Main Godam'. Each wrong cell is tinted with its message. The count control shows the scale at once. |
| 6 | Rows selected | Filter, select, set once. Filter to errors in Warehouse Name, select all eight, and set 'Main Godown' in the bulk bar. The rows are checked again. |
| 7 | All Clean | Nothing left to fix. Valid equals total. Posting is available, with a confirmation, because it creates real transactions. |
| 8 | Completed | Posted as whole documents. The 42 lines are posted as delivery notes and the user is back on the list page. The import now shows as completed in recent imports. |
Asset to add
Figma export: Tigg New Features → 🟢 Bulk Import → frame 'All Clean', 2x PNG
Handoff, and what the build decided
I handed the 🟢 page over marked Ready for dev, with every state described in this case drawn as its own frame. The senior frontend engineer built it, starting on 2 June 2026, and QA tested it as part of the release. I have no record of specific review comments on these pages, so I don't claim any.
Several decisions in the build came from the senior frontend engineer, not from my frames. They're good decisions, and they are theirs:
- Imports survive leaving the page. Work in the grid is saved as a draft on the way out. An unfinished import comes back in Recent imports, where only sessions still in progress can be opened. My list of recent uploads frame gave the list a place; the build made the resume work.
- Edits are checked when you leave a cell, not on every keystroke. The cell's error clears as soon as you change it, and it comes back only if the new value is also wrong.
- Documents post whole. If only some rows of one delivery note are selected, posting stops and names the document: select all its rows first. Half a document in the books is worse than none.
- Clear limits at upload. Excel files only, first sheet only, under 2 MB. A column that has data but no heading is rejected with "Missing header for specific column", instead of being dropped without a word.
- An online/offline indicator in the grid, and a message if the connection drops.
The same mapping and repair pages now serve Delivery Notes, Goods Received Notes and Inventory Adjustment in tagged releases, and Product/Service import on UAT. Only the fields change.
Status and evidence
| What | Where it stands |
|---|---|
| Design | 🟢 page Ready for dev, finished before the build began on 2 June 2026 |
| Tagged release | Delivery Note and Goods Received Note import, 20 July 2026; Inventory Adjustment import, 4 August 2026. Built by the senior frontend engineer |
| UAT only | Product/Service import (September 2026), not in a release tag yet |
| First-party signal | Users reach the "required still unmapped" state in real use, relayed through QA, support and the CEO |
| Measured outcome | None |
Nothing about this importer is measured: no import count, success rate, time to import or support trend. My own summary, "before: bad UX; now better", is a judgement, not a result.
The claim is deliberately narrow. The grid removes the trip back to Excel for the errors it supports: typed values, references, required cells, repeated fixes. Some problems still start in the file. Supported errors are repaired in Tigg before posting; the Excel round trip isn't gone for everything.
First I'd measure where imports stall (started, mapped, posted), then whether a round trip still happens: the same file uploaded again within a day.
What I learned
- Give the failure its own frame. "Required still unmapped but clicked next" is the most useful frame on the page because it's the state people reach. Drawing it as a state set the logic for the whole mapping page: counts on both panels, amber before red, and a Next button that says why it won't move.
- Design the pattern, not the screen. The states were defined by what people need, not by one document's fields, so the same pages took on more document types.
- A design-only handoff needs to carry behaviour, not just looks. Frames show states well. Behaviour such as moving between cells with the keyboard, or pasting a block of values, is easy to leave implicit. "Excel-like" in the build means typed in-cell editing and bulk changes; arrow-key movement and paste aren't there yet. Next time I'd add a short interaction spec: a keyboard map, focus order, and what Enter and Tab do.
The import's states, and the difficult ones
An import is a session with a lifecycle, not a file transfer. Every blocked transition keeps the user where they are and says why.
Mapping sub-states
| State | Mapped panel | Unmapped panel | Next |
|---|---|---|---|
| Nothing Mapped | "No fields mapped yet" | Every field; required ones amber | Blocked: red selects and a named message |
| Some Mapped | Matches with a sample of the sheet's values | Remaining fields | Blocked while any required field is unmapped |
| All required mapped | Required fields and samples | Optional fields only | Allowed |
| All mapped | Every field | "All fields are mapped" | Allowed |
| Column used twice | Both fields red | – | Blocked: "Each Excel column can only be mapped to one field." |
Difficult states
| Kind | What happens |
|---|---|
| Empty | "No import history" in recent imports; "No fields mapped yet"; "No records found" in a filtered grid |
| Blank vs zero | A blank required cell is an error. In the build, blank quantity, rate and discount are read as 0. For an accounting document I'd treat that as a design question: a silent zero on a delivery note is a wrong document |
| Rejected file | Not Excel, or over 2 MB: an inline error in the upload drawer, never a dead-end page |
| Headerless column | "Missing header for specific column"; empty columns are simply ignored |
| Heading gone | A mapping that points to a heading no longer in the file shows an amber warning |
| Settings change | Turning on billing locations or warehouses makes those fields required; product code is required only when automatic codes are off |
| Half a document | Posting stops and names the document until all its rows are selected |
| Interrupted | Leaving saves a draft; the import can be resumed from recent imports. A lost connection shows "Connection lost. Please refresh the page." |
| Irreversible | Deleting an import: "This action cannot be undone." Posting: "This will create actual transactions and cannot be undone." |
From insight to frame, and the 2026 comparison
Each insight became one requirement, and each requirement one named frame on the 🟢 page. The second insight is first-party. The rest are my reading of the old importer and the data, written after the fact as design reasoning.
Import flows compared (September 2026, public documentation)
| Product | Mapping | Fixing errors | Worth noting |
|---|---|---|---|
| Zoho Books / Inventory | Auto-map, with an option to save the selections | Preview counts (ready, skipped, unmapped); fix the file and re-import | Skip or overwrite duplicates by a chosen key |
| QuickBooks Online | Dropdown per field; "No Match" | Invalid cells highlighted in red in the review, fixed there | 1,000 rows at a time; an import can't be undone |
| Xero | Assign columns (bank statements), remembered for next time | Review, then complete | Name is the identity key for contacts |
| Odoo 19 | Suggested from the first lines, manual override | A Test step lists errors; fix the file | Product imports run in batches |
| TallyPrime | Saved mapping templates | An exceptions report to review and correct | Masters must exist before vouchers |
| Flatfile (import tool) | Suggested column matches | Edit any cell; filter by error; find and replace, including filling blanks | Warning and error levels are separate |
| Tigg, final design | Suggested matches, counts, gaps shown on the field | Typed cells, filter by error and column, bulk update, auto fill | Posting is by whole document, confirmed |
Two things Tigg's design doesn't do yet, and the comparison suggests: remembered mappings for repeat imports (Zoho, Xero, Tally), and a warning level separate from errors, so a note like "this category will be created" doesn't read as a failure.
Sources: vendor help centres read in September 2026. No competitor product was used hands-on. A feature not listed may exist without public documentation.From frames to the built product
For this case I traced each frame on the 🟢 page to its counterpart in the product. The build is the senior frontend engineer's. The mapping between the two is my reconstruction.
| Frame on the 🟢 page | In the built product |
|---|---|
| Entry Point | "Import" in the menu of each supported list page |
| list of recent uploads | A Recent imports drawer; imports still in progress can be reopened |
| upload or download template | An upload drawer with the template download beside the drop zone |
| First time Mapping | Matches suggested on arrival, using field names and common aliases |
| Nothing Mapped, Some Mapped | Mapped and Unmapped panels with counts and empty states |
| Required still unmapped but clicked next | Next checks required fields; red selects and a message naming them |
| Excel like Editing, with input, date and dropdown edit | The review grid with typed cells |
| Auto fill empty | "Apply to all rows in this group": the closest match, and a loose one. It copies a value across one document rather than filling blanks |
| Rows Selected, Bulk Update | The bulk edit bar |
| Filter, Filter Selected | Column filters, an "errors in this column" toggle and a clear control |
| All Clean | Valid equals total; posting available |
Asset to add
Figma export: Tigg New Features → 🟢 Bulk Import → frame 'list of recent uploads', 2x PNG
Asset to add
Figma export: Tigg New Features → 🟢 Bulk Import → frame 'upload or download template', 2x PNG
Asset to add
Figma export: Tigg New Features → 🟢 Bulk Import → frame 'First time Mapping', 2x PNG
Asset to add
Figma export: Tigg New Features → 🟢 Bulk Import → frame 'Filter Selected' (with 'Filter' for context), 2x PNG
Asset to add
Figma export: Tigg New Features → 🟢 Bulk Import → frame 'Auto fill empty', 2x PNG
Asset to add
Figma export: Tigg New Features → 🟢 Bulk Import → frame 'Rows Selected', 2x PNG
Gaps between the idea and the build
None of these is a criticism of the build. They're the next steps I'd propose.
| Gap | Why it matters | What I'd propose |
|---|---|---|
| Errors show on hover | A tint plus a hover message fails keyboard users and anyone who can't see the tint | A visible icon in the cell, the message on focus too, and a count per row |
| No keyboard movement or paste | "Excel-like" today means typed editing and bulk changes | Arrow keys, Enter and Tab between cells; paste a block of values |
| Blank numbers read as 0 | A silent zero on a delivery note is a wrong document | Blank quantity and rate should be errors |
| Excel only, first sheet only | A CSV, or data on sheet two, surprises people | Say so in the drop zone; name the sheet being read on the mapping page |
| Duplicates found late | Product import must not create duplicate codes or names | Show duplicate errors in the grid, before posting (an open follow-up) |
| Mapping every time | Repeat imports of the same sheet start from suggestions again | Remember a mapping per organisation, keyed by the sheet's headings |
| Posting scope | "Post Entries" doesn't preview what it will create | A one-line summary: "42 rows → 9 delivery notes" |
How I would validate it
Nothing here has been run. It's the plan, in the order I'd do it.
Instrument what already exists
Every stage is already a state in the product, so measuring it needs logging, not new screens.
| Question | Measure | What it would decide |
|---|---|---|
| Where do imports stall? | Imports started → mapped → posted; drop-off at each stage | Which surface to improve first |
| Are suggested matches good enough? | Share of fields correctly matched on arrival; manual changes per import | Whether to add aliases or remembered mappings |
| How much repair is left? | Errors per 100 rows at first check vs at posting | Whether templates or missing master data cause most errors |
| Is bulk edit used? | Fixes made by bulk edit vs one cell at a time | Whether to invest in keyboard movement and paste |
| Is the round trip gone? | The same file name uploaded again within 24 hours | The proxy for this case's main claim |
A small usability test
- Who: 5 people per proto-persona: accountants who onboard clients, and operations clerks who post deliveries.
- Material: a fictional 60-row delivery sheet with its own headings ("Item", "Qty", "Godown") and planted errors: an inactive warehouse, a misspelled customer, a blank rate, a text quantity, and a document split across a selection.
- Tasks: import and post; recover from the blocked Next; fix one warehouse across many rows.
- Watch for: errors found without help, errors found only by hovering, time to All Clean, and whether anyone tries to leave for Excel.
- Accessibility pass: find every error with the keyboard only; list every state that relies on colour alone.
Notes on sources
- Design: Figma file "Tigg New Features", pages 🟢 Bulk Import (final, Ready for dev) and 🔴 Bulk Import (archive). Frame names in this case are the page's layer names. Both pages were drawn before the build began on 2 June 2026 (my own account).
- Built behaviour and microcopy: the product as built by the senior frontend engineer. Release dates are the dates of the tagged releases that include each collection. Product/Service import was on UAT only at the time of writing.
- First-party: my statements that the frontend was built by the senior frontend engineer, that the grid idea came from market research and ideation, and that users reach the unmapped-required state.
- Comparison: public vendor documentation read in September 2026, after the design. Not hands-on.
- Figures: screens are redrawn reconstructions with fictional data (business names, file names, counts) until the Figma exports are added. Diagrams are mine, drawn from the final design and the built product.
- Not available: usage, adoption or support data; import-specific QA records; the server's validation rules, which I describe only through the messages people see.