# Architecture

This document describes the active architecture of The Biergarten App.

## High-Level Overview

The Biergarten App is a monorepo with a clear split between the backend and the
active website:

- **Backend**: .NET 10 Web API with SQL Server, organized as vertical feature
  slices with MediatR
- **Frontend**: React 19 + React Router 7 website in `web/frontend`
- **Architecture Style**: Vertical-slice backend plus server-rendered React
  frontend

The legacy Next.js frontend has been retained in `archive/next-js-web-app/`
for reference only.

## Diagrams

For visual representations, see:

- [architecture.svg](website/diagrams-out/architecture.svg) - Vertical-slice
  architecture diagram
- [deployment.svg](website/diagrams-out/deployment.svg) - Docker deployment
  diagram
- [authentication-flow.svg](website/diagrams-out/authentication-flow.svg) -
  Authentication workflow
- [database-schema.svg](website/diagrams-out/database-schema.svg) - Database
  relationships

## Backend Architecture

### Vertical Slice Architecture Pattern

The backend organizes business capabilities as feature slices instead of
technical layers. Each feature (`Features.Auth`, `Features.Breweries`,
`Features.UserManagement`, `Features.Emails`) is a single project that owns
its own controller, MediatR commands/queries/handlers, validators, and
repository, end to end:

```
┌───────────────────────────────────────────────────────────────────────┐
│                          API.Core (thin host)                         │
│   - Program.cs wiring: MediatR + AddApplicationPart per slice         │
│   - Swagger/OpenAPI, JWT auth middleware, global exception filter     │
└───────────────────────────────────────────────────────────────────────┘
                  ↓ discovers controllers via AddApplicationPart
┌───────────────┬───────────────┬───────────────────┬───────────────────┐
│ Features.Auth │Features.      │ Features.          │ Features.Emails  │
│               │Breweries      │ UserManagement      │ (no controller,  │
│ Controller    │ Controller    │ Controller          │  internal only)  │
│ Commands/     │ Commands/     │ Commands/           │ Commands/        │
│  Queries +    │  Queries +    │  Queries +          │  Handlers        │
│  Handlers     │  Handlers     │  Handlers           │                  │
│ Repository    │ Repository    │ Repository          │ EmailDispatcher  │
└───────────────┴───────────────┴───────────────────┴───────────────────┘
       ↓ each slice depends only on shared/domain/infra, never on another slice
┌─────────────────────────┬─────────────────────────┬────────────────────┐
│ Shared.Contracts        │ Shared.Application        │ Domain.Entities /  │
│ (ResponseBody envelope) │ (ValidationBehavior,       │ Domain.Exceptions  │
│                         │  cross-slice email cmds)   │                    │
└─────────────────────────┴─────────────────────────┴────────────────────┘
       ↓
┌─────────────────────────────────────────────────────────────────────────┐
│ Infrastructure.Sql, Infrastructure.Jwt, Infrastructure.PasswordHashing,  │
│ Infrastructure.Email, Infrastructure.Email.Templates                    │
└─────────────────────────────────────────────────────────────────────────┘
                  ↓
┌─────────────────────────────────────┐
│      Database (SQL Server)          │
│   - Stored procedures               │
│   - Tables & constraints            │
└─────────────────────────────────────┘
```

Slices never reference each other's project. The one cross-slice
interaction (`Features.Auth` triggering a confirmation email handled by
`Features.Emails`) goes through a MediatR command (`SendRegistrationEmailCommand`)
whose contract lives in `Shared.Application`, so neither slice takes a
project reference on the other.

### Layer Responsibilities

#### API Layer (`API.Core`)

**Purpose**: Thin ASP.NET Core host: no business logic, no controllers of
its own

**Components**:

- `Program.cs`: registers MediatR (scanning every `Features.*` assembly),
  FluentValidation, and uses `AddApplicationPart` so each slice's controllers
  are discovered by MVC
- `GlobalException.cs`: global exception filter (host-level cross-cutting
  concern)
- `Authentication/JwtAuthenticationHandler.cs`: JWT auth scheme middleware
- Swagger/OpenAPI documentation, health check endpoints

**Dependencies**:

- Every `Features.*` project (for controller/MediatR discovery)
- `Shared.Contracts`, `Shared.Application`
- `Infrastructure.Jwt` (for the auth middleware)

**Rules**:

- No controllers, no business logic, no feature-specific contracts
- Exists purely to host and wire up the feature slices

#### Feature Slices (`Features.Auth`, `Features.Breweries`, `Features.UserManagement`, `Features.Emails`)

**Purpose**: Each slice is the complete vertical for one business capability

**Components** (per slice):

- `Controllers/`: HTTP endpoints, binding directly to Command/Query types
  as the request contract
- `Commands/<Operation>/` and `Queries/<Operation>/`: one folder per
  operation, each containing the Command/Query record, its
  `IRequestHandler`, and (for commands) a FluentValidation validator
- `Repository/`: the slice's own stored-procedure repository
  implementation
- `Dtos/`: response shapes returned by query handlers (never the raw
  domain entity)
- `DependencyInjection/`: an `AddFeaturesX()` extension method registering
  the slice's repository/services

`Features.Emails` has no `Controllers/` folder. It's invoked only via
MediatR commands sent from other slices, never over HTTP.

**Dependencies**:

- `Domain.Entities`, `Domain.Exceptions`
- `Infrastructure.Sql` (generic ADO.NET plumbing) plus whichever
  infrastructure project the slice needs (`Infrastructure.Jwt`/
  `Infrastructure.PasswordHashing` for Auth, `Infrastructure.Email`/
  `Infrastructure.Email.Templates` for Emails)
- `Shared.Contracts`, `Shared.Application`
- **Never** another `Features.*` project

**Rules**:

- All business logic for that feature lives in its command/query handlers
- No direct controller-to-repository calls; everything flows through
  MediatR
- Read endpoints return a dedicated `Dto`, never the domain entity directly

#### Shared Projects (`Shared.Contracts`, `Shared.Application`)

**Purpose**: The minimum cross-slice surface area required because every
slice needs it, or because duplicating it four times would be worse than
sharing it

**Components**:

- `Shared.Contracts`: `ResponseBody<T>`/`ResponseBody`, the API response
  envelope every controller returns
- `Shared.Application`: `ValidationBehavior<TRequest,TResponse>` (the
  MediatR pipeline behavior that runs FluentValidation before a handler
  executes) and the cross-slice email commands
  (`SendRegistrationEmailCommand`, `SendResendConfirmationEmailCommand`)

**Rules**:

- Kept deliberately small: this is the exception to "no slice depends on
  another slice," not a general-purpose dumping ground

#### Infrastructure Layer

**Purpose**: Technical capabilities and external integrations, shared by
whichever slices need them

**Components**:

- **Infrastructure.Sql**: generic ADO.NET connection/command plumbing
  (`ISqlConnectionFactory`, the abstract `Repository<T>` base class), not
  domain-specific; each slice's own `Repository/` folder builds on this
- **Infrastructure.Jwt**: JWT token generation and validation
- **Infrastructure.PasswordHashing**: Argon2id password hashing
- **Infrastructure.Email**: Email sending capabilities (SMTP/MailKit)
- **Infrastructure.Email.Templates**: Email template rendering (Razor
  components)

**Dependencies**:

- Domain entities
- External libraries (ADO.NET, JWT, Argon2, MailKit, etc.)

**Rules**:

- Implements technical concerns only, no business logic
- Reusable across slices

#### Domain Layer (`Domain.Entities`)

**Purpose**: Core business entities and models

**Components**:

- `UserAccount` - User profile data
- `UserCredential` - Authentication credentials
- `UserVerification` - Account verification state

**Dependencies**:

- None (pure domain)

**Rules**:

- Plain Old CLR Objects (POCOs)
- No framework dependencies
- No infrastructure references
- Represents business concepts

### Design Patterns

#### Vertical Slice + MediatR

**Purpose**: Organize code by feature instead of by technical layer, so
everything needed to understand or change one capability lives in one
project

**Implementation**:

- Each HTTP write operation is a `Command` (e.g. `CreateBreweryCommand` in
  `Features.Breweries/Commands/CreateBrewery/`); each read operation is a
  `Query` (e.g. `GetBreweryByIdQuery`)
- Controllers bind directly to the Command/Query as the request body;
  there is no separate request DTO + mapping step for writes
- A single shared `ValidationBehavior<TRequest,TResponse>`
  (`Shared.Application/Behaviors/`) runs FluentValidation validators in the
  MediatR pipeline before any handler executes
- Query handlers map to a dedicated response `Dto`, so domain entities never
  leak over the wire

**Example**:

```csharp
public record CreateBreweryCommand(Guid PostedById, string BreweryName, string Description, ...)
    : IRequest<BreweryDto>;

public class CreateBreweryHandler(IBreweryRepository repository) : IRequestHandler<CreateBreweryCommand, BreweryDto>
{
    public async Task<BreweryDto> Handle(CreateBreweryCommand request, CancellationToken cancellationToken) { ... }
}
```

#### Repository Pattern

**Purpose**: Abstract database access behind interfaces

**Implementation**: each slice owns its own repository, scoped to that
feature only:

- `Features.Auth/Repository/IAuthRepository.cs`
- `Features.Breweries/Repository/IBreweryRepository.cs`
- `Features.UserManagement/Repository/IUserAccountRepository.cs`
- `Infrastructure.Sql/DefaultSqlConnectionFactory.cs`: the generic
  connection factory every slice's repository builds on

**Benefits**:

- Testable (easy to mock)
- SQL-first approach (stored procedures)
- Each slice's data access logic is self-contained

**Example**:

```csharp
public interface IAuthRepository
{
    Task<UserCredential> GetUserCredentialAsync(string username);
    Task<int> CreateUserAccountAsync(UserAccount user, UserCredential credential);
}
```

#### Dependency Injection

**Purpose**: Loose coupling and testability

**Configuration**: `Program.cs` wires up MediatR/FluentValidation across
every `Features.*` assembly; each slice exposes its own `AddFeaturesX()`
extension method that registers its repository and slice-internal services

**Lifetimes**:

- Scoped: Repositories, slice-internal services (per request)
- Singleton: `ISqlConnectionFactory`
- Transient: Utilities, helpers

#### SQL-First Approach

**Purpose**: Push complex logic into the database

**Strategy**:

- All queries via stored procedures
- No ORM (Entity Framework not used)
- Database handles complex logic
- Application focuses on orchestration

**Stored Procedure Examples**:

- `USP_RegisterUser` - User registration
- `USP_GetUserAccountByUsername` - User lookup
- `USP_RotateUserCredential` - Password update

## Frontend Architecture

### Active Website (`web/frontend`)

The current website is a React Router 7 application with server-side rendering
enabled.

```text
web/frontend/
├── app/
│   ├── components/      Shared UI such as Navbar, FormField, SubmitButton, ToastProvider
│   ├── lib/             Auth helpers, schemas, and theme metadata
│   ├── routes/          Route modules for home, login, register, dashboard, confirm, theme
│   ├── root.tsx         App shell and global providers
│   └── app.css          Theme tokens and global styling
├── .storybook/          Storybook config and preview setup
├── stories/             Storybook stories for shared UI and themes
├── tests/playwright/    Storybook Playwright coverage
└── package.json         Frontend scripts and dependencies
```

### Frontend Responsibilities

- Render the auth demo and theme guide routes
- Manage cookie-backed website session state
- Call the .NET API for login, registration, token refresh, and confirmation
- Provide shared UI building blocks for forms, navigation, themes, and toasts
- Supply Storybook documentation and browser-based component verification

### Theme System

The active website uses semantic DaisyUI theme tokens backed by four Biergarten
themes:

- Biergarten Lager
- Biergarten Stout
- Biergarten Cassis
- Biergarten Weizen

All component styling should prefer semantic tokens such as `primary`,
`success`, `surface`, and `highlight` instead of hard-coded color values.

### Legacy Frontend

The previous Next.js frontend has been archived at `archive/next-js-web-app/`
for reference only. Active product and engineering documentation should point
to `web/frontend`.

## Security Architecture

### Authentication Flow

1. **Registration**:
   - User submits credentials
   - Password hashed with Argon2id
   - User account created
   - JWT token issued

2. **Login**:
   - User submits credentials
   - Password verified against hash
   - JWT token issued
   - Token stored client-side

3. **API Requests**:
   - Client sends JWT in Authorization header
   - Middleware validates token
   - Request proceeds if valid

### Password Security

**Algorithm**: Argon2id

- Memory: 64MB
- Iterations: 4
- Parallelism: CPU core count
- Salt: 128-bit (16 bytes)
- Hash: 256-bit (32 bytes)

### JWT Tokens

**Algorithm**: HS256 (HMAC-SHA256)

**Claims**:

- `sub` - User ID
- `unique_name` - Username
- `jti` - Unique token ID
- `iat` - Issued at timestamp
- `exp` - Expiration timestamp

**Configuration** (appsettings.json):

```json
{
  "Jwt": {
    "ExpirationMinutes": 60,
    "Issuer": "biergarten-api",
    "Audience": "biergarten-users"
  }
}
```

## Database Architecture

### SQL-First Philosophy

**Principles**:

1. Database is source of truth
2. Complex queries in stored procedures
3. Database handles referential integrity
4. Application orchestrates, database executes

**Benefits**:

- Performance optimization via execution plans
- Centralized query logic
- Version-controlled schema (migrations)
- Easier query profiling and tuning

### Migration Strategy

**Tool**: DbUp

**Process**:

1. Write SQL migration script
2. Embed in `Database.Migrations` project
3. Run migrations on startup
4. Idempotent and versioned

**Migration Files**:

```
scripts/
├── 001-CreateUserTables.sql
├── 002-CreateLocationTables.sql
├── 003-CreateBreweryTables.sql
└── ...
```

### Data Seeding

**Purpose**: Populate development/test databases

**Implementation**: `Database.Seed` project

**Seed Data**:

- Countries, states/provinces, cities
- Test user accounts
- Sample breweries (future)

## Deployment Architecture

### Docker Containerization

**Container Structure**:

- `sqlserver` - SQL Server 2022
- `database.migrations` - Schema migration runner
- `database.seed` - Data seeder
- `api.core` - ASP.NET Core Web API

**Environments**:

- Development (`docker-compose.dev.yaml`)
- Testing (`docker-compose.test.yaml`)
- Production (`docker-compose.prod.yaml`)

For details, see [Docker Guide](website/docker.md).

### Health Checks

**SQL Server**: Validates database connectivity **API**: Checks service health
and dependencies

**Configuration**:

```yaml
healthcheck:
  test: ["CMD-SHELL", "sqlcmd health check"]
  interval: 10s
  retries: 12
  start_period: 30s
```

## Testing Architecture

### Test Pyramid

```
    ┌──────────────┐
    │  Integration │  ← API.Specs (Reqnroll)
    │    Tests     │
    ├──────────────┤
    │  Unit Tests  │  ← Features.Auth.Tests, Features.Breweries.Tests,
    │ (per slice,  │     Features.UserManagement.Tests, Features.Emails.Tests
    │  handlers +  │     (commands/queries/handlers + that slice's own
    │  repository) │     repository, mocked with Moq/DbMocker)
    └──────────────┘
```

**Strategy**:

- Many unit tests (fast, isolated)
- Fewer integration tests (slower, e2e)
- Mock external dependencies
- Test database for integration tests

For details, see [Testing Guide](website/testing.md).
