Skip to main content

Architecture Overview

Flo is a monorepo containing a .NET 9 backend, Angular 21 frontend, Roslyn source generator, Blazor admin panel, test suite, and a Node.js deployment CLI.

Project Structure

Flo/
├── Flo.BE/ # Backend API (.NET 9)
│ ├── Controllers/ # REST API endpoints (versioned)
│ ├── Services/ # Business logic (30+ services)
│ ├── Models/ # EF Core entities
│ ├── Schemas/ # JSON schemas for dynamic entity code generation
│ │ └── immobili/ # Real estate bounded context
│ ├── BoundedContexts/ # Domain-specific code (controllers, services)
│ ├── Middlewares/ # Exception handling, correlation IDs
│ ├── Helpers/ # Role checking, password hashing, audit
│ └── Migrations/ # 73 EF Core migrations
├── Flo.FE/ # Frontend SPA (Angular 21)
│ └── src/app/
│ ├── features/ # Feature modules (auth, dashboard, immobili)
│ ├── components/ # 33 shared components
│ ├── services/ # Auto-generated API clients, stores
│ └── guards/ # Auth, role, feature flag guards
├── Flo.SchemaGen/ # Roslyn Source Generator
│ └── Generators/ # Entity, Controller, Service, Migration generators
├── Flo.Backoffice/ # Admin panel (Blazor Server)
├── Flo.BE.Tests/ # NUnit test suite (438+ tests, 63% coverage)
├── cli/ # Multi-tenant deployment CLI (Node.js)
│ ├── lib/commands/ # 25+ commands (deploy, rollback, backup, etc.)
│ ├── lib/core/ # Blue-green logic, tenant management
│ └── data/ # Tenant configs, Traefik config
├── Docs/ # Internal documentation
├── tools/ # VPS update scripts
├── compose.yaml # Docker Compose (single-tenant)
├── Dockerfile # Multi-stage .NET build
├── nginx.conf.template # Nginx config with security headers
└── deploy.sh # Single-tenant deployment script

Backend Architecture

The backend follows a services-layer pattern (no repository pattern) with dependency injection.

Key Technologies

TechnologyPurpose
.NET 9 + ASP.NET CoreWeb API framework
Entity Framework CoreORM with PostgreSQL 16
OpenIddictOIDC/OAuth2 server
Roslyn Source GeneratorCompile-time code generation from JSON schemas
NSwagOpenAPI docs + TypeScript client generation
SerilogStructured logging with correlation IDs
MailKit + MJMLEmail templates

Backend Patterns

  • Services layer with DI — No repository pattern, services access DbContext directly
  • Role-based authorization — Flags-based enum with bitwise checking
  • Feature flags — Database-backed, checked via FeatureFlagsHelper
  • Dynamic entities — JSON schemas + compile-time code generation
  • Bounded contexts — Domain-specific functionality isolated in BoundedContexts/
  • Health checks + maintenance mode — Configurable per deployment
  • Response caching — Tiered Cache-Control headers (24h for static data, 5min for config, no-cache for mutations)

Middlewares

MiddlewarePurpose
ExceptionMiddlewareGlobal error handling with structured error responses
CorrelationIdMiddlewareRequest tracing via X-Correlation-Id header
OidcLoggingMiddlewareOIDC debugging (development only)

Frontend Architecture

The frontend is a standalone Angular 21 SPA using signals and OnPush change detection.

Key Technologies

TechnologyPurpose
Angular 21Framework (standalone components, signals)
PrimeNG 21UI component library
Tailwind CSS 3.4Utility-first styling
NGRX ComponentStoreState management (10+ stores)
TranslocoInternationalization (Italian + English)
TipTapRich text editor (WYSIWYG)
LeafletInteractive maps
GSAPAnimations (sidebar, mobile tab bar)

Frontend Patterns

  • Signal-based reactivitysignal(), computed(), effect() for component state
  • Thin components — All business logic lives in stores/services
  • Multi-brand theming — Runtime brand detection via hostname
  • Feature flag guards — Routes gated by database-backed flags
  • Auto-generated API clients — NSwag generates TypeScript clients from OpenAPI spec
  • PWA — Service worker, install prompts, offline caching

Data Flow

Browser → Nginx/Traefik → ASP.NET Core API → Services → EF Core → PostgreSQL

Feature Flags
Role Checking
Audit Logging

Key Design Decisions

  1. Compile-time code generation — Dynamic entities are defined via JSON schemas and turned into C# code at build time by the Roslyn Source Generator. Zero runtime overhead.

  2. Cookie-based auth — All three auth flows (password, OTP, OIDC) result in a cookie session. No JWT tokens sent to the frontend.

  3. Additive-only migrations — SchemaGen migrations only add tables/columns (CREATE IF NOT EXISTS). No destructive operations.

  4. Multi-brand via CSS variables — Brand detection at startup injects CSS variables into :root, making the entire UI theme-aware without code changes.

  5. Blue-green deployments — Multi-tenant CLI deploys to a standby slot, verifies health, then switches traffic via Traefik. Instant rollback.