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>
This PR contains the work done to rename the _Website_ service's library SwiftPM target from `WebsiteCore` to `WebsiteLibrary`, updating every reference across the manifest, source, tests, Xcode schemes, and documentations.
Reviewed-on: rock-n-code/loud-amsterdam#14
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 _Fluent_-based persistence layer for the Website service, selectable at runtime alongside the existing in-memory default, plus the local dev tooling and docs to support it.
To provide further details about the work:
* Persistence package
* The `Driver` and `TLS` enumerations
* The `Configuration` type
* The `Service` factory that builds the service
* `PrepareDB` for migrations registration
* The `Probe` for readiness checks.
* App integration
* Builds the driver, registers migrations, and attaches `Fluent` to the service lifecycle so it starts/stops with the HTTP server.
* Migrate-on-boot is gated to the in-memory backend; MySQL/MariaDB is migrated out of band via --database-migrate so shared databases never race on startup.
* The `ConfigReader+Properties` extension maps database.* config keys onto the driver.
* Library
* Added database configuration constants.
* The `HealthController` controller gains a readiness probe: `GET /health/ready` checks whether the database is reachable, separate from the existing liveness check.
* Others
* Updated the `docker-compose` files to support a database service behind a database profile, and hardened for local development
* New database targets on the `Makefile` file and overall documentation updated
* Updated the `.env.local`, `Dockerfile`, and `README` files to document the persistence workflow, config keys, and local DB commands
Reviewed-on: rock-n-code/loud-amsterdam#13
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>