Cotizly
A multi-tenant SaaS that turns scattered quote spreadsheets into a single flow — build a quote, walk it through its lifecycle, and convert the approved one into a real order, per company.
Most of the money a small business loses between “here’s your quote” and “here’s your invoice” doesn’t disappear in one big mistake — it leaks. A price lives in one spreadsheet, the client’s details in another, the approved version in an email thread, and the order gets re-keyed by hand into a third place where a digit quietly changes. The quote was right; the order wasn’t; nobody can say where it drifted.
Cotizly closes that gap. It’s a web SaaS that lets a company build quotes, move them through a real lifecycle, and convert the approved ones into orders — all in one place, with the numbers carried across instead of retyped.
What it does
- Per-company workspace. Each company logs in to its own space — its users, its clients, its catalog. Each company works inside its own.
- Catalog management. Products and categories are managed per company, with images, so a quote is built from real items at real prices, not free text.
- A dynamic quote builder. Pick a client, pull products from the catalog, set quantities — subtotal, tax and total are computed as you go, and the server refuses to save a quote whose numbers don’t add up.
- A quote lifecycle. A quote isn’t just “open” or “closed.” It moves through draft → pending → approved (or rejected / expired), and only along transitions the system actually allows.
- Quote → order conversion. An approved quote becomes an order that stays linked back to the quote it came from — the audit trail the email thread never had.
- Filterable, exportable history. Every quote is searchable, and any one can be exported to PDF or Excel for the client or the records.
- A dashboard. Counts of products, clients and quotes, quotes broken down by status, and the most recent activity — the at-a-glance the spreadsheet couldn’t give.
Under the hood
The interesting part is that Cotizly is a real multi-tenant SaaS, and the isolation is enforced where it counts — on the server.
Tenant isolation as a guard, not a convention. Company scoping isn’t left to
the UI hoping to send the right ID. A dedicated CompanyIsolationGuard compares
the company on the authenticated user against the company in the request — route
and body — and rejects attempts to touch another tenant’s data, even
if the IDs are mismatched on purpose. In the quoting flow, queries are additionally
scoped by companyId on the server, so each company operates on its own data.
The quote lifecycle is modeled, not implied. Status is a typed enum, and the allowed moves between states live in an explicit transition table on the server. Ask for an illegal jump — say, reviving a rejected quote — and the API tells you exactly which transitions are valid instead of silently corrupting the record.
Writes are transactional and self-checking. Creating or editing a quote runs inside a database transaction: relationships (company, user, client, every product) are validated, items are saved, and the totals are recomputed and reconciled against what the client sent within a tolerance — the server is the source of truth on money, not the browser.
A typed NestJS API. The backend is strict-TypeScript NestJS over TypeORM / PostgreSQL, with JWT access + refresh tokens (Passport), role-based guards (admin / manager / user), and a soft-delete-and-restore model on core entities so nothing is ever truly lost. Redis backs a response cache — with single-flight locking so a cold key doesn’t stampede the database — and the rate limiter. The surface is hardened with Helmet, request-context IDs, global validation and a documented Swagger / OpenAPI spec.
The stack
- Frontend — Angular 19 with Tailwind CSS and Angular Material/CDK, RxJS; client-side PDF (jsPDF) and Excel (SheetJS/xlsx) export. Deployed on Firebase Hosting.
- Backend — NestJS in strict TypeScript, REST documented with Swagger/OpenAPI; product images stored in Firebase Storage.
- Data — PostgreSQL via TypeORM; Redis for response caching and rate-limit storage.
- Auth & security — JWT access/refresh with Passport, role-based access control, bcrypt, Helmet, throttling, a per-company isolation guard.
- Ops — multi-stage Docker build with a non-root user and a health check, container-ready for Railway-style deploys.
Worth noting
I built Cotizly solo, end to end — frontend, backend and database. It’s a personal product, currently on pause rather than in active development.
What makes it worth a look isn’t a long feature list — it’s the discipline underneath a fairly small product. Multi-tenant isolation enforced on the server, a quote lifecycle modeled as explicit, validated state transitions, money recomputed server-side rather than trusted from the client, and caching that fails open if Redis isn’t there — these are the decisions that separate a demo from something a business could actually run its quoting on without quietly losing money in the gaps.