Inspiration
A small business owner looks at a sales spreadsheet and sees revenue go up. The owner does not see that the margin goes down, that a few reps give large discounts, or that customers pay late. The data to see these problems is in the export. But the export is dirty, and the dashboards that could read it are expensive and hard to set up.
The Chrome & Oak case showed this well. In the raw files, the company makes a gross loss of 3,077,114 CAD, with a margin of −119.8 %. After the cleaning, the true gross profit is 2,266,540 CAD, with a margin of 28.5 %. One data error caused most of the difference: discounts typed as percents (15 in place of 0.15). The same raw files also hid the two largest business problems. One region gave discounts far above the company average, and one rep had a low margin.
So we asked two questions, and we wanted a tool that keeps them separate:
- What is wrong with my data? The cleaning fixes it.
- What is wrong with my business? An action plan fixes it.
What it does
BYOD (Bring Your Own Data) turns a sales export into a dashboard and an action plan. It works with any company's data that has the BYOD schema.
- Prepare your data. The user copies our cleaning prompt into their own AI (Claude, ChatGPT or another). The AI cleans the customers, orders and returns files into our standard schema. It asks the user before it makes a decision about an outlier or a conflicting ID.
- Upload. The app checks the three CSV files in the browser. The data never leaves the browser.
- See the three states. The first card shows the books in three states:
| Raw data | Fixed by the cleaning | Clean data | Fixed by the plan | After the plan | |
|---|---|---|---|---|---|
| What the files say | Data fix | What is true today | Business decision | If the plan works |
Each change has a cause. A data fix has a neutral color. A business decision names the action and the owner, for example "Set a discount approval limit for Atlantic. Owner: C-suite."
- Find the problems. Plain rules find the problems and rank them by their dollar impact:
- a rep with a low margin
- a region with discounts above the company average
- invoices past their due date
- discounts in the last month of a quarter
- refunds for damaged items
- Act. Each alert goes to the team that can act on it: Sales, Accounting or the C-suite. The user reads the message with the real numbers, then sends it by email, copies it, or dismisses it. The action log records each step.
- Simulate. The user moves a threshold, and the alerts, the charts and the "After the plan" column change. The data columns do not change. This shows the difference between the two questions.
- Report. One click prints a report for the C-suite, Sales or Accounting.
The dashboard also answers 14 business questions. Examples: the most returned products, the average discount for each rep, cash against invoiced amounts, and why the cost goes up.
How we built it
- App: Next.js 16, React, shadcn/ui, Tailwind CSS 4 and Recharts. Deployed on Vercel.
- Design: our own design system, in a calm and functional style, with a light theme and a dark theme.
- No database and no LLM in the app. Each number comes from one TypeScript file of formulas. Each sentence comes from templates that we fill with the real numbers. The team can explain every figure.
- The cleaning happens in the user's own AI. Our prompt tells the AI to write and run Python code, and never to edit a number by hand. It must also check the saved files against the schema before it gives them back.
- Tracking columns. The hard part was to show the raw data for any dataset. The cleaned
orders.csvkeeps one row for each row of the source file, with 6 extra columns:row_status: kept, duplicate or excludeddata_issues: a code for each problem in the row- four source values: what a spreadsheet reads from the original cells
With these columns, the app calculates the raw totals with the same formulas as the clean totals:
$$\text{Revenue}{\text{raw}} = \sum{\text{all rows}} q_{\text{source}} \times p_{\text{source}} \times (1 - d_{\text{source}})$$
$$\text{Revenue}{\text{clean}} = \sum{\text{kept rows}} q \times p \times (1 - d)$$
The app then gives each issue code its part of the change, so the parts add up to the total:
$$\sum_{\text{codes}} \Delta_{\text{code}} = \text{Revenue}{\text{clean}} - \text{Revenue}{\text{raw}}$$
- How we worked: one teammate built the app with Claude Code. The other teammate gave the business reasoning, checked the findings, and wrote the cleaning prompt.
Challenges we ran into
- Dirty data hides the business problem. In the raw files, the rep with the largest discounts showed −89,667 CAD of revenue and a margin of 1,960 %. A dashboard on the raw data gives wrong answers, and the user cannot see why.
- "Is this from the data or from a decision?" Our first version showed a "now → after the plan" figure. A user could not tell whether a change came from the cleaning or from the plan. We replaced it with the three states strip and a tag on each change.
- A flag is not enough. Our first prompt removed duplicate rows and excluded bad rows. After that, the app could not rebuild the raw totals. We changed the schema so that the AI keeps every source row and marks its status.
- Double counting. One row can have two problems, for example a region spelling and a percent discount. Our first attribution gave the full amount to both problems, so a spelling fix seemed to add 191,339 CAD of revenue. Now a name or date fix has no effect, and two problems of one kind share the effect.
- Long prompt. The final prompt has about 42,000 characters. That is too long for an "Open in Claude" link, so the app gives "Copy prompt" and "Download prompt".
- Repeated numbers. We removed figures that another figure already gives. For example, the app showed both "rows with a correction" and "rows with no change", and the channel chart repeated the segment chart.
Accomplishments that we're proud of
- The app works for any dataset that follows the schema. A test file with a 999,999 quantity, a "25%" discount, a quantity typed as "two", a duplicate and a row with no ID passes all 21 checks.
- The data stays in the browser. Nothing goes to our server.
- Every number can be explained. There is no black box between the data and the alert.
- The demo tells one clear story. The raw files show a loss. The clean data shows a 28.5 % margin. The plan raises it to 31.1 %, and each step has a name and an owner.
What we learned
- The first problem with business data is the data itself. A good insight on dirty data is still a wrong insight.
- Users trust a number more when they can see where it comes from. The tags "Data fix" and "Business decision" did more for trust than any chart.
- An AI is good at cleaning messy files when the rules are strict, the AI writes code, and a human decides each case that is not clear.
- Less is more on a dashboard. When one number gives another, show only one.
What's next for BYOD
- Any payment term: accept "Net N" for any number of days, not only Net 30 and Net 60.
- Any currency: one setting for the currency of the files.
- Send from the app: send the alert emails directly, with the report attached.
- More rules: a customer above the credit limit, and a long-time customer who stopped ordering.
- Before and after for each chart: show the raw data and the clean data side by side on the rep and region charts.
- A cleaning skill: give the cleaning steps as a reusable skill, so a company can clean each new export the same way.
Built With
- claude
- next.js
- python
- vercel