mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-02-16 10:42:08 +00:00
405 lines
11 KiB
Markdown
405 lines
11 KiB
Markdown
# Architecture
|
|
|
|
This document describes the architecture patterns and design decisions for The Biergarten App.
|
|
|
|
## High-Level Overview
|
|
|
|
The Biergarten App follows a **multi-project monorepo** architecture with clear separation between backend and frontend:
|
|
|
|
- **Backend**: .NET 10 Web API with SQL Server
|
|
- **Frontend**: Next.js with TypeScript
|
|
- **Architecture Style**: Layered architecture with SQL-first approach
|
|
|
|
## Diagrams
|
|
|
|
For visual representations, see:
|
|
- [architecture.pdf](diagrams/pdf/architecture.pdf) - Layered architecture diagram
|
|
- [deployment.pdf](diagrams/pdf/deployment.pdf) - Docker deployment diagram
|
|
- [authentication-flow.pdf](diagrams/pdf/authentication-flow.pdf) - Authentication workflow
|
|
- [database-schema.pdf](diagrams/pdf/database-schema.pdf) - Database relationships
|
|
|
|
Generate diagrams with: `make diagrams`
|
|
|
|
## Backend Architecture
|
|
|
|
### Layered Architecture Pattern
|
|
|
|
The backend follows a strict layered architecture:
|
|
|
|
```
|
|
┌─────────────────────────────────────┐
|
|
│ API Layer (Controllers) │
|
|
│ - HTTP Endpoints │
|
|
│ - Request/Response mapping │
|
|
│ - Swagger/OpenAPI │
|
|
└─────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────┐
|
|
│ Service Layer (Business Logic) │
|
|
│ - Authentication logic │
|
|
│ - User management │
|
|
│ - Validation & orchestration │
|
|
└─────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────┐
|
|
│ Infrastructure Layer (Tools) │
|
|
│ - JWT token generation │
|
|
│ - Password hashing (Argon2id) │
|
|
│ - Email services │
|
|
│ - Repository implementations │
|
|
└─────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────┐
|
|
│ Domain Layer (Entities) │
|
|
│ - UserAccount, UserCredential │
|
|
│ - Pure POCO classes │
|
|
│ - No external dependencies │
|
|
└─────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────┐
|
|
│ Database (SQL Server) │
|
|
│ - Stored procedures │
|
|
│ - Tables & constraints │
|
|
└─────────────────────────────────────┘
|
|
```
|
|
|
|
### Layer Responsibilities
|
|
|
|
#### API Layer (`API.Core`)
|
|
|
|
**Purpose**: HTTP interface and request handling
|
|
|
|
**Components**:
|
|
- Controllers (`AuthController`, `UserController`)
|
|
- Middleware for error handling
|
|
- Swagger/OpenAPI documentation
|
|
- Health check endpoints
|
|
|
|
**Dependencies**:
|
|
- Service layer
|
|
- ASP.NET Core framework
|
|
|
|
**Rules**:
|
|
- No business logic
|
|
- Only request/response transformation
|
|
- Delegates all work to Service layer
|
|
|
|
#### Service Layer (`Service.Auth`, `Service.UserManagement`)
|
|
|
|
**Purpose**: Business logic and orchestration
|
|
|
|
**Components**:
|
|
- Authentication services (login, registration)
|
|
- User management services
|
|
- Business rule validation
|
|
- Transaction coordination
|
|
|
|
**Dependencies**:
|
|
- Infrastructure layer (repositories, JWT, password hashing)
|
|
- Domain entities
|
|
|
|
**Rules**:
|
|
- Contains all business logic
|
|
- Coordinates multiple infrastructure components
|
|
- No direct database access (uses repositories)
|
|
- Returns domain models, not DTOs
|
|
|
|
#### Infrastructure Layer
|
|
|
|
**Purpose**: Technical capabilities and external integrations
|
|
|
|
**Components**:
|
|
- **Infrastructure.Repository**: Data access via stored procedures
|
|
- **Infrastructure.Jwt**: JWT token generation and validation
|
|
- **Infrastructure.PasswordHashing**: Argon2id password hashing
|
|
- **Infrastructure.Email**: Email sending capabilities
|
|
- **Infrastructure.Email.Templates**: Email template rendering
|
|
|
|
**Dependencies**:
|
|
- Domain entities
|
|
- External libraries (ADO.NET, JWT, Argon2, etc.)
|
|
|
|
**Rules**:
|
|
- Implements technical concerns
|
|
- No business logic
|
|
- Reusable across services
|
|
|
|
#### 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
|
|
|
|
#### Repository Pattern
|
|
|
|
**Purpose**: Abstract database access behind interfaces
|
|
|
|
**Implementation**:
|
|
- `IAuthRepository` - Authentication queries
|
|
- `IUserAccountRepository` - User account queries
|
|
- `DefaultSqlConnectionFactory` - Connection management
|
|
|
|
**Benefits**:
|
|
- Testable (easy to mock)
|
|
- SQL-first approach (stored procedures)
|
|
- Centralized data access logic
|
|
|
|
**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` registers all services
|
|
|
|
**Lifetimes**:
|
|
- Scoped: Repositories, Services (per request)
|
|
- Singleton: Connection factories, JWT configuration
|
|
- Transient: Utilities, helpers
|
|
|
|
#### SQL-First Approach
|
|
|
|
**Purpose**: Leverage database capabilities
|
|
|
|
**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
|
|
|
|
### Next.js Application Structure
|
|
|
|
```
|
|
Website/src/
|
|
├── components/ # React components
|
|
├── pages/ # Next.js routes
|
|
├── contexts/ # React context providers
|
|
├── hooks/ # Custom React hooks
|
|
├── controllers/ # Business logic layer
|
|
├── services/ # API communication
|
|
├── requests/ # API request builders
|
|
├── validation/ # Form validation schemas
|
|
├── config/ # Configuration & env vars
|
|
└── prisma/ # Database schema (current)
|
|
```
|
|
|
|
### Migration Strategy
|
|
|
|
The frontend is **transitioning** from a standalone architecture to integrate with the .NET API:
|
|
|
|
**Current State**:
|
|
- Uses Prisma ORM with Postgres (Neon)
|
|
- Has its own server-side API routes
|
|
- Direct database access from Next.js
|
|
|
|
**Target State**:
|
|
- Pure client-side Next.js app
|
|
- All data via .NET API
|
|
- No server-side database access
|
|
- JWT-based authentication
|
|
|
|
## 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)
|
|
|
|
**Rationale**:
|
|
- Argon2 winner of Password Hashing Competition (2015)
|
|
- Memory-hard (resistant to GPU/ASIC attacks)
|
|
- Configurable resource usage
|
|
|
|
### 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](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 │ ← Service.Auth.Tests
|
|
│ (Service) │ Repository.Tests
|
|
├──────────────┤
|
|
│ Unit Tests │
|
|
│ (Repository) │
|
|
└──────────────┘
|
|
```
|
|
|
|
**Strategy**:
|
|
- Many unit tests (fast, isolated)
|
|
- Fewer integration tests (slower, e2e)
|
|
- Mock external dependencies
|
|
- Test database for integration tests
|
|
|
|
For details, see [Testing Guide](testing.md).
|
|
|
|
## Future Enhancements
|
|
|
|
### Planned Architecture Changes
|
|
|
|
- [ ] **CQRS Pattern**: Separate read and write models
|
|
- [ ] **Event Sourcing**: Audit trail for critical operations
|
|
- [ ] **Caching Layer**: Redis for frequently accessed data
|
|
- [ ] **Message Queue**: Background job processing
|
|
- [ ] **API Gateway**: Centralized routing and auth
|
|
- [ ] **Microservices**: Break into bounded contexts
|
|
|
|
### Scalability Considerations
|
|
|
|
- **Horizontal Scaling**: Stateless API design allows multiple instances
|
|
- **Database Scaling**: Read replicas for query load
|
|
- **CDN**: Static asset delivery via CDN
|
|
- **Load Balancing**: Distribute traffic across API instances
|