System Architecture · How it works

3 min read
Mid-level7 min read
Rapid overview

How it works

Choose a system topology that matches scale, team size, and operational maturity.


Detailed Explanation

Modular Monolith

What it is: A single deployment with strict module boundaries (e.g., Orders, Pricing, Risk).

Pros:

  • Simple deployment and debugging
  • Strong consistency and transactions
  • Clear boundaries without distributed complexity

Cons:

  • Scaling is all-or-nothing
  • Boundary violations creep in without discipline

Use it when: Team is small to medium and you want fast delivery with strong consistency.


Microservices Architecture

What it is: Independent services owning their data and deploy lifecycle.

                        [Keycloak IDP]
                              |
                         JWT Tokens
                              |
    [API Gateway] -----> Authentication
         |
    +----|----+---------+---------+
    |         |         |         |
[Identity] [Orders] [Content] [Menu]
    |         |         |         |
  [DB]      [DB]     [S3]      [DB]

Pros:

  • Independent scaling and deployments
  • Clear ownership boundaries
  • Technology flexibility per service
  • Team autonomy

Cons:

  • Distributed systems complexity
  • Data consistency challenges
  • Higher operational overhead (observability, tracing, CI/CD)

Key Components:

ComponentPurpose
API GatewaySingle entry point, routing, rate limiting, auth
Service MeshService-to-service communication, mTLS
Message BrokerAsync communication (RabbitMQ, Kafka)
Distributed CacheRedis for cross-service caching
Identity ProviderCentralized auth (Keycloak, Auth0)

Use it when: You have multiple teams, different scaling needs, and strong DevOps maturity.


Event-Driven Architecture

What it is: Services publish events; consumers react asynchronously.

[Order Service] ---> [Message Broker] ---> [Notification Service]
                           |
                           +-----------> [Analytics Service]
                           |
                           +-----------> [Billing Service]

Event Patterns:

PatternDescriptionUse Case
Pub/SubOne-to-many broadcastingNotifications, cache invalidation
Event SourcingStore events as source of truthAudit, replay capability
CQRSSeparate read/write modelsHigh-read workloads
SagaDistributed transactions via eventsMulti-service workflows
OutboxReliable event publishingConsistency guarantees

Pros:

  • Loose coupling between services
  • Natural fit for streaming (price ticks, trade events)
  • Resilient under bursts
  • Easy to add new consumers

Cons:

  • Eventual consistency
  • Harder debugging without tracing
  • Need idempotency and deduplication
  • Event schema evolution challenges

Use it when: You need high throughput, asynchronous workflows, or streaming pipelines.


API Gateway Pattern

What it is: Single entry point that routes requests to appropriate microservices.

[Mobile App]  [Web App]  [Third Party]
      \          |          /
       \         |         /
        +--------+---------+
                 |
           [API Gateway]
           - Authentication
           - Rate Limiting
           - Request Routing
           - Response Aggregation
                 |
    +------------+------------+
    |            |            |
[Service A] [Service B] [Service C]

Responsibilities:

  • Authentication/Authorization: Validate JWT tokens, enforce policies
  • Rate Limiting: Protect services from abuse, per-tenant limits
  • Request Routing: Route to appropriate backend service
  • Response Aggregation: Combine multiple service responses (BFF pattern)
  • Protocol Translation: REST to gRPC, WebSocket proxying
  • Caching: Edge caching for common requests

Technologies:

  • YARP (C# reverse proxy)
  • Kong, AWS API Gateway
  • Azure API Management
  • Nginx, Envoy

Use it when: You have multiple backend services and need unified edge policies.


Multi-Tenant SaaS Architecture

What it is: Single application instance serving multiple tenants with data isolation.

Isolation Strategies:

StrategyDescriptionProsCons
Row-LevelTenant ID column, query filteringCost efficient, simpleFilter discipline required
Schema-LevelSeparate schema per tenantBetter isolationMore complex migrations
Database-LevelSeparate DB per tenantComplete isolationHigher cost, more ops

Row-Level Implementation (EF Core):

// Automatic tenant filtering in DbContext
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Order>().HasQueryFilter(e =>
        _currentTenantService.TenantId == null || // SuperUser bypass
        e.TenantId == _currentTenantService.TenantId);
}

Tenant Resolution:

  • JWT claims (tenant_id claim)
  • Subdomain (tenant1.app.com)
  • Header (X-Tenant-Id)
  • Path segment (/api/tenants/{tenantId}/orders)

Key Considerations:

  • Data Isolation: Prevent cross-tenant data access
  • Resource Limits: Per-tenant quotas, rate limiting
  • Configuration: Tenant-specific settings, feature flags
  • Billing/Metering: Track usage per tenant
  • Onboarding: Self-service vs manual provisioning

Micro-kernel (Plugin Architecture)

What it is: A small core with extensible plugins that follow a strict contract.

Pros:

  • Extend behavior without changing the core
  • Clear contract for integrations and client-specific behavior

Cons:

  • Plugin lifecycle and versioning complexity
  • Requires strict API contracts and discipline

Use it when: You need a stable core with customizable extensions (e.g., per-client risk engines, pluggable pricing strategies, tenant-specific tax rules).


Layered / N-Tier

What it is: Classic tier separation (UI, business, data) often deployed together as a single unit.

Pros:

  • Easy to understand for newcomers
  • Works well for small internal apps

Cons:

  • Can become tightly coupled across tiers
  • Hard to scale individual tiers independently
  • Layers tend to leak responsibilities over time

Use it when: Small internal apps where the cost of any other architecture isn't justified.


See also