diff --git a/Packages/Infrastructure/README.md b/Packages/Infrastructure/README.md index 2181cf2..8fd2d8d 100644 --- a/Packages/Infrastructure/README.md +++ b/Packages/Infrastructure/README.md @@ -5,11 +5,11 @@ The shared [Hummingbird](https://github.com/hummingbird-project/hummingbird) too | Role | Types | | --- | --- | | Routing | `RouterController`, `RouteCollectionBuilder`, the `addController` extension on `RouterMethods` | -| Middlewares | `SecurityHeadersMiddleware`, `HTTPSRedirectMiddleware`, `TrailingSlashRedirectMiddleware`, `VaryMiddleware`, `RateLimitMiddleware`, `LocalizationMiddleware`, `NotFoundMiddleware` | +| Middlewares | `SecurityHeadersMiddleware`, `HTTPSRedirectMiddleware`, `TrailingSlashRedirectMiddleware`, `VaryMiddleware`, `RateLimitMiddleware`, `LocalizationMiddleware` (negotiating from a `lang` query parameter, then a leading path segment, then `Accept-Language`), `NotFoundMiddleware` | | Pages and assets | `Page`, `Asset`, `AssetExtension`, `FingerprintAssets` | | Link previews | `SocialCard`, its `Image` and `Style`, and the `Tag` meta tags it derives | | Structured data | `StructuredData`, the `Node`, `Property`, and `Value` types of its schema.org graph, the open `Name` and `Kind` vocabularies, and the site-wide initializer building the `Organization`/`WebSite` pair | -| Analytics | `Analytics`, the `Event`s a page reports (with `tagging()` to apply one to a tag), the tracker script `Attribute`s it derives, and the `origin` its preconnect hint targets | +| Analytics | `Analytics`, the `Event`s a page reports (with `tagging()` to apply one to a tag), the tracker script `Attribute`s it derives, the optional session `recorder` script paired with it, and the `origin` its preconnect hint targets | | Responses | `CachedHTMLResponse`, `LocalizedHTMLCollectionResponse` | | Contexts | `LocalizedRequestContext` | | Constants | The `HTTPField.Name` header names, `Int.RateLimit` limits, and `String.Security` header values the middlewares default to | diff --git a/Services/Website/README.md b/Services/Website/README.md index b7faa7c..57c1076 100644 --- a/Services/Website/README.md +++ b/Services/Website/README.md @@ -3,8 +3,8 @@ The **Site** public website service — a [Hummingbird](https://github.com/hummi ## Overview The service: -- Serves the landing page at `GET /` (rendered once per supported language with [Elementary](https://github.com/elementary-swift/elementary) and cached). -- Negotiates each request's language from its `Accept-Language` header against the languages in the `WebsiteLibrary` String Catalog, falling back to the default (`en`); pages are served from the per-language cache with `Content-Language` and `Vary: Accept-Language` headers. +- Serves the landing page at `GET /` (rendered once per supported language with [Elementary](https://github.com/elementary-swift/elementary) and cached), plus one prefixed route per non-default catalog language — `GET /nl` and so on (see [Language editions](#language-editions)). +- Negotiates each request's language from the `lang` query parameter, the leading path segment, then its `Accept-Language` header, against the languages in the `WebsiteLibrary` String Catalog, falling back to the default (`en`); pages are served from the per-language cache with `Content-Language` and `Vary: Accept-Language` headers. - Builds every page on the shared `Page` scaffolding from `Infrastructure`, which assembles the document head around the page's own markup: the viewport declaration, the optional `description` summary and `rel="canonical"` link, the Open Graph / Twitter link-preview tags, the JSON-LD structured-data script, and the optional analytics tracker (see [Page metadata](#page-metadata)). - Answers a liveness check at `GET /health` with a static JSON payload, and a readiness check at `GET /health/ready` that reports whether the database is reachable (`200` ready / `503` unavailable). - Answers `HEAD` on every `GET` route: the router is built with `.autoGenerateHeadEndpoints`, so uptime monitors and crawlers probing with `HEAD` get the route's status and headers instead of a `404`. @@ -43,10 +43,10 @@ LogRequestsMiddleware → TrailingSlashRedirectMiddleware (301 to the path without a trailing slash) → VaryMiddleware (marks every response as varying on Accept-Encoding) → ResponseCompressionMiddleware (gzip/deflate above the size threshold) - → LocalizationMiddleware (negotiates the request's language) + → LocalizationMiddleware (negotiates the language: ?lang=, path prefix, then Accept-Language) → NotFoundMiddleware (renders the localized not-found page on .notFound) → FileMiddleware (serves Resources/Static) -RootController (GET / → landing page) +RootController (GET / → landing page; GET / → its other editions) HealthController (GET /health → liveness, GET /health/ready → readiness) ``` @@ -55,20 +55,38 @@ The router is created with `.autoGenerateHeadEndpoints`, so each of those `GET` ### Page metadata Each page conforms to `Infrastructure`'s `Page` protocol and supplies only its `title`, `content`, `stylesheets`, and `scripts`; the protocol assembles the document around them and renders the head in a fixed order: the viewport declaration, the `analytics` origin preconnect hint, the `summary`, the `canonicalURL` link, the `socialCard` tags, the `structuredData` script, the `analytics` tracker script, then the page `metadata` and the stylesheet links. The body is the content followed by the script tags. -Four of those are page-authored, optional, and **omitted by default** — the reference site leaves them unset, so a generated site fills in what it needs by overriding them on `IndexPage` (or on the shared `Page+Defaults` extension, for site-wide values): +Four of those are page-authored and optional. `IndexPage` supplies `canonicalURL`; the other three are **omitted by default** — the reference site leaves them unset, so a generated site fills in what it needs by overriding them on `IndexPage` (or on the shared `Page+Defaults` extension, for site-wide values): | Property | Renders as | Notes | | --- | --- | --- | | `summary` | `` | The page's one-line description. | -| `canonicalURL` | `` | Absolute URL. | -| `socialCard` | Open Graph + Twitter `` tags | A `SocialCard` — title, summary, URL, site name, locale, share image. Scrapers require absolute URLs, so the page composes them from its own origin. | +| `canonicalURL` | `` | Absolute URL. `IndexPage` derives it from `site.origin` and the page's own language; an unset origin omits it (see [Language editions](#language-editions)). | +| `socialCard` | Open Graph + Twitter `` tags | A `SocialCard` — title, summary, URL, site name, locale, share image. Scrapers require absolute URLs, so the page composes them from its own origin; `Page+Defaults` supplies the locale as `ogLocale`. | | `structuredData` | `