Format all markdown files in active directories

This commit is contained in:
Aaron Po
2026-04-27 18:05:59 -04:00
parent b1f4ff2641
commit 7925fc6caf
11 changed files with 693 additions and 641 deletions

View File

@@ -4,24 +4,28 @@ 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:
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 and a layered architecture
- **Frontend**: React 19 + React Router 7 website in `src/Website`
- **Architecture Style**: Layered backend plus server-rendered React frontend
The legacy Next.js frontend has been retained in `src/Website-v1` for reference only and is
documented in [archive/legacy-website-v1.md](archive/legacy-website-v1.md).
The legacy Next.js frontend has been retained in `src/Website-v1` for reference
only and is documented in
[archive/legacy-website-v1.md](archive/legacy-website-v1.md).
## Diagrams
For visual representations, see:
- [architecture.svg](diagrams-out/architecture.svg) - Layered architecture diagram
- [architecture.svg](diagrams-out/architecture.svg) - Layered architecture
diagram
- [deployment.svg](diagrams-out/deployment.svg) - Docker deployment diagram
- [authentication-flow.svg](diagrams-out/authentication-flow.svg) - Authentication workflow
- [database-schema.svg](diagrams-out/database-schema.svg) - Database relationships
- [authentication-flow.svg](diagrams-out/authentication-flow.svg) -
Authentication workflow
- [database-schema.svg](diagrams-out/database-schema.svg) - Database
relationships
## Backend Architecture
@@ -218,7 +222,8 @@ public interface IAuthRepository
### Active Website (`src/Website`)
The current website is a React Router 7 application with server-side rendering enabled.
The current website is a React Router 7 application with server-side rendering
enabled.
```text
src/Website/
@@ -244,20 +249,22 @@ src/Website/
### Theme System
The active website uses semantic DaisyUI theme tokens backed by four Biergarten themes:
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.
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 `src/Website-v1`. Active product and
engineering documentation should point to `src/Website`, while legacy notes live in
The previous Next.js frontend has been archived at `src/Website-v1`. Active
product and engineering documentation should point to `src/Website`, while
legacy notes live in
[archive/legacy-website-v1.md](archive/legacy-website-v1.md).
## Security Architecture
@@ -387,8 +394,8 @@ For details, see [Docker Guide](docker.md).
### Health Checks
**SQL Server**: Validates database connectivity **API**: Checks service health and
dependencies
**SQL Server**: Validates database connectivity **API**: Checks service health
and dependencies
**Configuration**:

View File

@@ -1,7 +1,7 @@
# Docker Guide
This document covers Docker deployment, configuration, and troubleshooting for The
Biergarten App.
This document covers Docker deployment, configuration, and troubleshooting for
The Biergarten App.
## Overview
@@ -13,7 +13,8 @@ The project uses Docker Compose to orchestrate multiple services:
- .NET API
- Test runners
See the [deployment diagram](diagrams/pdf/deployment.pdf) for visual representation.
See the [deployment diagram](diagrams/pdf/deployment.pdf) for visual
representation.
## Docker Compose Environments
@@ -144,7 +145,11 @@ api.core / tests (start when ready)
```yaml
healthcheck:
test: ['CMD-SHELL', "sqlcmd -S localhost -U sa -P '${DB_PASSWORD}' -C -Q 'SELECT 1'"]
test:
[
"CMD-SHELL",
"sqlcmd -S localhost -U sa -P '${DB_PASSWORD}' -C -Q 'SELECT 1'",
]
interval: 10s
timeout: 5s
retries: 12
@@ -209,16 +214,16 @@ Each environment uses isolated bridge networks:
All containers are configured via environment variables from `.env` files:
```yaml
env_file: '.env.dev' # or .env.test, .env.prod
env_file: ".env.dev" # or .env.test, .env.prod
environment:
ASPNETCORE_ENVIRONMENT: 'Development'
DOTNET_RUNNING_IN_CONTAINER: 'true'
DB_SERVER: '${DB_SERVER}'
DB_NAME: '${DB_NAME}'
DB_USER: '${DB_USER}'
DB_PASSWORD: '${DB_PASSWORD}'
JWT_SECRET: '${JWT_SECRET}'
ASPNETCORE_ENVIRONMENT: "Development"
DOTNET_RUNNING_IN_CONTAINER: "true"
DB_SERVER: "${DB_SERVER}"
DB_NAME: "${DB_NAME}"
DB_USER: "${DB_USER}"
DB_PASSWORD: "${DB_PASSWORD}"
JWT_SECRET: "${JWT_SECRET}"
```
For complete list, see [Environment Variables](environment-variables.md).

View File

@@ -1,7 +1,7 @@
# Environment Variables
This document covers the active environment variables used by the current Biergarten
stack.
This document covers the active environment variables used by the current
Biergarten stack.
## Overview
@@ -19,8 +19,8 @@ Direct environment variable access via `Environment.GetEnvironmentVariable()`.
### Frontend (`src/Website`)
The active website reads runtime values from the server environment for its auth and API
integration.
The active website reads runtime values from the server environment for its auth
and API integration.
### Docker
@@ -54,14 +54,15 @@ Provide complete connection string:
DB_CONNECTION_STRING="Server=localhost,1433;Database=Biergarten;User Id=sa;Password=YourStrong!Passw0rd;TrustServerCertificate=True;"
```
**Priority**: `DB_CONNECTION_STRING` is checked first. If not found, connection string is
built from components.
**Priority**: `DB_CONNECTION_STRING` is checked first. If not found, connection
string is built from components.
**Implementation**: See `DefaultSqlConnectionFactory.cs`
### JWT Authentication Secrets (Backend)
The backend uses separate secrets for different token types to enable independent key rotation and validation isolation.
The backend uses separate secrets for different token types to enable
independent key rotation and validation isolation.
```bash
# Access token secret (1-hour tokens)
@@ -131,8 +132,8 @@ DOTNET_RUNNING_IN_CONTAINER=true # Flag for container execution
## Frontend Variables (`src/Website`)
The active website does not use the old Next.js/Prisma environment model. Its core runtime
variables are:
The active website does not use the old Next.js/Prisma environment model. Its
core runtime variables are:
```bash
API_BASE_URL=http://localhost:8080 # Base URL for the .NET API
@@ -208,9 +209,10 @@ cp .env.example .env.dev
## Legacy Frontend Variables
Variables for the archived Next.js frontend (`src/Website-v1`) have been removed from this
active reference. See [archive/legacy-website-v1.md](archive/legacy-website-v1.md) if you
need the legacy Prisma, Cloudinary, Mapbox, or SparkPost notes.
Variables for the archived Next.js frontend (`src/Website-v1`) have been removed
from this active reference. See
[archive/legacy-website-v1.md](archive/legacy-website-v1.md) if you need the
legacy Prisma, Cloudinary, Mapbox, or SparkPost notes.
**Docker Compose Mapping**:
@@ -243,8 +245,8 @@ need the legacy Prisma, Cloudinary, Mapbox, or SparkPost notes.
| `MSSQL_PID` | | | ✓ | No | SQL Server edition |
| `DOTNET_RUNNING_IN_CONTAINER` | ✓ | | ✓ | No | Container flag |
\* Either `DB_CONNECTION_STRING` OR the component variables (`DB_SERVER`, `DB_NAME`,
`DB_USER`, `DB_PASSWORD`) must be provided.
\* Either `DB_CONNECTION_STRING` OR the component variables (`DB_SERVER`,
`DB_NAME`, `DB_USER`, `DB_PASSWORD`) must be provided.
## Validation
@@ -258,8 +260,8 @@ Variables are validated at startup:
### Frontend Validation
The active website relies on runtime defaults for local development and the surrounding
server environment in deployed environments.
The active website relies on runtime defaults for local development and the
surrounding server environment in deployed environments.
- `API_BASE_URL` defaults to `http://localhost:8080`
- `SESSION_SECRET` falls back to a development-only local secret

View File

@@ -1,7 +1,7 @@
# Getting Started
This guide covers local setup for the current Biergarten stack: the .NET backend in
`src/Core` and the active React Router frontend in `src/Website`.
This guide covers local setup for the current Biergarten stack: the .NET backend
in `src/Core` and the active React Router frontend in `src/Website`.
## Prerequisites
@@ -128,8 +128,9 @@ dotnet run --project API/API.Core/API.Core.csproj
## Legacy Frontend Note
The previous Next.js frontend now lives in `src/Website-v1` and is not the active website.
Legacy setup details have been moved to [docs/archive/legacy-website-v1.md](archive/legacy-website-v1.md).
The previous Next.js frontend now lives in `src/Website-v1` and is not the
active website. Legacy setup details have been moved to
[docs/archive/legacy-website-v1.md](archive/legacy-website-v1.md).
## Next Steps

View File

@@ -1,6 +1,7 @@
# Testing
This document describes the testing strategy and how to run tests for The Biergarten App.
This document describes the testing strategy and how to run tests for The
Biergarten App.
## Overview
@@ -9,13 +10,15 @@ The project uses a multi-layered testing approach across backend and frontend:
- **API.Specs** - BDD integration tests using Reqnroll (Gherkin)
- **Infrastructure.Repository.Tests** - Unit tests for data access layer
- **Service.Auth.Tests** - Unit tests for authentication business logic
- **Storybook Vitest project** - Browser-based interaction tests for shared website stories
- **Storybook Playwright suite** - Browser checks against Storybook-rendered components
- **Storybook Vitest project** - Browser-based interaction tests for shared
website stories
- **Storybook Playwright suite** - Browser checks against Storybook-rendered
components
## Running Tests with Docker (Recommended)
The easiest way to run all tests is using Docker Compose, which sets up an isolated test
environment:
The easiest way to run all tests is using Docker Compose, which sets up an
isolated test environment:
```bash
docker compose -f docker-compose.test.yaml up --abort-on-container-exit
@@ -98,7 +101,8 @@ npm run test:storybook
**Purpose**:
- Verifies shared stories such as form fields, submit buttons, navbar states, toasts, and the theme gallery
- Verifies shared stories such as form fields, submit buttons, navbar states,
toasts, and the theme gallery
- Runs in browser mode via Vitest and Storybook integration
### Frontend Playwright Storybook Tests
@@ -113,7 +117,8 @@ npm run test:storybook:playwright
- Storybook dependencies installed
- Playwright browser dependencies installed
- The command will start or reuse the Storybook server defined in `playwright.storybook.config.ts`
- The command will start or reuse the Storybook server defined in
`playwright.storybook.config.ts`
## Test Coverage
@@ -278,7 +283,8 @@ Scenario: User login with valid credentials
## Continuous Integration
Tests run automatically in CI/CD pipelines using the test Docker Compose configuration:
Tests run automatically in CI/CD pipelines using the test Docker Compose
configuration:
```bash
# CI/CD command
@@ -292,7 +298,8 @@ Exit codes:
- `0` - All tests passed
- Non-zero - Test failures occurred
Frontend UI checks should also be included in CI for the active website workspace:
Frontend UI checks should also be included in CI for the active website
workspace:
```bash
cd src/Website

View File

@@ -2,11 +2,14 @@
## Overview
The Core project implements comprehensive JWT token validation across three token types:
The Core project implements comprehensive JWT token validation across three
token types:
- **Access Tokens**: Short-lived (1 hour) tokens for API authentication
- **Refresh Tokens**: Long-lived (21 days) tokens for obtaining new access tokens
- **Confirmation Tokens**: Short-lived (30 minutes) tokens for email confirmation
- **Refresh Tokens**: Long-lived (21 days) tokens for obtaining new access
tokens
- **Confirmation Tokens**: Short-lived (30 minutes) tokens for email
confirmation
## Components
@@ -17,10 +20,13 @@ The Core project implements comprehensive JWT token validation across three toke
Low-level JWT operations.
**Methods:**
- `GenerateJwt()` - Creates signed JWT tokens
- `ValidateJwtAsync()` - Validates token signature, expiration, and format
**Implementation:** [JwtInfrastructure.cs](Infrastructure.Jwt/JwtInfrastructure.cs)
**Implementation:**
[JwtInfrastructure.cs](Infrastructure.Jwt/JwtInfrastructure.cs)
- Uses Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler
- Algorithm: HS256 (HMAC-SHA256)
- Validates token lifetime, signature, and well-formedness
@@ -32,16 +38,20 @@ Low-level JWT operations.
High-level token validation with context (token type, user extraction).
**Methods:**
- `ValidateAccessTokenAsync(string token)` - Validates access tokens
- `ValidateRefreshTokenAsync(string token)` - Validates refresh tokens
- `ValidateConfirmationTokenAsync(string token)` - Validates confirmation tokens
**Returns:** `ValidatedToken` record containing:
- `UserId` (Guid)
- `Username` (string)
- `Principal` (ClaimsPrincipal) - Full JWT claims
**Implementation:** [TokenValidationService.cs](Service.Auth/TokenValidationService.cs)
**Implementation:**
[TokenValidationService.cs](Service.Auth/TokenValidationService.cs)
- Reads token secrets from environment variables
- Extracts and validates claims (Sub, UniqueName)
- Throws `UnauthorizedException` on validation failure
@@ -51,15 +61,18 @@ High-level token validation with context (token type, user extraction).
Token generation (existing service extended).
**Methods:**
- `GenerateAccessToken(UserAccount)` - Creates 1-hour access token
- `GenerateRefreshToken(UserAccount)` - Creates 21-day refresh token
- `GenerateConfirmationToken(UserAccount)` - Creates 30-minute confirmation token
- `GenerateConfirmationToken(UserAccount)` - Creates 30-minute confirmation
token
### Integration Points
#### [ConfirmationService](Service.Auth/IConfirmationService.cs)
**Flow:**
1. Receives confirmation token from user
2. Calls `TokenValidationService.ValidateConfirmationTokenAsync()`
3. Extracts user ID from validated token
@@ -69,6 +82,7 @@ Token generation (existing service extended).
#### [RefreshTokenService](Service.Auth/RefreshTokenService.cs)
**Flow:**
1. Receives refresh token from user
2. Calls `TokenValidationService.ValidateRefreshTokenAsync()`
3. Retrieves user account via `AuthRepository.GetUserByIdAsync()`
@@ -78,6 +92,7 @@ Token generation (existing service extended).
#### [AuthController](API.Core/Controllers/AuthController.cs)
**Endpoints:**
- `POST /api/auth/register` - Register new user
- `POST /api/auth/login` - Authenticate user
- `POST /api/auth/confirm?token=...` - Confirm email
@@ -88,11 +103,13 @@ Token generation (existing service extended).
### Token Secrets
Three independent secrets enable:
- **Key rotation** - Rotate each secret type independently
- **Isolation** - Compromise of one secret doesn't affect others
- **Different expiration** - Different token types can expire at different rates
**Environment Variables:**
```bash
ACCESS_TOKEN_SECRET=... # Signs 1-hour access tokens
REFRESH_TOKEN_SECRET=... # Signs 21-day refresh tokens
@@ -111,6 +128,7 @@ Each token is validated for:
### Error Handling
Validation failures return HTTP 401 Unauthorized:
- Invalid signature → "Invalid token"
- Expired token → "Invalid token" (message doesn't reveal reason for security)
- Missing claims → "Invalid token"
@@ -149,16 +167,19 @@ Validation failures return HTTP 401 Unauthorized:
### Unit Tests
**TokenValidationService.test.cs**
- Happy path: Valid token extraction
- Error cases: Invalid, expired, malformed tokens
- Missing/invalid claims scenarios
**RefreshTokenService.test.cs**
- Successful refresh with valid token
- Invalid/expired refresh token rejection
- Non-existent user handling
**ConfirmationService.test.cs**
- Successful confirmation with valid token
- Token validation failures
- User not found scenarios
@@ -166,16 +187,19 @@ Validation failures return HTTP 401 Unauthorized:
### BDD Tests (Reqnroll)
**TokenRefresh.feature**
- Successful token refresh
- Invalid/expired token rejection
- Missing token validation
**Confirmation.feature**
- Successful email confirmation
- Expired/tampered token rejection
- Missing token validation
**AccessTokenValidation.feature**
- Protected endpoint access token validation
- Invalid/expired access token rejection
- Token type mismatch (refresh used as access token)