Commit Graph
35 Commits
Author SHA1 Message Date
austinandaustin d5103e44b9 docs: add CONTRIBUTING guide (#9)
Co-authored-by: austin <[email protected]>
2026-07-23 14:42:30 -05:00
austinandClaude Opus 4.8 2e87a68791 CI: gate the merge, not just the image
build-and-publish / build (pull_request) Successful in 2m53s
Run the workflow on pull_request too, so tests + build + Trivy must pass before main can be
merged (branch protection requires this check). Push the image only on a real push to main —
never from a PR. Also standardises the workflow across all apps (three had drifted).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XXKjx7FNyRVAjU8dgB5KhN
2026-07-23 13:54:00 -05:00
austinandClaude Opus 4.8 65c1cab0c1 Merge the catalogue admin (your branch, reconciled onto main)
build-and-publish / build (push) Successful in 1m55s
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XXKjx7FNyRVAjU8dgB5KhN
2026-07-23 13:10:46 -05:00
austinandClaude Opus 4.8 651ff1e30c Reconcile: your admin wins, keeping main's non-admin work
You built a self-service catalogue admin on feature/admin-and-ui-wins while I built a
competing one that had already merged and deployed. Both forked from c8cc8fe. Per your
call, your implementation is the one that stays.

Kept from main (files your branch didn't touch, so no conflict):
- the CI test gate (tests now run and block the image)
- motion 12.42.2
- the platform contract test

Took from your branch:
- split AdminProductController / AdminCategoryController + ProductPhotoService (server-side
  webp via cwebp)
- a real category table (Category, V3__categories.sql) behind the product filters
- pages/Admin.tsx, with server-side /admin protection that redirects a browser to Authentik
  and returns it to /admin afterward — cleaner than my client-side gate, and it avoids the
  post-login-to-home issue my version had

Deleted my competing admin (AdminController, MeController, pages/admin/*, auth.tsx, and my
admin tests).

Grafted onto your gallery: swipe + arrow keys, which the deployed version had and yours
didn't. Added an AdminSecurityTest for your endpoints (admin closed, shop public, contact
CSRF) — the admin was otherwise untested, and CI now gates on tests.

Verified against a running container: /admin redirects a browser to Authentik (a bare 401
only for */* fetches, which is correct). 25 tests green.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XXKjx7FNyRVAjU8dgB5KhN
2026-07-23 13:10:46 -05:00
austinandClaude Opus 4.8 021dd0db8d Return to where you signed in from, and take motion 12.42.2
build-and-publish / build (push) Successful in 1m57s
Post-login landed on the home page. Spring only remembers the pre-login location when it
BOUNCES you off a protected page, but every route here is public — the SPA sends you to the
identity provider itself — so nothing is saved and login defaults to '/'. AuthProvider now
stashes the current path in sessionStorage before the redirect and navigates back once /api/me
confirms the session. sessionStorage, not a query parameter: it survives the redirect chain,
stays in this tab, and cannot be pointed at another site. Sign-in is only ever triggered from
an /admin route, so that is exactly where the reader is returned.

Also merges the motion 12.42.2 bump, which had stayed open on its own PR.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XXKjx7FNyRVAjU8dgB5KhN
2026-07-23 12:34:31 -05:00
austinandClaude Opus 4.8 f9f54b2a62 Remove the temporary gate probe
build-and-publish / build (push) Successful in 1m35s
Confirmed: the run failed at the Test step and the registry digest was unchanged, so a
failing test now stops the image being published.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XXKjx7FNyRVAjU8dgB5KhN
2026-07-23 12:20:14 -05:00
austinandClaude Opus 4.8 63a79eeb95 TEMPORARY: prove a failing test blocks the image
build-and-publish / build (push) Failing after 43s
Will be reverted in the next commit. Verifying the gate rather than assuming it — the last
assumption of this kind was wrong for months.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XXKjx7FNyRVAjU8dgB5KhN
2026-07-23 12:18:54 -05:00
austinandClaude Opus 4.8 04bc687ea1 CI: match the workspace volume on GITHUB_WORKSPACE
build-and-publish / build (push) Successful in 1m53s
act_runner mounts it at the full repo path (/workspace/Owner/repo), not at /workspace, so
the previous lookup found nothing and the step refused to run — correctly, but for the
wrong reason.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XXKjx7FNyRVAjU8dgB5KhN
2026-07-23 12:16:08 -05:00
austinandClaude Opus 4.8 c6202b15f5 CI: print the job container's mounts while wiring up the test step
build-and-publish / build (push) Failing after 2s
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XXKjx7FNyRVAjU8dgB5KhN
2026-07-23 12:14:46 -05:00
austinandClaude Opus 4.8 d630033148 CI: actually run the tests, and let them gate the image
build-and-publish / build (push) Failing after 1s
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
2026-07-23 12:14:06 -05:00
austinandClaude Opus 4.8 48bd0a3a6e Merge feature/admin-ui-wins
build-and-publish / build (push) Successful in 1m15s
Admin for the menu and enquiries, gallery swipe/keyboard, and the N+1 fix on product photos.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XXKjx7FNyRVAjU8dgB5KhN
2026-07-23 12:07:46 -05:00
austinandClaude Opus 4.8 3b80584e22 Admin for the menu and enquiries, plus gallery fixes
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
2026-07-23 11:58:21 -05:00
austin 4aee743efd Update dependency motion to v12.42.2
renovate/artifacts Artifact file update failure
2026-07-23 14:53:14 +00:00
austinandClaude Opus 4.8 c8cc8fe02d Inherit the platform contract tests, and extend the shared Renovate preset
build-and-publish / build (push) Successful in 1m16s
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
2026-07-23 09:46:53 -05:00
austinandClaude Opus 4.8 50e17eb73f Point the motion imports at the renamed package
build-and-publish / build (push) Successful in 1m40s
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
2026-07-23 08:52:01 -05:00
austinandClaude Opus 4.8 25832bd9ea tsconfig: drop baseUrl, which TypeScript 7 removed
build-and-publish / build (push) Successful in 1m27s
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
2026-07-23 08:50:29 -05:00
austin f46c27f143 Update dependency vite-plugin-svgr to v5
renovate/artifacts Artifact file update failure
2026-07-23 12:44:13 +00:00
austin 912b47b0c3 Update dependency typescript to v7
renovate/artifacts Artifact file update failure
2026-07-23 12:44:13 +00:00
austin cd4a09c3e6 Replace dependency framer-motion with motion
renovate/artifacts Artifact file update failure
2026-07-23 12:44:11 +00:00
austin 5b1d3116a8 Update bennett platform to v0.1.7 2026-07-23 12:44:11 +00:00
austinandClaude Opus 4.8 ac2c938fea Platform 0.1.6 (contact security) + fidelity fixes from the port review
build-and-publish / build (push) Successful in 1m14s
- .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
2026-07-23 06:09:38 -05:00
austinandClaude Opus 4.8 1961dc64a6 Platform 0.1.5: fail fast on a blank contact recipient
build-and-publish / build (push) Successful in 46s
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XXKjx7FNyRVAjU8dgB5KhN
2026-07-22 22:18:23 -05:00
austinandClaude Opus 4.8 11ae5f378d Rewrite on the Bennett platform: Spring Boot + Vite/React SPA
build-and-publish / build (push) Successful in 1m9s
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
2026-07-22 22:09:51 -05:00
austin 3f9efa178a ci: exercise workflow_run webhook (no-op)
build-and-publish / build (push) Successful in 3s
2026-07-22 19:50:15 -05:00
austinandClaude Opus 4.8 69e67182a1 contact: fan out enquiries to n8n hub (fire-and-forget)
build-and-publish / build (push) Successful in 8s
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]>
2026-07-22 18:12:45 -05:00
austinandClaude Opus 4.8 c88bd3bc98 contact route: optional SMTP auth + trust local self-signed relay/bridge
build-and-publish / build (push) Successful in 2s
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-22 15:17:06 -05:00
austinandClaude Opus 4.8 0736081b5f ci: push image under thevine org after repo move
build-and-publish / build (push) Successful in 9s
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-22 11:53:58 -05:00
austin 9976d45af2 ci: re-trigger build after runner docker.sock fix
build-and-publish / build (push) Successful in 15s
2026-07-22 10:50:09 -05:00
austinandClaude Opus 4.8 d1cbe93721 Add Docker build + Gitea Actions CI for self-hosting
build-and-publish / build (push) Failing after 11s
- 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]>
2026-07-22 10:44:04 -05:00
austin 12c7f2ee49 added a dynamic favicon 2025-02-25 16:54:58 -08:00
austin 16db05a6a7 removed unessesary images 2025-02-25 16:54:45 -08:00
austin 84693e10b0 removed history page 2025-02-11 10:45:19 -06:00
austin 3e18e8e058 updated readme 2025-02-10 12:45:41 -06:00
austin a6ecff81d0 updated default.nix shell for nextjs 2025-02-10 12:42:19 -06:00
austin 9d03bcf8ee 2.0 2025-02-08 14:24:51 -06:00