73 lines
3.5 KiB
Markdown
73 lines
3.5 KiB
Markdown
# Architecture decisions
|
|
|
|
Why the site is built the way it is. Read this before questioning one of these
|
|
decisions — each records the reasoning, not just the choice. Operational how-to
|
|
lives in `docs/deployment.md`; open work lives in `tasks/`.
|
|
|
|
> **Note on scope.** These decisions describe stage 1: a static information site
|
|
> with content as files. The move to editor-based content maintenance
|
|
> (`tasks/001-redaktion-ohne-entwickler.md`) deliberately revisits AE-2 and AE-3 —
|
|
> when that lands, update this file.
|
|
|
|
## AE-1: Blazor with static server-side rendering, not WebAssembly
|
|
|
|
**Decision:** Blazor Web App with interactivity mode *None* (pure static SSR).
|
|
Target framework .NET 10 (LTS).
|
|
|
|
**Rationale:** Blazor WASM loads several MB of runtime before the first visible
|
|
letter, serves search engines and link previews (WhatsApp, Signal, Messenger — the
|
|
main distribution channel among parents) an empty shell, and provides no value on a
|
|
pure information site. Static SSR delivers finished HTML, needs no JavaScript, and
|
|
costs around 60 MB of RAM in the container.
|
|
|
|
**Consequence:** Interactivity can be added later per component
|
|
(`@rendermode InteractiveServer` on exactly that one component), without changing the
|
|
architecture. Never global.
|
|
|
|
## AE-2: Content as files in the repo, not in a database
|
|
|
|
**Decision:** Page content as Markdown with YAML frontmatter, events as structured
|
|
YAML (`Content/events.yml`), documents as PDF under `wwwroot`.
|
|
|
|
**Rationale:** No DB backup, no migration schema, no consistency problems between
|
|
files and database. Changes are commits and are therefore traceable and reversible.
|
|
For a site with ~10 subpages and a few events per year, anything else is overhead.
|
|
|
|
**Consequence:** Text changes require a commit and a redeploy. With an expected five
|
|
changes a year that is acceptable — and the reason the editor expansion
|
|
(`tasks/001`) is treated as a separate stage.
|
|
|
|
## AE-3: Content is baked into the image, not mounted as a volume
|
|
|
|
**Decision:** `Content/` and `wwwroot/` are part of the image.
|
|
|
|
**Rationale:** Mounted content from the appdata share could be edited directly on the
|
|
NAS, but that is exactly when the repo and the live state drift apart — and the
|
|
"backup = `git clone`" property from AE-2 would be worthless.
|
|
|
|
**Consequence:** No quick fix on the live system. Typos are corrected properly via a
|
|
commit. Note: the content is read once at startup and cached — there is **no**
|
|
`FileSystemWatcher` (a change needs a restart / `dotnet watch`).
|
|
|
|
## AE-4: TLS and certificates exclusively in the Nginx Proxy Manager
|
|
|
|
**Decision:** The container speaks only HTTP on port 8080 and has **no** port mapping
|
|
to the outside. NPM terminates TLS and is the only path to the container.
|
|
|
|
**Rationale:** Matches the pattern already established in the home lab
|
|
(`cloud.anticarnist.de`). Certificate management stays in one place.
|
|
|
|
**Consequence (important):** In `Program.cs`, **no** `UseHttpsRedirection()` and
|
|
**no** `UseHsts()` — otherwise a redirect loop behind the proxy. NPM sets HSTS.
|
|
`UseForwardedHeaders` with emptied `KnownNetworks`/`KnownProxies` is correct because
|
|
the container has no port mapping and is reachable only through NPM.
|
|
|
|
## Rejected alternatives (for AE-1)
|
|
|
|
| Alternative | Why not |
|
|
|---|---|
|
|
| Blazor WASM | Payload, SEO, link previews, no benefit |
|
|
| ASP.NET Core MVC/Razor Pages | Works too, but Razor Components are the more modern model |
|
|
| Statiq.Web (C# SSG) → nginx | Leanest to operate, but every text change forces a build. Kept as a fallback. |
|
|
| Astro/Hugo | More mature SSG ecosystem, but unfamiliar territory |
|