Implemented phase 2 for the POC prototype in the Website service.

This commit is contained in:
javier committed 2026-09-21 11:44:58 +02:00
1 parent 09c7b8a1a7
commit 43dcc03da6
28 files changed
+1468 -65

No files matched your search

+12 -1
View File
@@ -5,6 +5,7 @@ The **CCN** public website service — a [Hummingbird](https://github.com/hummin
The service:
- 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)).
- Serves the public catalogue, rendered per request: search results at `GET /search` (filtered through its query parameters), a listing at `GET /listing/{slug}`, and a seller's shop at `GET /shop/{slug}`; an unknown slug gets the not-found page (see [Catalogue](#catalogue)).
- Serves the gate: the sign-in screen at `GET /sign-in`, the sign-in at `POST /sign-in`, and the sign-out at `POST /sign-out` (see [Sign-in](#sign-in)).
- 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`) — asked for only where the answer is used, the bare landing route and the not-found page; 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).
@@ -48,6 +49,7 @@ LogRequestsMiddleware
→ FileMiddleware (serves Resources/Static)
RootController (GET / → landing page, language negotiated; GET /<lang> → its other editions)
CatalogueController (GET /search, GET /listing/{slug}, GET /shop/{slug} → rendered per request)
SessionController (GET /sign-in, POST /sign-in, POST /sign-out)
HealthController (GET /health → liveness, GET /health/ready → readiness)
```
@@ -64,10 +66,19 @@ The screens follow the **CCN marketplace** design canvas:
- **Data**: `Persistence`'s `CatalogueRepository` reads the shops and listings; the in-memory backend is migrated and seeded with demo data at launch.
- **Landing page**: rendered once and cached, so its listing rows are a snapshot taken at launch (`HomeListings`).
- **Search and shop**: `SearchParameters` turns the query string into a `ListingFilter` and builds every link that changes it — filter pills, tabs, pagination — so the screens work as plain `GET` forms and links. Searches default to listings shipping from the EU.
- **Gated actions**: buy, offer, message, save, and follow link to the sign-in path with a `return` parameter; the sign-in screen itself is not built yet.
- **Gated actions**: signed out, buy, offer, message, save, and follow link to the sign-in screen with a `return` parameter; signed in, buy, offer, and message link to their own paths (not built yet), while save and follow render disabled.
- **Covers**: listings have no photos yet, so `Cover` draws a placeholder from the listing's lettering and tone.
- **Scripts**: `js/shared.js` only submits the sort select on change and opens the filter rail on older desktop browsers; everything works without it.
### Sign-in
> **The passkey ceremony is stubbed.** `POST /sign-in` trusts the email it is given, and signs in the seeded demo buyer when given none. Replace it with WebAuthn before anything real depends on it.
- **Sessions**: `SessionStore` keeps them in memory, keyed by a random token in the `ccn_session` cookie (`HttpOnly`, `SameSite=Lax`, and `Secure` when the site is served over HTTPS). They end with the process.
- **One step signs in and joins**: an unknown email creates the account, named after the email's local part.
- **Return to the intent**: the `return` parameter is followed only when it is a rooted path on this site; anything else returns home.
- **Per-viewer pages**: the controllers read the viewer from the request and send those pages `Cache-Control: private, no-cache`. The landing page stays cached for signed-out visitors and is rendered per request for signed-in ones.
- **Sign-out** is a `POST` form in the header, so a link on another site cannot trigger it. The not-found page always renders signed out.
### 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.