Nebluna Inventory & Sales
Inventory and sales system for a specialty coffee micro-roastery in Mexico City. Covers the full cycle: green coffee, roasting, bulk stock, packaging, sale, shipping and reporting. Next.js 16 and TypeScript on Supabase.
A multi-role operations app on PostgreSQL, where the business rules are enforced in the database rather than in the forms: constraints and triggers prevent negative stock, every sale references a specific lot, and roasting shrinkage is measured per batch. 99 versioned migrations, Row Level Security on every table, and a CI pipeline that rebuilds the database from scratch on every pull request.

Gallery
Project Overview
Nebluna is the inventory and sales system for a specialty coffee micro-roastery in Mexico City. It covers the full product cycle: green coffee intake, roasting, bulk stock, packaging, sales across four channels, shipping and reporting. It is built with Next.js 16 (App Router) and TypeScript on Supabase, replacing the spreadsheet the business had been running on.
Technical Implementation
Data Model & Integrity
99 versioned migrations define the schema in PostgreSQL. Business rules are enforced in the database rather than in the forms: constraints and triggers prevent stock from going negative, every sale references a specific packaged-inventory row, and a blend deducts from its source lots through a single canonical path. Business dates are stored as DATE rather than TIMESTAMPTZ, and rows are always related by foreign key, never by matching text.
Roles & Security
Two roles with different products: administration sees financials, costs and settings; each sales rep sees the catalogue, their own sales and their own commissions, and nothing belonging to anyone else. The separation is enforced by Row Level Security policies on every table, so it holds even if a route guard fails.
Interface
React Query for server state, react-hook-form with Zod for forms, and shadcn/ui over Tailwind CSS 4. Three route groups: authentication, dashboard, and a print group that renders a letter-sized sale ticket with its own stylesheet. Mobile first, with the dense screens, reports and reconciliation, designed for a desktop.
Testing & CI
86 unit tests and 9 integration suites covering RLS policies, the sale lifecycle, commissions, repackaging, inventory reconciliation, date handling and stock by SKU. Four GitHub Actions workflows: lint blocking at zero errors, integration against a Supabase stack built from scratch inside the runner, a Lighthouse audit on every production deploy, and a guard that compares the migrations against the remote registry.
Functionality
- Sales: a four-step guided flow, four channels (direct, sales rep, WhatsApp and Instagram), retail and wholesale pricing, shipping calculation and a printable ticket.
- Inventory: packaged and bulk stock broken down by lot, with a 60-day freshness indicator and bag assignment to sales reps.
- Production: roast records with green weight, roasted weight, shrinkage and a derived cost per kilo, plus blends built from several source lots.
- Commissions: a rate on subtotal, only on the sales-rep channel, with a settlement history by period.
- Reconciliation: physical inventory counts and count requests sent to sales reps.
- Reports: by channel, product, customer, freshness, profitability, collections, pricing and sales rep.
The Challenge
- Stock cannot be allowed to go negative, and a spreadsheet has no way to prevent it
- Roasting loses 12 to 20% of the green weight, so cost per kilo depends on measuring shrinkage on every batch
- Administration and sales reps share the same data with opposing needs: one works in costs and margins, the others must not see them, or each other's
- Applying 99 migrations to a database already in use without the files and the remote registry drifting apart
The Approach
- Constraints and triggers in PostgreSQL: the database refuses the write instead of the form validating it
- Shrinkage is recorded per roast as green weight in minus roasted weight out, and cost per kilo is derived from that
- Row Level Security on every table, with the permission enforced in the database rather than in the interface
- A single documented path for applying migrations, with an automated guard that compares the files against the remote registry
Results
- 99 versioned migrations and a drift guard that runs in CI
- 86 unit tests and 9 integration suites against an ephemeral database built from scratch on every pull request
- Lighthouse gates on every production deploy: accessibility and best practices at 0.95, performance at 0.60
- Login page cut from 6.2 MB to roughly 760 KB by self-hosting the icon font and optimizing the logos
Impact
Lot-level traceability, a real cost per kilo with shrinkage accounted for, and commissions the system calculates, instead of all three being reconstructed by hand in a spreadsheet.
Project Details
Objective
Move the operation off a spreadsheet and onto a system where the database enforces the business rules, and where the sales team works with the catalogue and their own commissions without access to financial data.
Theme
Operations and inventory software for specialty coffee production.
Date
August 20, 2026