Valentino Rota

Mar del Plata, ArgentinaOpen to roles in Buenos Aires or remote

All work

Stock Tienda

Software for small stores to sell at the counter, keep their stock and close the cash register. I built it alone, end to end. Three stores pay for it and have used it for about three months.

Own product, 2026 – now. Product, design, code and operations.

Next.js, TypeScript, Tailwind CSS 4, shadcn/Radix, PostgreSQL (Neon), Drizzle, Vitest, Playwright, fast-check. Repository (public) (opens in a new tab). Screens come from a test store with demo data.

Reports screen: total for the period, products with low stock, cash closings with differences
Reports: period total, low stock and cash closings (test store, demo data)
On this page
  1. Context
  2. My role
  3. Design decisions
  4. Engineering decisions

Context

The scene is a store counter during opening hours, in daylight, sometimes in a hurry with a customer waiting. The app runs in the browser of the counter computer and on phones. The owner sees everything; employees sell, check products and run the cash register. The type of business is part of the model: a restaurant gets tables and kitchen tickets, a card shop gets variants by set, condition and language.

The core rule: stock is deducted in one transaction when a sale goes through, and you can’t sell without an open cash session. Online, a sale without enough stock is rejected. Offline is the deliberate exception, explained below.

My role

All of it: scope, design, code, tests and production. Each store’s data is isolated from the others, with owner and employee roles. Stores load their catalogue from a spreadsheet, or from a photo or PDF of a supplier invoice read with AI.

Design decisions

The design brief, in one line: the numbers are the interface. Money, stock, SKUs and dates read like a ledger you can trust at a glance. The tokens and rules are written down in the repository, so every new screen follows them.

A counter sale: search, quantity, cash price list, charge

Every figure in tabular mono

Columns of money only read when digits line up. Fonts load with display: optional; with the default swap, every figure changes width when the font arrives and the whole table jumps.

Product table: stock, prices and costs in a monospaced font, right-aligned, with low stock marked in red
Product table: figures aligned in columns

Color only when there’s something to look at

A green zero makes you look up to read that nothing happened. Here the only color is the red 7 for low stock; the zero closings with a difference stay black. Negative amounts go in parentheses, like a bank statement.

Three figures: total for the period, 7 products with low stock in red, and 0 cash closings with a difference
Report figures

Borders, not shadows

Two grey borders give the density: one separates, one structures. Shadows are reserved for the paper documents on screen, like the delivery note, which is what makes them look like paper.

Two kinds of empty

“No customers yet” (dotted border) is not the same as “no results for this filter” (solid border, with a way to clear it). Saying “nothing here” when 400 products are hidden by a filter is the worst case.

Engineering decisions

Offline sales: record first, flag later

Instead of rejecting an offline sale when stock ran out, the sale is recorded, stock may go negative and an alert is raised. It lands in the cash session that was open when it happened, even if that session is closed now. Device clocks are bounded: a date more than 30 days old or 5 minutes ahead is replaced with the sync time.

By the time the sale syncs, the goods have left the store and the money is in the drawer. Rejecting it doesn’t bring the units back; it only loses the record.

Permissions checked on the server, always

Hiding a button is not a permission.

Every action is authorized server-side, per store and per role. I found and closed a privilege-escalation bug in the replay endpoint, and added CI in the same change.

Property-based tests for the money math

Instead of only example tests, plus a manual test sale after each deploy: property tests for totals, prices, cash counts, accounts and tax amounts, alongside example and end-to-end tests, and a production check that replaced the manual sale.

Totals, prices, cash counts and tax amounts have rules that must hold for any input, and a handful of examples misses edge cases.

A test store in production

A store in production where real invoicing is blocked, to exercise the real production setup without issuing real invoices.

Contact

Open to design engineering and full-stack roles, in Buenos Aires or remote (UTC−3). Spanish (native), English (professional, spoken and written).

valentino.rota3@gmail.com

Next: Conosur