Quoting System
A production-ready, multi-tenant quoting SaaS that streamlines the full quote lifecycle — from creation and line-item configuration to rules-engine pricing, client approval, branded PDF export, and CRM integrations. Built for speed, accuracy, and professional delivery.
The Challenge
Businesses waste significant time generating quotes manually across spreadsheets and disconnected tools — leading to inconsistencies, slow turnaround, and a poor client experience. Tracking quote status, managing revisions, and collecting approvals compounds the operational overhead.
The goal was to build a unified platform that manages the complete quoting workflow — from drafting and line-item configuration to client-facing delivery, digital approval, and branded PDF export — removing friction at every stage while supporting multi-tenancy from day one.
The Solution
Quodate is a full-stack, multi-tenant quoting SaaS. The React 19 + Vite frontend delivers a fast, responsive UI with TanStack React Query for server state and Zustand for local state. The FastAPI backend (Python 3.12, async SQLAlchemy) owns all business logic — quote lifecycle, rules engine, approval routing, and PDF generation via WeasyPrint.
The rules engine supports discount, tax, and pricing adjustment logic with condition/action schemas and a dry-run simulation endpoint — so pricing changes are previewed before going live. Redis powers caching, and the entire platform is containerised with Docker Compose.
Technical Implementation
Frontend Stack
React 19 + TypeScript + Vite. TanStack React Query for data fetching, Zustand for global state, Tailwind CSS + Shadcn/ui for styling, React Hook Form + Zod for validation, and Axios with JWT interceptors.
Backend Stack
FastAPI with Python 3.12 and async SQLAlchemy. PostgreSQL 16 with Alembic migrations, Redis for caching, WeasyPrint for PDF generation, Jinja2 for templates, and pytest for the test suite.
Rules Engine — Dry-Run Simulation
# Condition/action schema — priority-ordered rule stack
class PricingRule(BaseModel):
condition: RuleCondition # product_type, qty, segment, date
action: RuleAction # discount, tax, adjustment
priority: int
active: bool
# Dry-run: preview totals before rules go live
@router.post("/rules/simulate")
async def simulate_rules(payload: SimulateRequest):
result = await rules_engine.dry_run(
quote_id=payload.quote_id,
rules=payload.rules,
)
return {"before": result.before, "after": result.after}
Core Features
Quote Lifecycle
Full pipeline: Draft → Review → Approved → Accepted / Rejected / Expired with revision lineage and snapshot pricing.
Rules Engine
Self-serve discount, tax, and pricing rules with condition/action schema, priority stacks, and dry-run simulation.
PDF & Templates
10 built-in branded layouts (Clean, Corporate, Bold, Minimal…) with per-tenant customisation and one-click preview.
Approvals & Audit
Configurable approval routing, persistent event timeline, and full async audit log across every mutation.
Product Catalog
Supply, Services, and Goods types with template-driven attribute schemas and validation on every quote line item.
Multi-Tenant Platform
Full data isolation per tenant, onboarding flow, role management, global search, and live pipeline dashboard.