Archived
build-and-publish / build (pull_request) Successful in 2m8s
The public site was a React SPA. It is now server-rendered Thymeleaf, and the goodie box and catering tables added in the previous commit have a page of their own. The look is unchanged: the templates carry the same Tailwind classes the components did, and every one of the 241 classes the five pages use resolves in the compiled stylesheet. WHAT WENT AWAY. PageMetaController — 148 lines whose only job was to splice per-page <title> and OG tags into one shell with regular expressions, with a test that read the real index.html so that reformatting it failed the build instead of silently breaking the rewriting. A page rendered on the server writes its own head. Also react-router (no client-side routes left), motion, vite-plugin-svgr, and the SPA fallback (platform.web.spa.enabled=false): with the site server-rendered, forwarding a mistyped URL to /index.html would answer with a blank admin shell and a 200 instead of the site's own 404 page. WHAT GOT BETTER ON THE WAY, none of it visible. The category filter is a ?category= link, so every filtered view is a URL you can send someone and a crawler can reach all forty items instead of the twelve the default filter showed. The contact form is a form post: the enquiry is recorded before delivery is attempted, and a refused relay re-renders the page with what the visitor typed still in the boxes. The mobile menu is a <details> — the React version needed four effects to close on navigation, close on Escape, stop the page behind it scrolling, and unmount (a panel parked off-screen still extends the scrollable area, which is how you used to be able to scroll sideways and find the menu); a new document cannot inherit an open menu. THE PUBLIC SITE SHIPS 5 KB OF JAVASCRIPT, and works without it. The product cards are scroll-snap strips, so the photos swipe on a phone and scroll with a trackpad unaided; gallery.js adds the arrows and the dots, and creates them itself rather than having the template render controls that would sit there dead. Tailwind still needs its compiler, so npm remains a BUILD tool: the CLI compiles the templates into static/css/site.css at process-classes (so `spring-boot:run` gets it too), and frontend/ now builds only that stylesheet and the admin. The brand tokens are one file both stylesheets import — the alternative was the shop front and the screen that edits it drifting a shade apart. The stylesheet URL carries ?v=<sha>, because one hand-written CSS file has no content hash and a deploy has to be able to tell a browser that what it cached is stale. The admin is still React and is untouched, apart from losing the router it no longer needs. It is an editor, not content. PlatformContractTest stopped inheriting platform-starter-test's contract and restates it. The shared version asserts that an unknown path forwards to the SPA shell, which is no longer true here, and its test methods are package-private so it cannot be overridden. The platform should decide that assertion from platform.web.spa.enabled — noted in the file. 9 new tests (46 total): every page's real title and og:url, the catalogue and the catering tables in the HTML rather than fetched afterwards, server-side filtering, the 404, and that a crafted ?about= link cannot put words of its own choosing in front of a customer. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
102 lines
4.1 KiB
YAML
102 lines
4.1 KiB
YAML
spring:
|
|
application:
|
|
name: itsthevine
|
|
datasource:
|
|
url: ${DB_URL:jdbc:postgresql://localhost:5432/itsthevine}
|
|
username: ${DB_USER:itsthevine}
|
|
password: ${DB_PASSWORD:changeme}
|
|
jpa:
|
|
hibernate:
|
|
ddl-auto: validate
|
|
open-in-view: false
|
|
flyway:
|
|
enabled: true
|
|
mail:
|
|
host: ${SMTP_SERVER:localhost}
|
|
port: ${SMTP_PORT:25}
|
|
username: ${SMTP_USERNAME:}
|
|
password: ${SMTP_TOKEN:}
|
|
properties:
|
|
mail:
|
|
smtp:
|
|
# Only authenticate when we were actually given credentials — the LAN relay takes mail
|
|
# from the docker network without them.
|
|
auth: ${SMTP_AUTH:false}
|
|
starttls:
|
|
enable: ${SMTP_STARTTLS:false}
|
|
# The local relay / Proton Bridge presents a self-signed cert (CN=127.0.0.1). This trusts
|
|
# only the configured host, not every server we might ever talk to.
|
|
ssl:
|
|
trust: ${SMTP_SERVER:localhost}
|
|
|
|
platform:
|
|
web:
|
|
spa:
|
|
# OFF. The platform's fallback forwards every extension-less path to /index.html so a React SPA can
|
|
# own routing; this site is server-rendered, and /index.html is now only the admin shell. Left on,
|
|
# a mistyped URL would answer with a blank JavaScript page and a 200 instead of the site's own 404.
|
|
# SiteController maps /admin to the shell explicitly — that one route is all the SPA is for.
|
|
enabled: false
|
|
data:
|
|
auditing:
|
|
enabled: true
|
|
contact:
|
|
to: ${CONTACT_TO:}
|
|
from: ${CONTACT_FROM:}
|
|
hub-url: ${CONTACT_HUB_URL:}
|
|
security:
|
|
# Unset means the platform's permit-all chain, which is what a brochure site wants and what the
|
|
# web contract expects (an unknown /api path must 404, not 401). Set SECURITY_MODE=OIDC in the
|
|
# deployment to turn on Authentik login — that, and only that, brings the admin endpoints into
|
|
# existence. Leaving it unset in dev keeps `mvn spring-boot:run` working with no identity provider.
|
|
mode: ${SECURITY_MODE:NONE}
|
|
permit-paths:
|
|
- /api/products
|
|
- /api/categories
|
|
- /api/contact
|
|
- /actuator/health/**
|
|
authenticated-paths:
|
|
- /api/admin/**
|
|
# The admin screen itself, not just its API. The platform sends /api/** a bare 401 (right for
|
|
# fetch) but bounces everything else to Authentik, so protecting the page means a browser that
|
|
# opens /admin lands on the login form and comes back signed in — rather than loading an editor
|
|
# whose every request immediately fails. It also keeps the page out of strangers' hands entirely.
|
|
- /admin/**
|
|
storage:
|
|
# Only consulted when someone uploads a photo, i.e. only in a deployment that also set OIDC above.
|
|
# Blank endpoint leaves the storage auto-config switched off, so tests and local runs boot without
|
|
# MinIO credentials.
|
|
endpoint: ${STORAGE_ENDPOINT:}
|
|
access-key: ${STORAGE_ACCESS_KEY:}
|
|
secret-key: ${STORAGE_SECRET_KEY:}
|
|
|
|
# Absolute URLs for og:url. Only matters to link-preview scrapers, which need a full URL.
|
|
site:
|
|
base-url: ${SITE_BASE_URL:https://itsthevine.com}
|
|
# Hung on the stylesheet URL as ?v=… The SPA's bundles had content hashes in their filenames; one
|
|
# hand-written stylesheet does not, so without this a returning visitor keeps the CSS they cached
|
|
# before the deploy. The CI build already passes the commit sha to the image.
|
|
build: ${GIT_SHA:dev}
|
|
assets:
|
|
# Where uploaded photos land. The key stored on a product is bucket-relative and excludes the
|
|
# prefix, because ProductCatalog re-adds `/images/` when it builds the public URL.
|
|
bucket: ${STORAGE_BUCKET:itsthevine}
|
|
key-prefix: images/
|
|
|
|
management:
|
|
endpoints:
|
|
web:
|
|
exposure:
|
|
include: health,info
|
|
endpoint:
|
|
health:
|
|
probes:
|
|
enabled: true
|
|
health:
|
|
mail:
|
|
# OFF deliberately. Boot's mail contributor opens an SMTP connection on every health check, so a
|
|
# relay outage would report the container unhealthy and get it restarted — taking a perfectly
|
|
# good website down over a side feature. Enquiries are persisted either way, and a failed send
|
|
# is already surfaced to the visitor and the log.
|
|
enabled: false
|