mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-10-15 01:54:43 +00:00
Fix React Router/Node version claims, the Infrastructure.Sql rename, and point env setup at generate-env.sh
This commit is contained in:
15
README.md
15
README.md
@@ -40,7 +40,7 @@ Data generation pipeline (C++):
|
|||||||
Active areas in the repository:
|
Active areas in the repository:
|
||||||
|
|
||||||
- .NET 10 backend (vertical-slice architecture with MediatR) + SQL Server
|
- .NET 10 backend (vertical-slice architecture with MediatR) + SQL Server
|
||||||
- React 19 website (React Router 7 + Vite)
|
- React 19 website (React Router 8 + Vite)
|
||||||
- Shared Biergarten theme system + Storybook coverage
|
- Shared Biergarten theme system + Storybook coverage
|
||||||
- Auth flows and account/email integration (local Mailpit in dev compose)
|
- Auth flows and account/email integration (local Mailpit in dev compose)
|
||||||
- Photo upload to S3-compatible object storage (local SeaweedFS in dev compose)
|
- Photo upload to S3-compatible object storage (local SeaweedFS in dev compose)
|
||||||
@@ -54,7 +54,7 @@ Archived/reference areas:
|
|||||||
## Tech stack
|
## Tech stack
|
||||||
|
|
||||||
- **Backend**: .NET 10, ASP.NET Core, SQL Server 2022, DbUp
|
- **Backend**: .NET 10, ASP.NET Core, SQL Server 2022, DbUp
|
||||||
- **Frontend**: React 19, React Router 7, Vite 7, Tailwind CSS 4, DaisyUI 5,
|
- **Frontend**: React 19, React Router 8, Vite 7, Tailwind CSS 4, DaisyUI 5,
|
||||||
Leaflet/React Leaflet (brewery maps)
|
Leaflet/React Leaflet (brewery maps)
|
||||||
- **UI Documentation**: Storybook 10, Vitest browser mode, Playwright
|
- **UI Documentation**: Storybook 10, Vitest browser mode, Playwright
|
||||||
- **Testing**: xUnit, Reqnroll (BDD), FluentAssertions, Moq
|
- **Testing**: xUnit, Reqnroll (BDD), FluentAssertions, Moq
|
||||||
@@ -66,7 +66,7 @@ Archived/reference areas:
|
|||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- .NET SDK 10 or later
|
- .NET SDK 10 or later
|
||||||
- Node.js 18 or later
|
- Node.js 22 or later
|
||||||
- Docker Desktop, or an equivalent Docker Engine setup
|
- Docker Desktop, or an equivalent Docker Engine setup
|
||||||
|
|
||||||
See [Getting Started](docs/web/getting-started.md) for the full
|
See [Getting Started](docs/web/getting-started.md) for the full
|
||||||
@@ -83,10 +83,15 @@ This section is the shortest path to a working dev environment.
|
|||||||
git clone https://github.com/aaronpo97/the-biergarten-app
|
git clone https://github.com/aaronpo97/the-biergarten-app
|
||||||
cd the-biergarten-app
|
cd the-biergarten-app
|
||||||
|
|
||||||
cp web/.env.example web/.env.dev
|
cd web && ./generate-env.sh .env.dev && cd ..
|
||||||
docker compose --env-file web/.env.dev -f web/docker-compose.dev.yaml up --build -d
|
docker compose --env-file web/.env.dev -f web/docker-compose.dev.yaml up --build -d
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`generate-env.sh` copies `.env.example` and replaces the secret-bearing values
|
||||||
|
with freshly randomized ones; a plain `cp` leaves placeholder secrets in
|
||||||
|
place. See [Environment Variables](docs/web/environment-variables.md#generating-an-env-file)
|
||||||
|
for details.
|
||||||
|
|
||||||
Access:
|
Access:
|
||||||
|
|
||||||
- Website: http://localhost:3000
|
- Website: http://localhost:3000
|
||||||
@@ -137,7 +142,7 @@ Create a test environment file, then run the full test stack (backend and
|
|||||||
frontend) with Docker:
|
frontend) with Docker:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp web/.env.example web/.env.test
|
cd web && ./generate-env.sh .env.test && cd ..
|
||||||
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 --abort-on-container-exit
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ The Biergarten App is a monorepo split between the backend and the website:
|
|||||||
|
|
||||||
- **Backend**: .NET 10 Web API with SQL Server, organized as vertical feature
|
- **Backend**: .NET 10 Web API with SQL Server, organized as vertical feature
|
||||||
slices with MediatR
|
slices with MediatR
|
||||||
- **Frontend**: React 19 + React Router 7 website in `web/frontend`
|
- **Frontend**: React 19 + React Router 8 website in `web/frontend`
|
||||||
- **Architecture Style**: Vertical-slice backend plus server-rendered React
|
- **Architecture Style**: Vertical-slice backend plus server-rendered React
|
||||||
frontend
|
frontend
|
||||||
|
|
||||||
@@ -96,6 +96,7 @@ flowchart TB
|
|||||||
|
|
||||||
HOST -- "discovers controllers via<br/>AddApplicationPart" --> SLICES
|
HOST -- "discovers controllers via<br/>AddApplicationPart" --> SLICES
|
||||||
S1 -- "SendRegistrationEmailCommand<br/>(via Shared.Application contract)" --> S3
|
S1 -- "SendRegistrationEmailCommand<br/>(via Shared.Application contract)" --> S3
|
||||||
|
S1 -- "ProjectReference<br/>(avatar upload)" --> S5
|
||||||
|
|
||||||
SLICES --> SHARED
|
SLICES --> SHARED
|
||||||
SLICES --> DOMAIN
|
SLICES --> DOMAIN
|
||||||
@@ -108,11 +109,13 @@ flowchart TB
|
|||||||
style S5 stroke-dasharray: 4 3
|
style S5 stroke-dasharray: 4 3
|
||||||
```
|
```
|
||||||
|
|
||||||
Slices never reference each other's project. The one cross-slice interaction
|
Slices generally don't reference each other's project. Most cross-slice
|
||||||
(`Features.Users` triggering a confirmation email handled by `Features.Emails`)
|
interactions go through a MediatR command instead — for example,
|
||||||
goes through a MediatR command (`SendRegistrationEmailCommand`) whose contract
|
`Features.Users` triggering a confirmation email handled by `Features.Emails`
|
||||||
lives in `Shared.Application`, so neither slice takes a project reference on the
|
via a `SendRegistrationEmailCommand` whose contract lives in
|
||||||
other.
|
`Shared.Application`, so neither slice takes a project reference on the other.
|
||||||
|
The one exception is `Features.Users`, which takes a direct `ProjectReference`
|
||||||
|
on `Features.PhotoUpload` to send `UploadPhotoCommand` for avatar uploads.
|
||||||
|
|
||||||
### Layer responsibilities
|
### Layer responsibilities
|
||||||
|
|
||||||
@@ -173,13 +176,14 @@ brewery photo upload command) rather than bound to an HTTP route directly.
|
|||||||
**Dependencies**:
|
**Dependencies**:
|
||||||
|
|
||||||
- `Domain.Entities`, `Domain.Exceptions`
|
- `Domain.Entities`, `Domain.Exceptions`
|
||||||
- `Infrastructure.Sql` (generic ADO.NET plumbing) plus whichever infrastructure
|
- `Database.Connection` (generic ADO.NET connection/command plumbing) plus
|
||||||
project the slice needs (`Infrastructure.Jwt`/
|
whichever infrastructure project the slice needs (`Infrastructure.Jwt`/
|
||||||
`Infrastructure.PasswordHashing` for Users, `Infrastructure.Email`/
|
`Infrastructure.PasswordHashing` for Users, `Infrastructure.Email`/
|
||||||
`Infrastructure.Email.Templates` for Emails, `Infrastructure.FileUpload` for
|
`Infrastructure.Email.Templates` for Emails, `Infrastructure.FileUpload` for
|
||||||
PhotoUpload)
|
PhotoUpload)
|
||||||
- `Shared.Contracts`, `Shared.Application`
|
- `Shared.Contracts`, `Shared.Application`
|
||||||
- **Never** another `Features.*` project
|
- No other `Features.*` project, with one exception: `Features.Users`
|
||||||
|
references `Features.PhotoUpload` directly for avatar uploads
|
||||||
|
|
||||||
**Rules**:
|
**Rules**:
|
||||||
|
|
||||||
@@ -375,7 +379,7 @@ error-handling approach in more detail.
|
|||||||
|
|
||||||
### Website (`web/frontend`)
|
### Website (`web/frontend`)
|
||||||
|
|
||||||
The website is a React Router 7 application with server-side rendering enabled.
|
The website is a React Router 8 application with server-side rendering enabled.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
web/frontend/
|
web/frontend/
|
||||||
@@ -395,7 +399,7 @@ web/frontend/
|
|||||||
│ │ - home landing page
|
│ │ - home landing page
|
||||||
│ │ - theme theme switcher/guide
|
│ │ - theme theme switcher/guide
|
||||||
│ ├── hooks/ Shared hooks not tied to one feature, for example useMediaQuery
|
│ ├── hooks/ Shared hooks not tied to one feature, for example useMediaQuery
|
||||||
│ ├── routes.ts Route table (React Router 7 config-based routing)
|
│ ├── routes.ts Route table (React Router 8 config-based routing)
|
||||||
│ ├── root.tsx App shell and global providers
|
│ ├── root.tsx App shell and global providers
|
||||||
│ └── app.css Theme tokens and global styling
|
│ └── app.css Theme tokens and global styling
|
||||||
├── .storybook/ Storybook config and preview setup
|
├── .storybook/ Storybook config and preview setup
|
||||||
@@ -471,7 +475,7 @@ reference. Product and engineering documentation points to `web/frontend`.
|
|||||||
|
|
||||||
- Memory: 64MB
|
- Memory: 64MB
|
||||||
- Iterations: 4
|
- Iterations: 4
|
||||||
- Parallelism: CPU core count
|
- Parallelism: 2 (hardcoded, to avoid thread-pool exhaustion)
|
||||||
- Salt: 128-bit (16 bytes)
|
- Salt: 128-bit (16 bytes)
|
||||||
- Hash: 256-bit (32 bytes)
|
- Hash: 256-bit (32 bytes)
|
||||||
|
|
||||||
@@ -499,6 +503,12 @@ reference. Product and engineering documentation points to `web/frontend`.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This block exists in `appsettings.json`, but nothing in the code currently
|
||||||
|
reads it: actual token lifetimes come from the hardcoded
|
||||||
|
`TokenServiceExpirationHours` constants, and `JwtInfrastructure` hardcodes
|
||||||
|
`ValidateIssuer`/`ValidateAudience` to `false`, so `Issuer`/`Audience` are not
|
||||||
|
enforced.
|
||||||
|
|
||||||
## Database architecture
|
## Database architecture
|
||||||
|
|
||||||
For the table-by-table schema and the custom SQL error code scheme, see
|
For the table-by-table schema and the custom SQL error code scheme, see
|
||||||
|
|||||||
@@ -302,10 +302,16 @@ web/.env.prod # Production config (gitignored)
|
|||||||
**Setup**:
|
**Setup**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp web/.env.example web/.env.dev
|
cd web
|
||||||
# Edit web/.env.dev with your values
|
./generate-env.sh .env.dev
|
||||||
```
|
```
|
||||||
|
|
||||||
|
See [Generating an env file](#generating-an-env-file) above — `generate-env.sh`
|
||||||
|
randomizes the secret-bearing values, so it's the preferred way to create any
|
||||||
|
`.env.dev`/`.env.test`/`.env.prod` file. A plain `cp web/.env.example
|
||||||
|
web/.env.dev` works too, but leaves the placeholder secrets from the template
|
||||||
|
in place; edit them manually if you go that route.
|
||||||
|
|
||||||
**Docker Compose Mapping**:
|
**Docker Compose Mapping**:
|
||||||
|
|
||||||
- `web/docker-compose.dev.yaml` → `web/.env.dev`
|
- `web/docker-compose.dev.yaml` → `web/.env.dev`
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ This guide covers local setup for the Biergarten stack: the .NET backend in
|
|||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- **.NET SDK 10+**
|
- **.NET SDK 10+**
|
||||||
- **Node.js 18+**
|
- **Node.js 22+**
|
||||||
- **Docker Desktop** or equivalent Docker Engine setup
|
- **Docker Desktop** or equivalent Docker Engine setup
|
||||||
- **Java 8+** if you want to regenerate PlantUML diagrams
|
- **Java 8+** if you want to regenerate PlantUML diagrams
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user