EN|ES
← projects/
catoca-ventas.nest.tsIn development

CATOCA · Sales system

Sales, batch inventory, commissions and DIAN pre-invoicing for a coffee exporter

company:
CATOCA (client)
period:
Sep 2026 — ongoing
  • NestJS 12
  • Fastify
  • Drizzle ORM
  • PostgreSQL 18
  • React 19
  • Vite 8
  • TanStack Router / Query
  • Tailwind CSS 4
  • Zod (shared contracts)
  • Vitest
  • Testcontainers
  • Playwright
  • Docker + Nginx

// problem

Sales reps' sales, inventory and commissions were tracked separately and by hand. The online store didn't deduct inventory, and the accountant had to rebuild every invoice to load it into Siigo.

// my role

Architecture and full development in phases: data model, NestJS API with Drizzle on PostgreSQL 18, React web panel, integration with the online store and Wompi, and the testing strategy.

// architecture

Web panelReact 19 · TanStack
catoca.cafeAPI Key + HMAC
Wompisigned webhook
NginxTLS · rate limit · SPA
APINestJS · Fastify · Drizzle
PostgreSQL 18stock ledger · audit
Pre-invoicesDIAN fields
Siigo exportaccounting .xlsx

The online store creates orders with an API key + HMAC and Wompi confirms payment through a signed webhook; both become sales in the web channel.

// technical decisions

Exact money and rates stored on every sale

Amounts in numeric(18,2), always in COP. VAT is calculated by accumulating the base per rate and rounding once on the total (ROUND_HALF_UP). Each sale stores the VAT rate and commission percentage it was calculated with, and only the admin can change those rates, with history.

Batch inventory with a stock ledger and FIFO

Every stock entry requires a batch date and a roast date. Sales consume the oldest batches first, every movement is recorded in the stock ledger and the system won't sell without stock.

Immutable, audited sales

The seller is always the authenticated user and can't edit a saved sale. Only the admin edits, with a mandatory reason and a before/after revision. A cancellation returns the inventory and voids the commission (with a negative adjustment if already paid); a return restores inventory but doesn't touch the commission.

Tests as the specification

100% coverage is mandatory, API tests run against real PostgreSQL with Testcontainers and E2E with Playwright. A committed test is never changed to make the code pass: a hook blocks editing it and a script checks it against main.

// impact

Test coverage
100%

mandatory Vitest threshold

Backend modules
14
Sales channels
3

sales rep · online store · admin

Accounting
Siigo

.xlsx export by date range

// screenshots

Admin dashboard: sales by month and channel
Admin dashboard: sales by month and channel
Sales rep dashboard: monthly sales and commission
Sales rep dashboard: monthly sales and commission
Recording a sale with VAT calculated
Recording a sale with VAT calculated
Recorded sales with payment status
Recorded sales with payment status
Commissions: approval and payout per sales rep
Commissions: approval and payout per sales rep
Batch inventory with roast date
Batch inventory with roast date

Private repository. Screenshots taken from a local installation with demo data, not from real operations.