Documentation updates (#236)

Remove vague or flowery language, use Simplified Technical English whenever possible
This commit is contained in:
Aaron Po
2026-08-04 09:38:24 -04:00
parent 30cdb48491
commit b27b5bdb40
10 changed files with 272 additions and 250 deletions

View File

@@ -1,4 +1,4 @@
# Docker Guide
# Docker guide
This document covers Docker deployment, configuration, and troubleshooting for
The Biergarten App.
@@ -16,7 +16,7 @@ The project uses Docker Compose to orchestrate multiple services:
See the [deployment diagram](diagrams-out/deployment.svg) for visual
representation.
## Docker Compose Environments
## Docker Compose environments
### 1. Development (`docker-compose.dev.yaml`)
@@ -66,7 +66,7 @@ docker compose --env-file web/.env.dev -f web/docker-compose.dev.yaml down -v
### 2. Testing (`docker-compose.test.yaml`)
**Purpose**: Automated CI/CD testing in isolated environment
**Purpose**: Automated CI/CD testing in an isolated environment
**Features**:
@@ -128,18 +128,15 @@ api.core # Production API
docker compose --env-file web/.env.prod -f web/docker-compose.prod.yaml up -d
```
## Service Dependencies
## Service dependencies
Docker Compose manages startup order using health checks:
```mermaid
sqlserver (health check)
↓
database.migrations (completes successfully)
↓
database.seed (completes successfully)
↓
api.core / tests (start when ready)
graph TD
A[sqlserver: health check passes] --> B[database.migrations: completes successfully]
B --> C[database.seed: completes successfully]
C --> D[api.core / tests: start when ready]
```
**Health Check Example** (SQL Server):
@@ -168,7 +165,7 @@ api.core:
## Volumes
### Persistent Volumes
### Persistent volumes
**Development**:
@@ -184,7 +181,7 @@ api.core:
- `sqlserverdata-prod` - Production database files
- `nuget-cache-prod` - Production NuGet cache
### Mounted Volumes
### Mounted volumes
**Test Results**:
@@ -203,7 +200,7 @@ Each environment uses isolated bridge networks:
- `testnet` - Testing network (fully isolated)
- `prodnet` - Production network
## Environment Variables
## Environment variables
All containers are configured via environment variables from `.env` files:
@@ -224,9 +221,9 @@ environment:
For complete list, see [Environment Variables](environment-variables.md).
## Common Commands
## Common commands
### View Services
### View services
```bash
# Running services
@@ -236,7 +233,7 @@ docker compose --env-file web/.env.dev -f web/docker-compose.dev.yaml ps
docker ps -a
```
### View Logs
### View logs
```bash
# All services
@@ -249,17 +246,17 @@ docker compose --env-file web/.env.dev -f web/docker-compose.dev.yaml logs -f ap
docker compose --env-file web/.env.dev -f web/docker-compose.dev.yaml logs --tail=100 api.core
```
### Execute Commands in Container
### Execute commands in container
```bash
# Interactive shell
docker exec -it dev-env-api-core bash
# Run command
docker exec dev-env-sqlserver /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'password' -C
# Run command (replace <db-password> with the value of DB_PASSWORD from .env.dev)
docker exec dev-env-sqlserver /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P '<db-password>' -C
```
### Restart Services
### Restart services
```bash
# Restart all services
@@ -272,7 +269,7 @@ docker compose --env-file web/.env.dev -f web/docker-compose.dev.yaml restart ap
docker compose --env-file web/.env.dev -f web/docker-compose.dev.yaml up -d --build api.core
```
### Build Images
### Build images
```bash
# Build all images
@@ -285,7 +282,7 @@ docker compose --env-file web/.env.dev -f web/docker-compose.dev.yaml build api.
docker compose --env-file web/.env.dev -f web/docker-compose.dev.yaml build --no-cache
```
### Clean Up
### Clean up
```bash
# Stop and remove containers
@@ -301,9 +298,9 @@ docker compose --env-file web/.env.dev -f web/docker-compose.dev.yaml down -v --
docker system prune -af --volumes
```
## Dockerfile Structure
## Dockerfile structure
### Multi-Stage Build
### Multi-stage build
```dockerfile
# Stage 1: Build
@@ -321,7 +318,7 @@ COPY --from=build /app/build .
ENTRYPOINT ["dotnet", "Project.dll"]
```
## Additional Resources
## Additional resources
- [Docker Compose Documentation](https://docs.docker.com/compose/)
- [.NET Docker Images](https://hub.docker.com/_/microsoft-dotnet)

View File

@@ -1,4 +1,4 @@
# Environment Variables
# Environment variables
This document covers the active environment variables used by the current
Biergarten stack.
@@ -11,7 +11,7 @@ The application uses environment variables for:
- **React Router website** - API base URL and session signing
- **Docker containers** - environment-specific orchestration
## Configuration Patterns
## Configuration patterns
### Backend (.NET API)
@@ -30,9 +30,9 @@ Environment-specific `.env` files loaded via `env_file:` in docker-compose.yaml:
- `.env.test` - Testing
- `.env.prod` - Production
## Backend Variables (.NET API)
## Backend variables (.NET API)
### Database Connection
### Database connection
**Option 1: Component-Based (Recommended for Docker)**
@@ -59,7 +59,7 @@ string is built from components.
**Implementation**: See `DefaultSqlConnectionFactory.cs`
### JWT Authentication Secrets (Backend)
### JSON Web Token (JWT) authentication secrets (backend)
The backend uses separate secrets for different token types to enable
independent key rotation and validation isolation.
@@ -80,9 +80,9 @@ WEBSITE_BASE_URL=https://thebiergarten.app # Base URL for the website
**Security Requirements**:
- Each secret should be minimum 32 characters
- Recommend 127+ characters for production
- Generate using cryptographically secure random functions
- Use at least 32 characters per secret
- Use 127 or more characters in production
- Generate secrets with a cryptographically secure random function
- Never reuse secrets across token types or environments
- Rotate secrets periodically in production
@@ -110,19 +110,20 @@ openssl rand -base64 127
- **Handler**: Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler
- **Validation**: Token signature, expiration, and malformed token checks
### Migration Control
### Migration control
```bash
CLEAR_DATABASE=true
```
- **Required**: No
- **Default**: false
- **Effect**: If "true", drops and recreates database during migrations
- **Usage**: Development and testing environments ONLY
- **Warning**: NEVER use in production
- **Default**: `false`
- **Effect**: If set to `true`, drops and recreates the database during
migrations
- **Usage**: Development and testing environments only
- **Warning**: Never use in production
### ASP.NET Core Configuration
### ASP.NET Core configuration
```bash
ASPNETCORE_ENVIRONMENT=Development # Development, Production, Staging
@@ -130,7 +131,7 @@ ASPNETCORE_URLS=http://0.0.0.0:8080 # Binding address and port
DOTNET_RUNNING_IN_CONTAINER=true # Flag for container execution
```
## Frontend Variables (`web/frontend`)
## Frontend variables (`web/frontend`)
The active website does not use the old Next.js/Prisma environment model. Its
core runtime variables are:
@@ -141,7 +142,7 @@ SESSION_SECRET=<generated-secret> # Cookie session signing secret
NODE_ENV=development # Standard Node runtime mode
```
### Frontend Variable Details
### Frontend variable details
#### `API_BASE_URL`
@@ -163,7 +164,7 @@ NODE_ENV=development # Standard Node runtime mode
- **Typical values**: `development`, `production`, `test`
- **Purpose**: Controls secure cookie behavior and runtime mode
### SMTP Configuration (Backend)
### SMTP configuration (backend)
Read by `Infrastructure.Email/SmtpEmailProvider.cs` for sending confirmation
and account emails.
@@ -183,11 +184,11 @@ SMTP_FROM_NAME=The Biergarten App # Optional, defaults to "The Biergarten
- **Local dev**: point at the `mailpit` Docker service (SMTP on port 1025, web
UI on http://localhost:8025)
- **Production**: point at a real provider (SendGrid, Mailgun, Amazon SES,
etc.)
and so on)
## Docker-Specific Variables
## Docker-specific variables
### SQL Server Container
### SQL Server container
```bash
SA_PASSWORD=YourStrong!Passw0rd # SQL Server SA password
@@ -201,9 +202,9 @@ MSSQL_PID=Express # SQL Server edition (Express, Developer, Ente
- Uppercase, lowercase, digits, and special characters
- Maps to `DB_PASSWORD` for application containers
## Environment File Structure
## Environment file structure
### Backend/Docker (`web/` Directory)
### Backend/Docker (`web/` directory)
```
web/.env.example # Template (tracked in Git)
@@ -219,7 +220,7 @@ cp web/.env.example web/.env.dev
# Edit web/.env.dev with your values
```
## Legacy Frontend Variables
## Legacy frontend variables
Variables for the archived Next.js frontend (`archive/next-js-web-app/`) have
been removed from this active reference, since that app is retained for
@@ -231,7 +232,7 @@ reference only and is not run as part of the active stack.
- `web/docker-compose.test.yaml` → `web/.env.test`
- `web/docker-compose.prod.yaml` → `web/.env.prod`
## Variable Reference Table
## Variable reference table
| Variable | Backend | Frontend | Docker | Required | Notes |
| ----------------------------- | :-----: | :------: | :----: | :------: | -------------------------- |
@@ -268,7 +269,7 @@ reference only and is not run as part of the active stack.
## Validation
### Backend Validation
### Backend validation
Variables are validated at startup:
@@ -279,7 +280,7 @@ Variables are validated at startup:
"minimum 32 characters" guidance above is a recommendation, not an
enforced check
### Frontend Validation
### Frontend validation
The active website relies on runtime defaults for local development and the
surrounding server environment in deployed environments.
@@ -288,9 +289,9 @@ surrounding server environment in deployed environments.
- `SESSION_SECRET` falls back to a development-only local secret
- `NODE_ENV` controls secure cookie behavior
## Example Configuration Files
## Example configuration files
### `.env.dev` (Backend/Docker)
### `.env.dev` (backend/Docker)
```bash
# Database

View File

@@ -1,4 +1,4 @@
# Getting Started
# Getting started
This guide covers local setup for the current Biergarten stack: the .NET backend
in `web/backend` and the active React Router frontend in `web/frontend`.
@@ -10,16 +10,16 @@ in `web/backend` and the active React Router frontend in `web/frontend`.
- **Docker Desktop** or equivalent Docker Engine setup
- **Java 8+** if you want to regenerate PlantUML diagrams
## Recommended Path: Docker for Backend, Node for Frontend
## Recommended path: Docker for backend, Node for frontend
### 1. Clone the Repository
### 1. Clone the repository
```bash
git clone <repository-url>
git clone https://github.com/aaronpo97/the-biergarten-app
cd the-biergarten-app
```
### 2. Configure Backend Environment Variables
### 2. Configure backend environment variables
```bash
cp web/.env.example web/.env.dev
@@ -40,7 +40,7 @@ WEBSITE_BASE_URL=http://localhost:3000
See [Environment Variables](environment-variables.md) for the full list.
### 3. Start the Backend Stack
### 3. Start the backend stack
```bash
docker compose --env-file web/.env.dev -f web/docker-compose.dev.yaml up -d
@@ -54,7 +54,7 @@ Available endpoints:
- Health Check: http://localhost:8080/health
- Mailpit UI: http://localhost:8025
### 4. Start the Active Frontend
### 4. Start the active frontend
```bash
cd web/frontend
@@ -69,7 +69,7 @@ Required frontend runtime variables for local work:
- `API_BASE_URL` - Base URL for the .NET API
- `SESSION_SECRET` - Cookie session signing secret for the website server
### 5. Optional: Run Storybook
### 5. Optional: run Storybook
```bash
cd web/frontend
@@ -78,7 +78,7 @@ npm run storybook
Storybook runs at http://localhost:6006 by default.
## Useful Commands
## Useful commands
### Backend
@@ -99,11 +99,11 @@ npm run test:storybook
npm run test:storybook:playwright
```
## Manual Backend Setup
## Manual backend setup
If you do not want to use Docker, you can run the backend locally.
### 1. Set Environment Variables
### 1. Set environment variables
```bash
export DB_CONNECTION_STRING="Server=localhost,1433;Database=Biergarten;User Id=sa;Password=YourStrong!Passw0rd;TrustServerCertificate=True;"
@@ -113,7 +113,7 @@ export CONFIRMATION_TOKEN_SECRET="<generated>"
export WEBSITE_BASE_URL="http://localhost:3000"
```
### 2. Run Migrations and Seed
### 2. Run migrations and seed
```bash
cd web/backend
@@ -127,12 +127,12 @@ dotnet run --project Database/Database.Seed/Database.Seed.csproj
dotnet run --project API/API.Core/API.Core.csproj
```
## Legacy Frontend Note
## Legacy frontend note
The previous Next.js frontend lives in `archive/next-js-web-app/` for reference
only and is not the active website.
## Next Steps
## Next steps
- Review [Architecture](../architecture.md)
- Run backend and frontend checks from [Testing](testing.md)

View File

@@ -19,7 +19,7 @@ The project uses a multi-layered testing approach across backend and frontend:
- **Storybook Playwright suite** - Browser checks against Storybook-rendered
components
## Running Tests with Docker (Recommended)
## Running tests with Docker (recommended)
The easiest way to run all tests is using Docker Compose, which sets up an
isolated test environment:
@@ -37,7 +37,7 @@ This command:
5. Exports results to `./test-results/`
6. Exits when tests complete
### View Test Results
### View test results
```bash
# List test result files
@@ -51,18 +51,18 @@ cat test-results/Features.UserManagement.Tests.trx
cat test-results/Features.Emails.Tests.trx
```
### Clean Up
### Clean up
```bash
# Remove test containers and volumes
docker compose --env-file web/.env.test -f web/docker-compose.test.yaml down -v
```
## Running Tests Locally
## Running tests locally
You can run individual test projects locally without Docker:
### Integration Tests (API.Specs)
### Integration tests (API.Specs)
```bash
cd web/backend
@@ -75,7 +75,7 @@ dotnet test API/API.Specs/API.Specs.csproj
- Database migrated and seeded
- Environment variables set (DB connection, JWT secret)
### Feature Slice Unit Tests
### Feature slice unit tests
Each feature slice has its own test project, covering its command/query
handlers and repository:
@@ -96,7 +96,7 @@ for proj in Features/*.Tests; do dotnet test "$proj"; done
- No database required (handlers use Moq; repository tests use DbMocker to
simulate SQL Server responses)
### Frontend Storybook Tests
### Frontend Storybook tests
```bash
cd web/frontend
@@ -110,7 +110,7 @@ npm run test:storybook
toasts, and the theme gallery
- Runs in browser mode via Vitest and Storybook integration
### Frontend Playwright Storybook Tests
### Frontend Playwright Storybook tests
```bash
cd web/frontend
@@ -125,9 +125,9 @@ npm run test:storybook:playwright
- The command will start or reuse the Storybook server defined in
`playwright.storybook.config.ts`
## Test Coverage
## Test coverage
### Current Coverage
### Current coverage
**Features.Auth.Tests**:
@@ -160,7 +160,7 @@ npm run test:storybook:playwright
- Theme gallery rendering across Biergarten themes
- Toast interactions and themed notification display
### Planned Coverage
### Planned coverage
- [ ] Password reset functionality
- [ ] Beer post operations
@@ -168,7 +168,7 @@ npm run test:storybook:playwright
- [ ] Image upload service
- [ ] Frontend route integration coverage beyond Storybook stories
## Testing Frameworks & Tools
## Testing frameworks and tools
### xUnit
@@ -200,9 +200,9 @@ npm run test:storybook:playwright
- Simulates SQL Server responses
- No real database required for unit tests
## Test Structure
## Test structure
### API.Specs (Integration Tests)
### API.Specs (integration tests)
```
API.Specs/
@@ -260,9 +260,9 @@ Each of the other three slices (`Features.Breweries.Tests`,
`Features.UserManagement.Tests`, `Features.Emails.Tests`) follows the same
shape: a `Commands/`/`Queries/` folder with one test file per handler.
## Writing Tests
## Writing tests
### Unit Test Example (xUnit)
### Unit test example (xUnit)
```csharp
public class LoginHandlerTests
@@ -287,7 +287,7 @@ public class LoginHandlerTests
}
```
### Integration Test Example (Reqnroll)
### Integration test example (Reqnroll)
```gherkin
Scenario: User login with valid credentials
@@ -297,7 +297,7 @@ Scenario: User login with valid credentials
And the response should contain a JWT token
```
## Continuous Integration
## Continuous integration
Tests run automatically in CI/CD pipelines using the test Docker Compose
configuration:
@@ -326,7 +326,7 @@ npm run test:storybook:playwright
## Troubleshooting
### Tests Failing Due to Database Connection
### Tests failing due to database connection
Ensure SQL Server is running and environment variables are set:
@@ -334,12 +334,12 @@ Ensure SQL Server is running and environment variables are set:
docker compose --env-file web/.env.test -f web/docker-compose.test.yaml ps
```
### Port Conflicts
### Port conflicts
If port 1433 is in use, stop other SQL Server instances or modify the port in
`docker-compose.test.yaml`.
### Stale Test Data
### Stale test data
Clean up test database:
@@ -347,13 +347,13 @@ Clean up test database:
docker compose --env-file web/.env.test -f web/docker-compose.test.yaml down -v
```
### View Container Logs
### View container logs
```bash
docker compose --env-file web/.env.test -f web/docker-compose.test.yaml logs <service-name>
```
## Best Practices
## Best practices
1. **Isolation**: Each test should be independent and not rely on other tests
2. **Cleanup**: Use fixtures and dispose patterns for resource cleanup

View File

@@ -1,8 +1,8 @@
# Token Validation Architecture
# Token validation architecture
## Overview
The Core project validates JWTs across three token types:
The Core project validates JSON Web Tokens (JWTs) 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
@@ -12,7 +12,7 @@ The Core project validates JWTs across three token types:
## Components
### Infrastructure Layer
### Infrastructure layer
#### [ITokenInfrastructure](../../web/backend/Infrastructure/Infrastructure.Jwt/ITokenInfrastructure.cs)
@@ -30,7 +30,7 @@ Low-level JWT operations.
- Algorithm: HS256 (HMAC-SHA256)
- Validates token lifetime, signature, and well-formedness
### Features.Auth Slice
### Features.Auth slice
#### [ITokenService](../../web/backend/Features/Features.Auth/Services/ITokenService.cs)
@@ -69,7 +69,7 @@ registered by the host (`API.Core/Program.cs`) since
`JwtAuthenticationHandler` (host-level auth middleware) also depends on
it directly.
### Integration Points
### Integration points
#### [ConfirmUserHandler](../../web/backend/Features/Features.Auth/Commands/ConfirmUser/ConfirmUserHandler.cs)
@@ -112,9 +112,9 @@ it directly.
- `POST /api/auth/confirm/resend?userId=...` - Resend the confirmation email
- `POST /api/auth/refresh` - Refresh access token
## Validation Security
## Validation security
### Token Secrets
### Token secrets
Three independent secrets enable:
@@ -130,7 +130,7 @@ REFRESH_TOKEN_SECRET=... # Signs 21-day refresh tokens
CONFIRMATION_TOKEN_SECRET=... # Signs 30-minute confirmation tokens
```
### Validation Checks
### Validation checks
Each token is validated for:
@@ -139,7 +139,7 @@ Each token is validated for:
3. **Claims Presence** - Required claims (Sub, UniqueName) must be present
4. **Claims Format** - UserId claim must be a valid GUID
### Error Handling
### Error handling
Validation failures return HTTP 401 Unauthorized:
@@ -148,9 +148,9 @@ Validation failures return HTTP 401 Unauthorized:
- Missing claims → "Invalid token"
- Malformed claims → "Invalid token"
## Token Lifecycle
## Token lifecycle
### Access Token Lifecycle
### Access token lifecycle
1. **Generation**: During login (1-hour validity)
2. **Usage**: Included in Authorization header on API requests
@@ -158,16 +158,16 @@ Validation failures return HTTP 401 Unauthorized:
4. **Expiration**: Token becomes invalid after 1 hour
5. **Refresh**: Use refresh token to obtain new access token
### Refresh Token Lifecycle
### Refresh token lifecycle
1. **Generation**: During login (21-day validity)
2. **Storage**: Client-side (secure storage)
3. **Usage**: Posted to `/api/auth/refresh` endpoint
4. **Validation**: Validated by RefreshTokenService
4. **Validation**: Validated by `ITokenService.RefreshTokenAsync()`
5. **Rotation**: New refresh token issued on successful refresh
6. **Expiration**: Token becomes invalid after 21 days
### Confirmation Token Lifecycle
### Confirmation token lifecycle
1. **Generation**: During user registration (30-minute validity)
2. **Delivery**: Emailed to user in confirmation link
@@ -180,7 +180,7 @@ Validation failures return HTTP 401 Unauthorized:
All of the following live in `Features.Auth.Tests`.
### Unit Tests
### Unit tests
**Services/TokenServiceValidationTests.cs**
@@ -210,7 +210,7 @@ All of the following live in `Features.Auth.Tests`.
- Sends a fresh confirmation email when the user exists and is unverified
- No-ops when the user doesn't exist or is already verified
### BDD Tests (Reqnroll)
### BDD tests (Reqnroll)
**TokenRefresh.feature**
@@ -230,19 +230,19 @@ All of the following live in `Features.Auth.Tests`.
- Invalid/expired access token rejection
- Token type mismatch (refresh used as access token)
## Future Enhancements
## Future enhancements
### Stretch Goals
### Stretch goals
1. **Middleware for Access Token Validation**
- Automatically validate access tokens on protected routes
- Populate HttpContext.User from token claims
- Return 401 for invalid/missing tokens
2. **Token Blacklisting**
- Implement token revocation (e.g., on logout)
- Store blacklisted tokens in cache/database
- Check blacklist during validation
2. **Token Denylisting**
- Implement token revocation (for example, on logout)
- Store denylisted tokens in cache/database
- Check the denylist during validation
3. **Refresh Token Rotation Strategy**
- Detect token reuse (replay attacks)