The template's new `site.origin` key arrived empty, as bootstrap fills it in.
Pointing it at the origin robots.txt and sitemap.xml already carry turns on the
canonical and hreflang links, and the HTTPS redirect the production compose
already trusts the forwarded proto for.
Reconciled the bootstrap-customised files: kept the CCN naming, canonical
origin, database slug and analytics comments, dropped the template-only
Makefile, README.md and Scripts/bootstrap that bootstrap removes, and took
the template's ordering for the security headers in the production compose.
This PR contains the work done to define the `Analytics` type into the _Infrastructure_ package and also, to integrate this type into its `Page` protocol.
Reviewed-on: rock-n-code/loud-amsterdam#40
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
This PR contains the work done to introduce a `StructuredData` type that pages use to describe themselves to search engines as schema.org JSON-LD, and wires it into the Page protocol so the payload renders automatically in the document head.
Reviewed-on: rock-n-code/loud-amsterdam#32
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
This PR contains the work done to included the Utility package into the Docker deployment process in the Website service target.
Reviewed-on: rock-n-code/loud-amsterdam#31
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
This PR contains the work done to address certain tweaks in the newly-introduced _Social Card_ types in the **Infrastructure** package.
Reviewed-on: rock-n-code/loud-amsterdam#30
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
This PR contains the work done to create the new **Utility** package within the project, and also included in it the `NormalizeEmail` method, as it's not something that belongs to the **Infrastructure** package.
Reviewed-on: rock-n-code/loud-amsterdam#29
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
This PR contains the work done to extends the `Page` protocol with the head tags that control search snippets and link previews: a meta description, a canonical URL, and a social card rendered as _Open Graph_ and _Twitter_ meta tags. All three are optional with nil defaults, so existing conformers compile and render unchanged.
Reviewed-on: rock-n-code/loud-amsterdam#28
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
This PR contains the work done to do a little bit of housekeeping pass across all packages and the Website service.
To provide further details about the work:
* Refreshed the READMEs and source documentation to match the current code;
* Tagged every test case consistently across the Infrastructure, Localization, Persistence, and Website test targets;
* Removed Website middleware tests now covered by Infrastructure's own suite;
* Conformed the `PrepareDB` method to Sendable;
* Relaxes the production Compose DATABASE_TLS default from require to prefer;
* Added Persistence test verifying the prefer posture falls back to plaintext connections.
Reviewed-on: rock-n-code/loud-amsterdam#27
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>
This PR contains the work done to rename the _Web_ package as _Infrastructure_, to provide a clear naming and purpose to this particular package within the project.
To provide further details about the work:
* Infrastructure
* Asset fingerprinting: an FNV-1a token derived from the static files directory, appended as ?v= to asset URLs so deploys bust caches; pre-rendered pages also revalidate via weak ETags.
* New middlewares: fixed-window RateLimitMiddleware (per-client budgets keyed by trusted X-Forwarded-For or remote address) and VaryMiddleware (Accept-Encoding on every response); SecurityHeadersMiddleware now also stamps error responses.
* Auto-generated HEAD endpoints, cache max-age configuration, and Docker build/Compose refinements.
* Protocols and scaffolding: Asset/AssetExtension, the Page protocol (viewport, stylesheets, scripts, versioned URLs), and LocalizedRequestContext.
* Rate limiter's counter store swapped from an actor to a Mutex (no executor hop per request) with amortized batch eviction instead of O(n²) scans under client floods.
* FingerprintAssets reports unreadable files to a logger instead of silently producing a token that never busts their cache.
Reviewed-on: rock-n-code/loud-amsterdam#25
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>
This PR contains the work done to address small fixes.
To provide further details:
* HTML template
* Removed the duplicate charset <meta> tag from the Page protocol's head property.
* Router
* Enabled auto-generated HEAD endpoints so every GET route gets a HEAD sibling. Uptime monitors and crawlers probing with HEAD now receive the page's status and headers instead of a 404.
* Docker
* Pinned the asset optimizer versionsvia build args so minified output is reproducible for a given Dockerfile commit.
* Narrowed the build context copied into the release stage, only package manifests and Swift sources are copied. Static assets come from the separate assets stage after the binary is built.
* svgo now minifies all SVGs recursively rather than just icon.svg, and the staging step creates Resources/Static explicitly instead of conditionally moving the unminified sources.
* Added curl to the runtime image (needed for the container healthcheck) and .claude to .dockerignore.
* Docker-compose
* Added a `healthcheck` to the website service hitting GET /health (liveness only), so Compose reports process health without coupling container health to database reachability.
Reviewed-on: rock-n-code/loud-amsterdam#23
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>
This PR contains the work done to define a `Page` protocol that extracts the HTML scaffolding that `IndexPage` and `ErrorPage` pages duplicated, so every page of the website declares only what makes it unique — its content, title, and assets — while the document structure lives in one place. Also cleans up imports across the workspace.
Reviewed-on: rock-n-code/loud-amsterdam#22
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>
This PR contains the work done for build-time optimization of the static assets served by the Website service. The production Docker image now ships minified JS/CSS and losslessly recompressed images, while the sources in the repository stay readable and un-minified.
Reviewed-on: rock-n-code/loud-amsterdam#20
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>
This PR contains the work done to overhaul the static asset definitions for the Website service.
To provide further details about the work:
* Website library
* Overhauled the `StateFile` enumeration to reduce the number of cases to one case per logical file name, each exposing a `fileExtensions` list.
* Wired everything into the pages with a consistent ordering convention: stylesheets load shared-first so the page sheet wins the CSS cascade; scripts load page-first with shared.js last. The error page also gained the shared stylesheet and its scripts; the index page gained its page CSS/JS and the new touch icon link.
* Used the `StaticFile` enumeration as a single source of truth for every _href_/_src_ in the `IndexPage` and the `ErrorPage` pages, eliminating hardcoded asset paths.
* Website service
* Added new assets to the Resources folder:
* `apple-touch-icon.png`
* `css/index.css`
* `js/index.js`
* `js/error.js`
* `sitemap.xml`
* Renamed existing assets within the Resources folder:
* `css/style.css` → `css/shared.css`
* `js/app.js` → `js/shared.js`
* Fixed the working-directory location for the scheme in the Xcode project.
Reviewed-on: rock-n-code/loud-amsterdam#18
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>
This PR contains the work done to introduce a new Web Swift package that provides a reusable, declarative way to register route controllers on a Hummingbird router, then adopt it in the Website service.
To provide further details about the work:
* Web package
* The `RouterController` protocol — a Sendable protocol to group controllers behind one `routes` property.
* The `RouteCollectionBuilder` — a result builder that collects controllers' route collections into a stack, with full support for optionals, conditionals, and arrays.
* The `addController(_:)` method — a `RouterMethods` extension letting controllers be listed declaratively and adding each one's routes at the router root.
* Website service
* Added Web as a dependency of the _WebsiteLibrary_ target.
* Conformed the `RootController` and `HealthController`controllers to the `RouterController` protocol.
* Updated the `App+Build` extension to to use the cleaner `router.addController { … }` instead.
Reviewed-on: rock-n-code/loud-amsterdam#17
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>