Skip to main content
Back to Insights
Architecture

Greenfield SaaS Platform Architecture: Real-World Lessons

January 10, 2025
12 min read

Insights from architecting a greenfield SaaS platform using Azure, .NET 8, and Angular 18. Balancing microservices and modular monolith approaches for complex business rules and compliance systems.

Greenfield projects are rare. When you get one, the pressure to "do it right" can be paralyzing. Here's what I learned architecting a multi-tenant SaaS platform for tax and licensing systems, and why some of our early decisions turned out differently than expected.

The Microservices Temptation

We started with microservices. It seemed like the obvious choice for a modern SaaS platform. Independent deployment, technology flexibility, team autonomy. All the benefits you read about.

What we didn't fully appreciate was the operational complexity. Service discovery, distributed tracing, inter-service communication, data consistency across boundaries. Each problem has solutions, but those solutions add complexity that you have to carry forever.

Six months in, we realized we'd created more problems than we'd solved. Our team wasn't large enough to justify the overhead, and our domain boundaries weren't as clear as we'd assumed. We needed to rethink.

The Modular Monolith Compromise

We pivoted to a modular monolith. Not a big ball of mud, but a well-structured application with clear module boundaries, independent databases per module, and the ability to extract services later if needed.

Our Module Structure

  • Identity Module: Authentication, authorization, user management
  • Tenant Module: Multi-tenancy, subscription management, billing
  • Rules Engine Module: Business rules calculation, compliance validation, reporting
  • Workflow Module: Process automation, approval workflows, audit trails
  • Integration Module: External API integrations, webhooks, data sync

Each module has its own database schema, its own bounded context, and communicates with other modules through well-defined interfaces. The difference from microservices? They all deploy together, which dramatically simplifies operations while we're still figuring out the domain.

Multi-Tenancy: The Hard Parts

Multi-tenancy sounds straightforward until you implement it. We've built systems with every isolation level: row-level isolation in shared databases, schema-level isolation, separate databases per tenant, and even complete resource group isolation for enterprise customers with strict compliance requirements.

The choice depends on your customers. Small tenants share infrastructure for cost efficiency. Enterprise customers with compliance needs get dedicated resources. The architecture needs to support both without becoming two separate systems.

Isolation Strategies We've Implemented

  • Row-level isolation: Shared database, tenant ID on every row. Most cost-effective for small tenants.
  • Schema-level isolation: Separate schemas per tenant in shared database. Better isolation, manageable at scale.
  • Database-level isolation: Dedicated database per tenant. Required for some compliance scenarios.
  • Resource group isolation: Complete Azure resource separation. Maximum isolation for enterprise customers.

The technical implementation wasn't the hard part. The hard part was ensuring tenant isolation in every query, every background job, every cache entry, regardless of isolation level. One mistake and you've leaked data across tenants.

What We Learned

  • • Use a tenant context that flows through every operation
  • • Implement global query filters at the EF Core level for row-level isolation
  • • Add tenant ID to every cache key automatically
  • • Build tenant resolution logic that works across all isolation levels
  • • Test tenant isolation explicitly in integration tests
  • • Monitor for cross-tenant data access attempts
  • • Plan migration paths between isolation levels as tenants grow

Azure Services: What We Used and Why

We built on Azure, leveraging managed services where it made sense. Here's what we used and what we learned:

Azure App Service

Hosts our .NET 8 API. Easy deployment, built-in scaling, good monitoring. We use deployment slots for zero-downtime deployments. Cost-effective for our scale.

Azure SQL Database

Our primary data store. We use the serverless tier for development and reserved capacity for production. Automated backups and point-in-time restore saved us once when a migration went wrong.

Azure Service Bus

Handles async operations and module-to-module communication. More reliable than we expected, easier to debug than we feared. The dead letter queue has been invaluable for handling failures.

Azure Key Vault

Stores all secrets and connection strings. Integrates seamlessly with App Service. No secrets in config files or environment variables.

Frontend Architecture with Angular 18

We chose Angular 18 for the frontend. The decision was partly team familiarity, partly the strong typing and tooling. We use standalone components, signals for state management, and a feature-based folder structure that mirrors our backend modules.

The biggest win has been TypeScript interfaces generated from our C# DTOs. Changes to the API contract immediately show up as compile errors in the frontend. This catches integration issues before they reach testing.

We host the Angular app in Azure Static Web Apps. Simple deployment, global CDN, automatic SSL. It just works.

The Compliance Calculation Engine

The compliance calculation engine is the heart of the system. We built it using a rules engine pattern, where compliance rules are data rather than code. This lets us add new jurisdictions and update regulatory requirements without deploying code.

The challenge was performance. Compliance calculations can be complex, involving multiple jurisdictions, exemptions, and special cases. We use aggressive caching, pre-computation where possible, and async processing for batch operations.

Performance Optimizations

  • • Cache compiled compliance rules in memory with Redis backup
  • • Pre-calculate common scenarios during off-peak hours
  • • Use database indexes aggressively for jurisdiction lookups
  • • Implement circuit breakers for external regulatory data sources
  • • Monitor calculation times and alert on anomalies

DevOps and Deployment

We use Azure DevOps for CI/CD. Every commit triggers a build, runs tests, and deploys to a dev environment. Pull requests deploy to temporary environments for review. Production deployments happen through deployment slots with automated smoke tests before swapping.

Infrastructure as code using Bicep templates. Everything is version controlled and reproducible. We can spin up a complete environment in about 15 minutes.

The investment in automation paid off faster than expected. We deploy to production multiple times per week with confidence.

What We Learned Along the Way

Every project teaches you something. Here's what we learned that shaped how we approach similar projects now:

  • Start simpler, scale when needed. We pivoted from microservices to modular monolith after six months. The simpler approach let us move faster while keeping options open.
  • Observability from day one. Adding Application Insights early would have saved debugging time. Now we build monitoring in from the start.
  • Integration tests over unit tests. Unit tests are fine, but integration tests catch the problems that actually break production.
  • Document decisions as you make them. We started using Architecture Decision Records (ADRs) midway through. Wish we'd started earlier. Context gets lost fast.
  • Plan for data evolution. Schema changes in production are harder than you think. Build migration strategies early.

The Bottom Line

Greenfield projects let you make intentional choices, but they don't eliminate complexity. The key is choosing complexity that serves your actual needs, not complexity that serves an architectural ideal.

Start simpler than you think you need. Add complexity when you have evidence it's necessary. Your future self will thank you.

Building a SaaS Platform?

I help teams architect and build scalable SaaS platforms that balance technical excellence with practical delivery.

Start a Conversation