Maderera Juan B. Justo
One platform for a lumber company: public site, store, counter, sawmill, invoicing and customer portals.

Maderera Juan B. Justo has sold lumber in Mar del Plata since 1981, from two branches. Sales, stock, cuts and invoices had to live in one place. The counter, the sawmill and the online store all touch the same stock. Retail customers and trade professionals each need their own view of prices and accounts.
Three decisions that shaped it.
- 01
Every integration has a demo provider
Why. ARCA, Mercado Pago, WhatsApp and email depend on credentials the client still had to obtain. Without them, each module runs a demo provider behind the same interface. The full flow works and the screen says so.
Trade-off. Two implementations per integration to keep in sync. The demo can drift from the real API without anyone noticing.
- 02
No RLS: one server-only data layer
Why. The database credential never reaches the browser. Every read goes through the DAL and filters by the session user. Every write is a Server Action that checks the session, then validates with Zod.
Trade-off. The DAL is the only line of defense. One loose query in a component would bypass it, and only code review catches that.
- 03
The counter sells without internet
Why. A dropped connection can't stop a sale at the counter. The counter keeps a local copy of the catalog and queues sales in IndexedDB. Each sale gets a provisional number per register and syncs when the connection returns.
Trade-off. Local prices can be stale, and provisional numbers need reconciling. The shift can't close while sales are still pending.


Maderera Juan B. Justo
One platform for a lumber company: public site, store, counter, sawmill, invoicing and customer portals.
- Role
- Design and full-stack development
- Stack
- Next.js 16 (App Router), React 19, TypeScript, Postgres + Drizzle ORM, Better Auth, Tailwind CSS 4

Maderera Juan B. Justo has sold lumber in Mar del Plata since 1981, from two branches. Sales, stock, cuts and invoices had to live in one place. The counter, the sawmill and the online store all touch the same stock. Retail customers and trade professionals each need their own view of prices and accounts.
Three decisions that shaped it.
Every integration has a demo provider
Why. ARCA, Mercado Pago, WhatsApp and email depend on credentials the client still had to obtain. Without them, each module runs a demo provider behind the same interface. The full flow works and the screen says so.
Trade-off. Two implementations per integration to keep in sync. The demo can drift from the real API without anyone noticing.
No RLS: one server-only data layer
Why. The database credential never reaches the browser. Every read goes through the DAL and filters by the session user. Every write is a Server Action that checks the session, then validates with Zod.
Trade-off. The DAL is the only line of defense. One loose query in a component would bypass it, and only code review catches that.
The counter sells without internet
Why. A dropped connection can't stop a sale at the counter. The counter keeps a local copy of the catalog and queues sales in IndexedDB. Each sale gets a provisional number per register and syncs when the connection returns.
Trade-off. Local prices can be stale, and provisional numbers need reconciling. The shift can't close while sales are still pending.

