Project logo
2025
Chazy

Chazy: Designing a Future-Proof SaaS Architecture

How to build a fintech-grade MVP aimed for rapid evolution.

Chazy is an AI-powered assistant that automates the collection of financial documents. The core concept sounds simple: match a transaction in the accounting system with an email attachment. However, in fintech, "simple" concepts often hide massive complexity regarding data isolation, audit trails, and state management.

Chazy accountant dashboard
The Accountant's View. Beneath a simple interface lies a dense layer of compliance checks, fraud scoring, and audit trails.

The founders needed a working MVP to validate the market. However, my engineering priority was to ensure that this MVP wasn't just a throwaway prototype, but a solid foundation. I aimed for an architecture capable of evolving from a simple web tool into a multi-interface ecosystem without technical debt dragging it down.

🎯 The Challenge: Beyond the "Happy Path"

What the client described as a simple "match" operation is actually a distributed saga involving:

  • Stateful Workflows: A "chase" isn't an instant event. It’s a lifecycle (Request → Reminders → Validation → Approval) that can span weeks.
  • Strict Isolation: Handling financial data requires rigid multi-tenancy and audit logs from Day 1.
  • Omni-Channel Vision: The roadmap demanded seamless access via a Web Dashboard, Email client, and Mobile web simultaneously.

🏗 Architecture: The Pragmatic Monolith

I resisted the urge to overengineer with microservices too early. Instead, I designed a Modular Monolith flanked by specialized helper services. This approach provided the operational simplicity of a single codebase, with the scalability of the cloud where it counted.

  • The Core (The Brain): I enforced Domain-Driven Design (DDD) within a single, cohesive Node.js application. This ensures strict consistency for financial transactions and simplifies testing.
  • The Satellites (The Muscle): Tasks that threatened the core's performance were extracted. Email ingestion happens at the Edge (to handle traffic spikes), while heavy media processing (PDF/Image slicing) runs on isolated serverless functions.

        flowchart TB
    subgraph Users["📡 Omni-Channel Access"]
        Dashboard(["Web Dashboard"])
        Extension(["Chrome Extension"])
        EmailIn(["📧 Email Client"])
    end
    subgraph External["🌍 External World (via Provider Registry)"]
        AI["AI Models<br>OpenAI / Anthropic"]
        Acc["Accounting APIs<br>Xero / QBO"]
        EmailOut["Email Service"]
    end
    subgraph Cloud["☁️ Chazy Infrastructure"]
        Edge[/"⚡ Edge Function<br>(Ingests Emails, Absorbs Spikes)"/]
        Core{"🧠 The Core<br>Node.js Monolith (DDD)<br>Business Logic &amp; State"}
        DB[("🗄️ PostgreSQL<br>Audit &amp; Data")]
        Worker["🏗️ Serverless Worker<br>(PDF Slicing &amp; OCR)<br>*Heavy Lifting*"]
    end
    Dashboard -- API REST --> Core
    Extension -- API REST --> Core
    EmailIn -. Inbound Stream .-> Edge
    Edge -- Sanitized Data --> Core
    Core <-- Read/Write --> DB
    Core -- Async Job --> Worker
    Worker -- Result --> Core
    Core <-- Interface Adapter --> AI & Acc
    Core -- Interface Adapter --> EmailOut

    Edge:::satellite
    DB:::database
    Worker:::satellite
    classDef core fill:#f9f,stroke:#333,stroke-width:4px,color:black
    classDef satellite fill:#e1f5fe,stroke:#0277bd,stroke-width:2px,color:black
    classDef external fill:#f5f5f5,stroke:#9e9e9e,stroke-width:1px,stroke-dasharray: 5 5,color:#616161
    classDef database fill:#fff9c4,stroke:#fbc02d,stroke-width:2px,color:black
    style Cloud fill:transparent
    style External stroke:#BBDEFB
    linkStyle 7 stroke:#FFF9C4,fill:none

    
The High-Level Overview: Keeping the Core Clean

🧬 Evolution: Surviving Complexity

The database schema expanded from ~8 core entities to over 30 in just 9 months. While such growth often turns startup codebases into "spaghetti," this project remained clean due to two strategic patterns embedded from the start:

1. The Provider Registry (Business Agility)

Hardcoding external integrations is a trap. I implemented a Provider Registry, where the core interacts only with abstract interfaces.

  • The Result: When the business required adding a new accounting platform (switching from Xero to QuickBooks), it became a strictly additive task, posing zero risk to the stable core logic.

2. Global Decoupling (Tech Independence)

Every infrastructure tool—whether it’s a database, an email service, or an AI model—is treated as a replaceable plugin via Dependency Injection.

  • The Result: When the project needed to upgrade from a basic Regex parser to an LLM, and later switch LLM providers, the switch required changing only a single configuration line. The complex business flows didn't even notice the change.

        flowchart TB
    subgraph CoreSystem["🛡️ Stable Domain Core"]
        direction TB
        Orchestrator("Document Processing Saga")
    end
    subgraph AdapterLayer["🔌 Integration Boundary"]
        IParser{"IParser Interface"}
    end
    subgraph Providers["🧩 External Implementations"]
        Regex["Legacy: Regex Parser"]
        OpenAI["Current: OpenAI GPT-4"]
        Anthropic["Future: Anthropic Claude"]
    end
    Orchestrator -- Depends only on --> IParser
    Config>"⚙️ Config / Env Var"] -.-> IParser
    IParser -. ❌ Disabled .-> Regex
    IParser == ✅ Active Injection ==> OpenAI
    IParser -. 🔜 Ready to Swap .-> Anthropic

    Orchestrator:::core
    IParser:::interface
    Regex:::inactive
    OpenAI:::active
    Anthropic:::future
    classDef core fill:#e3f2fd,stroke:#1565c0,stroke-width:2px,color:#0d47a1
    classDef interface fill:#fff3e0,stroke:#ff9800,stroke-width:2px,stroke-dasharray: 5 5
    classDef inactive fill:#f5f5f5,stroke:#bdbdbd,stroke-width:1px,color:#9e9e9e,stroke-dasharray: 2 2
    classDef active fill:#e8f5e9,stroke:#2e7d32,stroke-width:3px,color:#1b5e20
    classDef future fill:#f3e5f5,stroke:#9c27b0,stroke-width:1px,stroke-dasharray: 2 2
    style IParser color:#000000

    
The 'Plug-and-Play' Pattern: Swapping Brains without Surgery

🚀 Business Impact

The architecture proved its value not just in clean code, but in ROI. It allowed for rapid execution with the stability of a much larger organization:

  1. Internal Ecosystem: The system was so robust that it enabled the founders to evolve Chazy into a service provider for their primary business. The email ingestion and OCR engines were exposed as internal APIs, replacing a costly third-party vendor.
  2. Rapid Expansion: When the roadmap called for a Chrome Extension, I was able to reuse 100% of the backend logic. This turned a potential few-months sub-project into a 3-week sprint.
  3. B2B Readiness: The system is now being sold as a "Headless" API solution to partners—a pivot made possible solely because the core logic was strictly decoupled from the UI.
System Design
Node.js (DDD)
Edge Computing
Serverless Processing
PostgreSQL
Vue 3