mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-10-15 10:04:44 +00:00
Cleanup prose in written documentation
This commit is contained in:
@@ -59,8 +59,8 @@ Scripts live under `scripts/`, applied in order and tracked so a script never
|
||||
re-runs once it has succeeded. Today that's `01-schema/`, with one script per
|
||||
table, numbered so a table's foreign keys always point at an earlier-numbered
|
||||
script. When the schema needs to change, add a new numbered script rather than
|
||||
editing an existing one in place — DbUp's tracking is per-script, so editing
|
||||
an already-applied script means it won't re-run against existing databases.
|
||||
editing an existing one in place: DbUp's tracking is per-script, so an edited
|
||||
already-applied script never re-runs against existing databases.
|
||||
|
||||
## Data seeding
|
||||
|
||||
@@ -68,7 +68,7 @@ an already-applied script means it won't re-run against existing databases.
|
||||
pipeline (see [Pipeline README](../pipeline/README.md)): countries,
|
||||
state/provinces, and cities (created on demand while resolving each brewery's
|
||||
location), user accounts, and brewery posts with locations. It doesn't call
|
||||
every feature slice that has a write path — `Photo`, for example, has a
|
||||
every feature slice that has a write path: `Photo`, for example, has a
|
||||
repository (`Features.PhotoUpload`) but no seed data.
|
||||
|
||||
## Database error handling
|
||||
@@ -78,10 +78,10 @@ repository (`Features.PhotoUpload`) but no seed data.
|
||||
- On failure, the repository throws a `Domain.Exceptions` type directly
|
||||
(`NotFoundException`, `ConflictException`, `ArgumentException`, ...).
|
||||
`API.Core`'s `GlobalExceptionFilter` maps these to HTTP status codes (404,
|
||||
409, 400, ...); an unmapped `SqlException` (e.g. a genuine connectivity or
|
||||
constraint-violation failure) maps to 503.
|
||||
409, 400, ...); an unmapped `SqlException` (for example, a genuine
|
||||
connectivity or constraint-violation failure) maps to 503.
|
||||
|
||||
- One exception: `Features.Users`' `DapperUserStore` does catch
|
||||
`SqlException` directly, to detect a duplicate-key race (SQL Server error
|
||||
2601 or 2627) when two requests try to verify the same account
|
||||
concurrently — see `DapperUserStore.IsDuplicateKeyViolation`.
|
||||
concurrently; see `DapperUserStore.IsDuplicateKeyViolation`.
|
||||
|
||||
@@ -100,7 +100,8 @@ frontend.tests # Storybook Vitest + Playwright suites (own Playwright image)
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
docker compose --env-file web/.env.test -f web/docker-compose.test.yaml up --abort-on-container-exit
|
||||
docker compose --env-file web/.env.test -f web/docker-compose.test.yaml up -d
|
||||
docker compose --env-file web/.env.test -f web/docker-compose.test.yaml wait api.specs unit.tests frontend.tests
|
||||
|
||||
# View results
|
||||
ls -la test-results/
|
||||
@@ -111,6 +112,13 @@ cat test-results/Features.Users.Tests.trx
|
||||
docker compose --env-file web/.env.test -f web/docker-compose.test.yaml down -v
|
||||
```
|
||||
|
||||
`wait` blocks until `api.specs`, `unit.tests`, and `frontend.tests` have all
|
||||
stopped, regardless of which one finishes first; `up --abort-on-container-exit`
|
||||
isn't used here because the one-shot `database.migrations`/`database.seed`
|
||||
jobs and `frontend.tests` (no database dependency) can exit before the other
|
||||
test containers, which would end the run prematurely. See
|
||||
[Testing](testing.md#running-tests-with-docker-recommended) for details.
|
||||
|
||||
### 3. Production (`docker-compose.prod.yaml`)
|
||||
|
||||
**Purpose**: Production-ready deployment
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Environment variables
|
||||
|
||||
This document covers the active environment variables used by the current
|
||||
Biergarten stack.
|
||||
This document covers the environment variables used by the Biergarten stack.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -19,10 +18,10 @@ Direct environment variable access via `Environment.GetEnvironmentVariable()`.
|
||||
|
||||
### Frontend (`web/frontend`)
|
||||
|
||||
The active website reads runtime values from the server environment for its auth
|
||||
and API integration. In Docker, the `frontend` service is wired into the same
|
||||
The website reads runtime values from the server environment for its auth and
|
||||
API integration. In Docker, the `frontend` service is wired into the same
|
||||
`web/.env.dev` / `.env.test` / `.env.prod` files as the backend; running it
|
||||
locally with `npm run dev` still reads from the shell environment.
|
||||
locally with `npm run dev` reads from the shell environment.
|
||||
|
||||
### Docker
|
||||
|
||||
@@ -104,7 +103,8 @@ WEBSITE_BASE_URL=https://thebiergarten.app # Base URL for the website
|
||||
**Security Requirements**:
|
||||
|
||||
- Use at least 32 characters per secret
|
||||
- Use 127 or more characters in production
|
||||
- Use secrets generated from 127 or more random bytes in production (base64
|
||||
encoding turns 127 bytes into a longer string, well over 127 characters)
|
||||
- Generate secrets with a cryptographically secure random function
|
||||
- Never reuse secrets across token types or environments
|
||||
- Rotate secrets periodically in production
|
||||
@@ -170,10 +170,17 @@ ASPNETCORE_URLS=http://0.0.0.0:8080 # Binding address and port
|
||||
DOTNET_RUNNING_IN_CONTAINER=true # Flag for container execution
|
||||
```
|
||||
|
||||
`ASPNETCORE_URLS` is hardcoded directly in `docker-compose.dev.yaml` and
|
||||
`docker-compose.prod.yaml` (not sourced from the `.env` file), so it's
|
||||
required only for Docker. Outside Docker, `dotnet run` falls back to the
|
||||
`http` profile in `API.Core/Properties/launchSettings.json`
|
||||
(`http://localhost:5069`), so manual backend setup (see
|
||||
[Getting Started](getting-started.md#manual-backend-setup)) doesn't need to
|
||||
set it.
|
||||
|
||||
## Frontend variables (`web/frontend`)
|
||||
|
||||
The active website does not use the old Next.js/Prisma environment model. Its
|
||||
core runtime variables are:
|
||||
The website's core runtime variables are:
|
||||
|
||||
```bash
|
||||
API_BASE_URL=http://api.core:8080 # Base URL for the .NET API (container DNS name in Docker)
|
||||
@@ -291,12 +298,6 @@ cp web/.env.example web/.env.dev
|
||||
# Edit web/.env.dev with your values
|
||||
```
|
||||
|
||||
## 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
|
||||
reference only and is not run as part of the active stack.
|
||||
|
||||
**Docker Compose Mapping**:
|
||||
|
||||
- `web/docker-compose.dev.yaml` → `web/.env.dev`
|
||||
@@ -334,7 +335,7 @@ reference only and is not run as part of the active stack.
|
||||
| `PORT` | | ✓ | ✓ | No | Frontend server port |
|
||||
| `CLEAR_DATABASE` | ✓ | | ✓ | No | Dev/test reset flag |
|
||||
| `ASPNETCORE_ENVIRONMENT` | ✓ | | ✓ | Yes | ASP.NET environment |
|
||||
| `ASPNETCORE_URLS` | ✓ | | ✓ | Yes | API binding address |
|
||||
| `ASPNETCORE_URLS` | ✓ | | ✓ | Yes\*\* | API binding address |
|
||||
| `SA_PASSWORD` | | | ✓ | Yes | SQL Server container |
|
||||
| `ACCEPT_EULA` | | | ✓ | Yes | SQL Server EULA |
|
||||
| `MSSQL_PID` | | | ✓ | No | SQL Server edition |
|
||||
@@ -343,6 +344,10 @@ reference only and is not run as part of the active stack.
|
||||
\* Either `DB_CONNECTION_STRING` OR the component variables (`DB_SERVER`,
|
||||
`DB_NAME`, `DB_USER`, `DB_PASSWORD`) must be provided.
|
||||
|
||||
\*\* Required for Docker, where it's hardcoded in the compose files. Outside
|
||||
Docker, `dotnet run` falls back to the `applicationUrl` in
|
||||
`launchSettings.json`.
|
||||
|
||||
## Validation
|
||||
|
||||
### Backend validation
|
||||
@@ -359,8 +364,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 website relies on runtime defaults for local development and on the server
|
||||
environment when deployed.
|
||||
|
||||
- `API_BASE_URL` defaults to `http://localhost:8080`
|
||||
- `SESSION_SECRET` falls back to a development-only local secret
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 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`.
|
||||
This guide covers local setup for the Biergarten stack: the .NET backend in
|
||||
`web/backend` and the React Router frontend in `web/frontend`.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -69,7 +69,7 @@ Available endpoints:
|
||||
- Mailpit UI: http://localhost:8025
|
||||
- SeaweedFS S3 API: http://localhost:8333
|
||||
|
||||
### 4. Start the active frontend
|
||||
### 4. Start the frontend
|
||||
|
||||
```bash
|
||||
cd web/frontend
|
||||
@@ -146,10 +146,10 @@ dotnet run --project Database/Database.Seed/Database.Seed.csproj
|
||||
dotnet run --project API/API.Core/API.Core.csproj
|
||||
```
|
||||
|
||||
## Legacy frontend note
|
||||
## Archived frontend
|
||||
|
||||
The previous Next.js frontend lives in `archive/next-js-web-app/` for reference
|
||||
only and is not the active website.
|
||||
`archive/next-js-web-app/` contains an archived Next.js frontend, kept for
|
||||
reference; it is not part of the running stack.
|
||||
|
||||
## Next steps
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ The project uses a multi-layered testing approach across backend and frontend:
|
||||
|
||||
## Running tests with Docker (recommended)
|
||||
|
||||
The easiest way to run all tests is using Docker Compose, which sets up an
|
||||
isolated test environment:
|
||||
To run all tests, use Docker Compose, which sets up an isolated test
|
||||
environment:
|
||||
|
||||
```bash
|
||||
docker compose --env-file web/.env.test -f web/docker-compose.test.yaml up -d
|
||||
@@ -43,7 +43,7 @@ This command:
|
||||
stopped, regardless of which one finishes first. Long-running services
|
||||
(`sqlserver`, `seaweedfs`) and the one-shot `database.migrations` /
|
||||
`database.seed` jobs keep running in the background alongside them and are
|
||||
torn down separately (see below) — `wait` doesn't touch them.
|
||||
torn down separately (see below); `wait` doesn't touch them.
|
||||
|
||||
### View test results
|
||||
|
||||
@@ -355,15 +355,12 @@ The workflow inspects the exit code of each test container
|
||||
after `wait` returns and fails the job if any of them is non-zero.
|
||||
`./test-results/` is uploaded as a build artifact regardless of outcome.
|
||||
|
||||
Earlier versions of this workflow used
|
||||
`up --abort-on-container-exit`, which stops the entire stack the instant
|
||||
*any* watched container exits. That's wrong here: the one-shot
|
||||
`database.migrations`/`database.seed` jobs are expected to exit 0 partway
|
||||
through, and even scoping the flag to just the three test services doesn't
|
||||
help, since `frontend.tests` (no database dependency) reliably finishes
|
||||
before `api.specs`/`unit.tests` even start, aborting them prematurely.
|
||||
`up -d` + `wait` avoids both races by not tying container teardown to any
|
||||
single container's exit.
|
||||
`up -d` + `wait` keeps container teardown independent of any single
|
||||
container's exit. The one-shot `database.migrations`/`database.seed` jobs
|
||||
exit 0 partway through the run, and `frontend.tests` (which has no database
|
||||
dependency) reliably finishes before `api.specs`/`unit.tests` start; because
|
||||
`wait` blocks on all three test containers, neither early exit ends the run
|
||||
prematurely.
|
||||
|
||||
Exit codes:
|
||||
|
||||
@@ -414,13 +411,13 @@ act push \
|
||||
`sqlserver` service's image is amd64-only, and act needs to know to
|
||||
emulate that platform for the whole job container, not just that one
|
||||
service.
|
||||
- No secrets or `.actrc` are needed — `generate-env.sh` creates its own
|
||||
- No secrets or `.actrc` are needed: `generate-env.sh` creates its own
|
||||
`.env.test` with freshly randomized values, same as in real CI.
|
||||
|
||||
**Known act-only limitation**: the "Upload test results" step
|
||||
(`actions/upload-artifact@v4`) fails locally with `Unable to get the
|
||||
ACTIONS_RUNTIME_TOKEN env variable`. act doesn't provide a real Actions
|
||||
artifact backend, so this step — and only this step — is expected to fail
|
||||
artifact backend, so this step, and only this step, is expected to fail
|
||||
under act even when everything else passes. It works normally on
|
||||
GitHub-hosted runners.
|
||||
|
||||
@@ -429,7 +426,7 @@ names and named volumes (`sqlserverdata-test`, `seaweedfsdata-test`) scoped
|
||||
to the `web` compose project. If a previous local run (via `act` or a
|
||||
manual `docker compose` invocation) didn't get torn down, its SQL Server
|
||||
volume can persist with an old `SA_PASSWORD` baked in, while a fresh
|
||||
`.env.test` generates a new one each run — causing `Login failed for user
|
||||
`.env.test` generates a new one each run, causing `Login failed for user
|
||||
'sa'` errors that look like a test bug but are really a leftover volume.
|
||||
Clear it before re-running:
|
||||
|
||||
|
||||
@@ -34,8 +34,7 @@ Low-level JWT operations.
|
||||
|
||||
#### [ITokenService](../../web/backend/Features/Features.Users/Services/ITokenService.cs)
|
||||
|
||||
Both token generation and validation live on the same slice-internal service
|
||||
(there is no separate validation service/class).
|
||||
Token generation and validation live on the same slice-internal service.
|
||||
|
||||
**Generation methods:**
|
||||
|
||||
@@ -79,9 +78,17 @@ directly.
|
||||
1. Receives confirmation token from user via `ConfirmUserCommand`
|
||||
2. Calls `ITokenService.ValidateConfirmationTokenAsync()`
|
||||
3. Extracts user ID from validated token and looks it up via `UserManager<ApplicationUser>`
|
||||
4. Marks the account confirmed via `IUserEmailStore<ApplicationUser>.SetEmailConfirmedAsync()`
|
||||
4. Marks the account confirmed via `IUserEmailStore<ApplicationUser>.SetEmailConfirmedAsync()`,
|
||||
then persists it via `UserManager<ApplicationUser>.UpdateAsync()`
|
||||
5. Returns confirmation result
|
||||
|
||||
`UserManager<ApplicationUser>` and `IUserEmailStore<ApplicationUser>` are
|
||||
ASP.NET Core Identity's abstractions, not EF Core's default Identity store:
|
||||
the app backs them with its own `DapperUserStore` (see
|
||||
[Database](database.md#database-error-handling)), which persists against the
|
||||
existing `UserAccount`/`UserCredential`/`UserVerification` tables via Dapper,
|
||||
consistent with the rest of the app's repository pattern.
|
||||
|
||||
#### [ResendConfirmationEmailHandler](../../web/backend/Features/Features.Users/Commands/Authentication/ResendConfirmationEmail/ResendConfirmationEmailHandler.cs)
|
||||
|
||||
**Flow:**
|
||||
|
||||
Reference in New Issue
Block a user