Single Page Application
ODO Perfume
- ROLE
- Product Designer (full-stack decision-making, AI-assisted implementation)
- TIMELINE
- Under 1 month to MVP, ongoing iteration since
- CORE PRODUCT
- Odo Perfume, internal single-page application for inventory, supplier pricing, and sales operations
- IMPACT
- Replaced a paper-and-memory process with a live, calculation-driven system for a team of under 10
01 / Context & The Bottleneck
Odo Perfume ran its operations on paper and institutional memory. That worked at a small scale. It stopped working the moment the client decided to scale distribution.
The real gap wasn’t the paper itself, it was what the paper couldn’t do. Nobody could evaluate performance by perfume, by time period, or by financial outcome. Pricing decisions depended on someone remembering a supplier’s last quote, not on a system that could tell them.
The team needed a way to see, in one place, what had been sold, what suppliers were charging, and what price to quote a customer right now, not after checking three different sources.
What made this harder than a standard inventory tool:
- Multiple suppliers for the same perfume, each with different currencies (USD and local), different minimum purchase quantities, and different per-unit pricing
- A pricing logic that had to account for the full spread between the cheapest and most expensive supplier purchase for a given product, while keeping the final customer price below market rate
- A team under 10 people, meaning the system had to be fast to adopt, not just powerful
The client’s priority was validating the system fast and keeping overhead low while the business scales. A full backend-separated web application was on the table. So was a simple spreadsheet. Both were set aside in favor of a single-page application, built to move fast now, with a clear path to a heavier architecture once the business outgrows this stage. This wasn’t the fallback option, it was the right-sized one.
02 / Architecture & The Fix
Here’s the thing about a spreadsheet: you can build this logic inside one. Nested formulas, conditional pricing, even a crude margin calculator. People do it all the time. But the moment you add multiple suppliers, multiple currencies, role-based access, and a pricing model that has to flex per transaction, a sheet stops being a tool and starts being a liability someone has to babysit. One broken formula reference and the whole pricing chain is wrong, silently, until someone notices the business lost money on a sale. That risk, not the feature list, is what actually ruled it out.
A full backend-separated web app was the “correct” long-term answer. It also wasn’t the right answer for a 10-person team still proving out a scaled distribution model. Why pay for infrastructure the business hasn’t earned yet? The SPA was the honest answer to where Odo Perfume actually is right now: real logic, low overhead, and a clean handoff point to something heavier once growth demands it.
Six modules, mapped to how people actually work, not how inventory software usually looks.
Dashboard. Calculator. Sell. Purchase. Supplier. Ops. None of these were picked off a template. They came from watching how the team already split the work in their heads, paper or no paper, and giving each split its own space.
The pricing problem that actually mattered.
Same perfume, three suppliers, three different costs, two different currencies, different minimum order sizes. Price it off the expensive supplier and you lose sales to the market. Price it off the cheapest and you bleed margin the moment that supplier runs out of stock. A flat markup can’t hold both truths at once.
So the system doesn’t fix a markup percentage. It fixes a target margin and solves backward from it, recalculating as supplier cost, currency, and order volume shift underneath it. The business always knows its margin before a sale happens, not after.
That same dynamic pricing engine turned into something more interesting than a safety net. Once price could flex per volume, it became a lever. Buy more, the per-unit math gets better for the customer, which is a nudge straight out of behavioral pricing, not a coincidence. Marketing now had a real tool for volume offers instead of asking for a one-off discount every time.
Who sees what, who can touch what.
Four roles. That’s it, four, not six interfaces to maintain. A salesperson quoting a customer doesn’t need to see supplier cost. Someone managing purchasing doesn’t need write access to sales records. Instead of building separate screens for each role, access sits underneath the same six modules through RBAC. Same pages, four different versions of what’s visible and actionable depending on who’s logged in.
How the build actually moved.
Agile, not waterfall, and not by default, by necessity. Paper-based businesses have a specific trap waiting for them the moment you digitize: every person who’s been frustrated with the old process suddenly wants their fix built in, all at once, and you end up with a feature factory instead of a working product. Two frameworks kept that in check. Eisenhower Matrix sorted what was urgent against what could wait. KANO sorted what the business actually needed against what would just be nice to have. Shipping in pieces, then collecting feedback before the next piece, is what kept six modules from becoming sixteen half-finished ones.
The client didn’t love this at first, and that’s worth saying.
Someone who’s run a business on paper for years has a kind of fluency with it. A new system, even a better one, feels like friction before it feels like progress. Early on, the pushback was direct: this is complicated, paper was easier. That changed once reporting and accuracy started showing him things paper never could, where margin was actually going, which products were actually moving. The complaint didn’t just quiet down. It flipped. He’s now the one pushing to optimize further.
How it got built.
Gemini and Claude Code ran in a loop across every module, not in separate lanes. Early on, Gemini scaffolded most of the groundwork. As the project matured, decision-making settled into Gemini while Claude Code carried the implementation forward, back and forth, module by module, until each piece held up.
One more thing worth saying plainly: every component, across all six modules and every permission level, follows Material 3. An internal tool doesn’t have to look like one.
03 / Impact & Outcome
The numbers that are real, not generated:
- Pricing used to be an estimate. A product’s sell price took roughly 2 minutes to work out by hand, and it was still a guess
- Now it’s under 30 seconds, and it’s exact, calculated per customer tier (friend, family, or external buyer), not a flat number applied to everyone
- 4 role-based access levels running across the same 6 modules
- 3 active suppliers, 200+ products tracked (perfumes and bottles) inside the system
- Full build in under a month, shipped in pieces, still ongoing as new friction points surface
What the client’s reaction actually tells you.
He didn’t want this at first. That’s not a detail to hide, it’s the most honest data point in the whole project. Paper feels safe until you can’t see what it’s costing you. Once reporting made that visible (what was actually profitable, what wasn’t, where the margin leaked) the resistance turned into requests for more. That shift, from “this is too complicated” to “let’s optimize further,” is the real before-and-after here. Not a chart. A person changing his mind because the system proved itself.
This is also still live work, not a closed case. New friction points get flagged, new pieces get shipped, the same agile loop that built it is the one maintaining it.