Skip to main content

MVP-Friendly, Future-State-Compatible Backend Architecture Plan

Future-state design document

This document was written as a pre-implementation design spec. The current deployed architecture is described in MVP Architecture. The high-level topology and principles here reflect the intended direction; the domain breakdown (Banking, Transaction, Classification, Reconciliation, Reporting) and advanced features (bank feeds, outbox, Kafka) are not yet implemented.

This document describes a scalable, privacy-first backend architecture designed for:

  • A React web client
  • Financial data (P&L, reconciliation, auditability)
  • PostgreSQL as the source of truth, with Firestore as the real-time read layer
  • Bank-feed imports and on-demand polling
  • An MVP that can evolve cleanly into microservices (Plan B)

This is intentionally modular, not microservices-first, and avoids early distributed-system complexity.


Architectural Principles

↑ Back to top

  • Modular-first, service-ready boundaries
  • Single transactional system of record
  • Append-only financial data
  • Strong tenant isolation
  • Explicit auditability
  • Async-ready without mandatory eventing
  • Clear ownership of data per domain

High-Level Topology

↑ Back to top

  • React web client
  • Node.js/Fastify REST API (BFF / API Edge)
  • PostgreSQL on Google Cloud SQL (schema-per-domain, source of truth)
  • Firestore (real-time read layer, synced from PostgreSQL via pg_notify)
  • Firestore sync service (long-running pg_notify listener, deployed as a separate Cloud Run service)

Layered Backend Architecture (Logical Layers)

↑ Back to top

1. API / Edge Layer (BFF)

  • Authentication via Firebase JWT (verified with Firebase Admin SDK)
  • Tenant resolution
  • Authorization (RBAC)
  • Request validation
  • Rate limiting
  • Response shaping for web clients
  • REST (Fastify)
  • Correlation ID injection

2. Application / Orchestration Layer

↑ Back to top

  • Use-case coordination
  • Job orchestration (imports, polling)
  • Transaction boundary management
  • Calls into domain services
  • No business rules
  • No persistence logic

3. Domain Layer (Service-Ready Modules)

↑ Back to top

Each module owns:

  • Its business rules
  • Its write model
  • Its database schema

Banking / Ingestion Domain

  • Bank connection management
  • Provider adapters
  • One-time imports
  • On-demand polling
  • Raw transaction ingestion
  • Import job lifecycle

Transaction Domain

  • Normalized transactions
  • Deduplication logic
  • Pending vs posted handling
  • Source attribution

Classification Domain

  • Chart of Accounts (flat for MVP)
  • Classification rules
  • Manual overrides
  • Uncategorized handling

Ledger Domain

  • Immutable ledger entries
  • Double-entry enforcement
  • Posting rules
  • Period awareness

Reconciliation Domain

  • Account balances
  • Cleared vs uncleared
  • Reconciliation periods
  • Period close and lock

Reporting Domain

  • P&L generation
  • Cross-account aggregation
  • Statement generation
  • Drill-down read models

Audit Domain

  • Append-only audit log
  • Change tracking
  • Access history
  • Compliance evidence

4. Persistence Layer

↑ Back to top

  • PostgreSQL
  • Schema-per-domain (e.g. ledger., banking.)
  • Single writer per table
  • No cross-domain foreign keys
  • Views or read models for cross-domain reads
  • Flyway migrations per schema

5. Async & Integration Layer (MVP-safe)

↑ Back to top

  • Deployed: pg_notify triggers → Node.js sync listener → Firestore (simple, low-latency, no extra infrastructure)
  • Future: Job tables (import_job), outbox table (event-shaped records)
  • Future: Kafka-compatible event log (or Datastream if staying on Google Cloud SQL)

6. Security & Privacy Layer

↑ Back to top

  • Tenant isolation enforced at service layer
  • Field-level encryption for sensitive data
  • No PII in logs
  • Immutable audit trails
  • Admin override with reason codes

7. Observability & Ops Layer

↑ Back to top

  • Structured logging
  • Correlation IDs
  • Metrics per domain
  • Health checks
  • Data completeness checks

MVP Scope Summary

↑ Back to top

Deployed (current MVP):

  • Entities, accounts, journal entries, parties (ledger schema)
  • IAM — organizations, memberships, roles
  • Firestore sync via pg_notify
  • Audit trail

Planned (not yet implemented):

  • Bank ingestion and transaction normalization
  • Reconciliation
  • P&L and statements

Explicitly excluded (Phase 2+):

  • Accruals
  • Budgeting
  • Tax automation
  • Multi-entity consolidation
  • Event-driven microservices

Evolution Path (Plan B)

↑ Back to top

  • Extract domains into services as needed
  • Promote outbox to Kafka
  • Split Postgres by schema ownership
  • Add read replicas and materialized views
  • Preserve API contracts at BFF

Non-Negotiables

↑ Back to top

  • Ledger is append-only
  • Corrections are new entries
  • Periods are lockable
  • Every report number is traceable
  • PostgreSQL is the system of record — Firestore is a read layer, not a data store