Abe's Pottery
A race-safe quote-to-packing-slip ERP for a B2B ceramics importer — NestJS 11 + Prisma 7 + PostgreSQL, built test-first and live in production on Railway.
A wholesale ceramics business was running its commercial side on documents and good intentions. The real risk wasn’t a missing feature — it was two people acting on the same numbers at the same time: two quotes built against the same batch, two documents claiming the same number, totals that drifted depending on who typed them. Abe’s Pottery & Imports needed a system where that simply can’t happen. The answer is a quote → invoice → packing-slip ERP with the concurrency designed in, shipped test-first and live in production on Railway.
What it does
It covers the full commercial lifecycle of a ceramics importer and wholesaler:
- Catalog. Categories and products with images (stored in Firebase Storage), plus bulk import of the real product catalog straight from Excel.
- Customers & addresses. Business customers with billing and shipping addresses and proper default-address management.
- Quotes with a state machine.
DRAFT → SENT → ACCEPTED / REJECTED / EXPIRED, with a scheduled job that expires stale quotes on its own. - Conversion & fulfilment. Accepted quotes convert into invoices, and packing slips are generated and auto-linked back to the invoice they fulfil.
- Money that’s trustworthy. Subtotals, discounts, freight and tax are all computed on the server — the source of truth for every total on every document.
Under the hood
The whole system is built around one principle: the backend never trusts the client, and never lets two operations corrupt each other.
Race-safe document numbering. Numbers like Q-2026-00001 are issued inside a
database transaction that takes a row-level lock on the sequence before incrementing
it. Two simultaneous requests serialize cleanly instead of colliding — no duplicate
numbers, no gaps from optimistic guessing. The sequence is year-scoped and resets
automatically each January.
A state machine, enforced for real. Quotes only move along legal transitions; illegal ones are rejected outright rather than silently allowed. Expiry isn’t a manual chore either — a scheduled task sweeps and expires quotes on time.
Soft-delete done properly. Deletion is handled through a Prisma client extension that transparently filters out deleted rows on every query, so nothing in the app has to remember to add the filter. Hard deletes are deliberately hard to do — gated behind an admin role and an explicit confirmation header. The point is auditability: data leaves the working set without leaving the system.
Immutable line-item snapshots. When a product lands on a quote, invoice or packing slip, its name, description and unit price are copied onto the line item. Edit or delete the product later and historical documents stay exactly as they were issued — because a quote from March must never silently rewrite itself in June.
A typed contract end to end. NestJS 11 in strict TypeScript over Prisma 7, validated request DTOs, an OpenAPI/Swagger surface, and a declarative audit interceptor that records who changed what — captured after the transaction commits so logging never blocks the request.
Built to stay up under load. Rate limiting is backed by Redis but fail-open: if Redis disappears, the limiter degrades to in-memory rather than taking the API down, and the health check reports Redis without ever failing on it. A single operational kill switch can bypass Redis entirely — no redeploy required.
The stack
- Backend — NestJS 11 in strict TypeScript on Node.js 22, REST API documented with Swagger / OpenAPI.
- Data — PostgreSQL 15 via Prisma 7 (with the
@prisma/adapter-pgdriver); Redis 7 for distributed rate-limiting and a selective response cache. - Auth & security — JWT access + rotating refresh tokens in httpOnly cookies, Passport, argon2 password hashing, Helmet, strict CORS, a global throttler.
- Platform — Firebase Storage for product images,
nestjs-i18n(en / es), structured logging withnestjs-pinoand sensitive-field redaction, feature flags to mount or unmount modules at boot. - Quality — a Jest test suite (unit, e2e and integration) with a custom test harness that spins an ephemeral Postgres on tmpfs, and GitHub Actions CI/CD that runs migrations before each deploy.
Worth noting
I built the backend end to end — the data model, the concurrency strategy, the state machine, security, tests and the deployment pipeline — and it’s running in production today. It was built test-first, which means the race conditions were proven impossible before any UI existed to exercise them.
It’s a real product for a real wholesale business — proprietary client work — which is exactly why it’s built the way a system that runs someone’s company should be: correct under concurrency, auditable, and safe to deploy on a pipeline rather than by hand.
Coffee & talk?
Like what you just read? I build products like this end to end — and I'm always up for a conversation. Let's talk about yours, or just trade notes over coffee.