The image build runs 'mvn -DskipTests', and the workflow was only build -> Trivy -> push, so
no app test has ever run in CI. Only Trivy gated a merge. ContactControllerTest had been
broken since platform 0.1.6 and nothing noticed; the platform contract tests added in 0.1.9
were not running either, which defeated their purpose.
They cannot run inside 'docker build' — Testcontainers needs a Docker daemon and a build has
none. Maven runs as a sibling container instead, mounting the workspace volume act_runner
gave this job (discovered from our own container rather than guessed) and sharing the host
network so published test ports are reachable as localhost.
Fails loudly if the volume cannot be found, rather than quietly skipping the tests, which
would recreate exactly the problem this fixes.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XXKjx7FNyRVAjU8dgB5KhN
Admin
- /api/admin: products CRUD, the enquiry inbox, and presigned photo upload straight to the
bucket so images never pass through the app. Gated by platform.security.authenticated-paths
= /api/admin/**, so any signed-in Authentik user is staff — the alternative is a role model
a two-person bakery would never maintain.
- /api/me is deliberately PUBLIC. The SPA asks on every page load, and requiring a login
would bounce every anonymous visitor to Authentik just to read the menu.
- /admin screens: product list with edit and remove, an editor with drag-free photo
reordering and upload, and an enquiry inbox that flags anything the relay refused.
Gallery
- swipe on touch devices, which the react-awesome-slider it replaced had and this did not,
plus arrow keys and position dots — with swipe there is otherwise nothing to say a card
holds more than one photo. Vertical drags are ignored so page scrolling still works.
- @BatchSize on the photo collection: the products page loaded the whole catalogue and
Hibernate issued a query per product for its images, forty-odd round trips for a page
that needs two.
Three things the tests caught, none of which are obvious:
- Adding the storage starter broke every existing test. It activates on a default endpoint,
so an S3 client is built even in tests and dies on blank keys.
- MockMvc's webAppContextSetup leaves the security filter chain OUT, so the first version of
the security test passed 200s and proved the opposite of what it claimed. It needs
.apply(springSecurity()).
- Turning on the security starter turns on CSRF — for the PUBLIC contact form too, which
then 403s. The SPA now reads the XSRF-TOKEN cookie and sends X-XSRF-TOKEN, and there is a
test asserting the form is rejected without it.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XXKjx7FNyRVAjU8dgB5KhN
PlatformWebContract asserts what this app must do because it is on the platform: an /api
path matching no controller 404s rather than returning the SPA, health is UP, the liveness
and readiness probes exist, and a client-side route forwards to the shell. That first one
shipped broken to six live sites and was found by typing a URL by hand; now it fails a
build instead.
renovate.json is three lines pointing at austin/renovate-config. The rules were copied per
repo, so they matched only by luck and a change was six edits.
Platform 0.1.9.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XXKjx7FNyRVAjU8dgB5KhN
Renovate's replacement PR swapped framer-motion for its successor 'motion' in
package.json but left the imports, so the build could not resolve them. The React entry
point is motion/react.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XXKjx7FNyRVAjU8dgB5KhN
TS7 errors with 'Option baseUrl has been removed'. The paths mapping already points at
./src/*, which resolves relative to this file without it, and TS 5.9 accepts the same
config — so this lands safely ahead of the TypeScript 7 bump.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XXKjx7FNyRVAjU8dgB5KhN
- .container back in @layer components so Tailwind's px-4 still wins; unlayered it had
quietly widened the gutter on every page
- shadow-sm -> shadow-xs: Tailwind v4 renamed the scale, so the ported markup was giving
every white card a heavier shadow than the live site
- route changes jump to the top again instead of smooth-scrolling
- preload the wordmark font and the hero image
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XXKjx7FNyRVAjU8dgB5KhN
Replaces the Next.js app. Same site, same look; the parts that were decisions rather
than markup now live in Java.
- catalogue, curated order, category filter and image URLs move from a TypeScript array
into Postgres behind /api/products and /api/categories
- contact form uses the shared platform-starter-contact: validate, RECORD, send, then
fan out to n8n. Recording first means a relay outage costs a notification, not an enquiry
- PageMetaController rewrites title/description/OG per route, replacing what Next's SSR
gave crawlers and link-preview scrapers
- 50MB of photos leave the repo for the MinIO bucket, re-encoded to webp (14MB) with EXIF
(including phone GPS) stripped
- fixes a catalogue typo: 'Strawberry Pie' was category 'Pies', which no filter matched, so
it was unreachable unless browsing All
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XXKjx7FNyRVAjU8dgB5KhN
Keeps the direct SMTP email as the reliable delivery path; when CONTACT_HUB_URL
is set, also POSTs the enquiry to the n8n webhook so the hub sends the customer
auto-reply and (later) creates CRM/task records. Best-effort with a 4s timeout,
so a slow or down hub never blocks or fails the form.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
- next.config: output 'standalone' for a self-contained server bundle
- Dockerfile: multi-stage Next.js build (node:22-alpine)
- .gitea/workflows/deploy.yml: build + push to the Gitea registry
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>