Commit Graph
33 Commits
Author SHA1 Message Date
austinandClaude Opus 5 eb5f75bc9d Notes move both ways, and prove a deleted table takes its cells with it
build-and-publish / build (pull_request) Successful in 2m2s
Two small things found reading it back: a note could be moved up but not down, and nothing exercised
`remove` against the real foreign keys — a delete that strands its children fails in Postgres rather
than in memory, and it's a button on the screen.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-26 15:16:09 -05:00
austinandClaude Opus 5 748b1cd59b Catering tables: the spreadsheet becomes data the bakery can edit
build-and-publish / build (pull_request) Successful in 1m58s
The goodie box and catering prices arrived as a spreadsheet — Office, Parties and Weddings, each a
few columns of sizes and prices with lines of baked goods underneath. This puts it behind
/api/catering and makes every part of it editable at /admin, because the prices move and the
spreadsheet's own last line says the tables are "mostly just an idea for people".

A package is one table, its tiers are the columns, its rows are the lines, and a line holds one
value per column. That alignment is why this is an aggregate rather than three tables edited
separately: drop the middle column on its own and every remaining entry shifts one place left, so
the Large box advertises the Medium box's contents at the Large price and nothing looks broken.
CateringPackage#arrange takes a whole table, renumbers positions from the order it arrived in, and
refuses an arrangement whose lines and columns disagree.

Money owns prices — what "24", "$24" or "24.50" means and how it prints — so the browser never
formats money and never multiplies it by 100 in floating point. Cents in the column, "$24" in the
response. An empty price is "ask us", not zero.

Seeded from the bakery's own wording. Shorthand is expanded ("4 dz cc or sc") and typos fixed, since
customers read these lines; in the wedding table the labels and the values are offset in the source
spreadsheet, so they are carried over literally and can be renamed in the admin. The lines that are
named but never quantified keep their blank cells: dropping the blanks would shorten the line and
shift everything after it.

The public response leaves out a table with no columns or no lines — adding a table and filling it
in are two separate acts, and the gap between them shouldn't put a bare heading on the live page.
No public page renders any of this yet; this is the backend and the editor for it.

Admin endpoints are @ConditionalOnProperty on SECURITY_MODE=OIDC like the rest, so a deployment with
no identity provider has no price writes. 18 new tests: the seeded spreadsheet, the alignment
invariant, money in both directions, and the HTTP surface the screen actually calls (including that
/packages/order isn't read as a table id, and that a refusal arrives as a ProblemDetail sentence).

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-07-26 15:13:39 -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 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 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
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 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
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
Austin 26d0e92509 Rebrand to Sage & Cream identity, working contact form, drop Firebase
- New sage/cream palette and stacked logo lockup (The Vine over Coffeehouse
  + Bakery) driven by currentColor; logo SVGs now colorable
- Reuse the logo component for the hero and section marks
- Rewrite site copy: real founding (Morissa Bennett, 2024), real story from
  the product range, remove invented claims and AI phrasing
- Contact form now sends over SMTP via /api/contact (nodemailer) with real
  send/error states, server-side validation, and reply-to the customer;
  delivers to CONTACT_TO. Add .env.example and a test-email script
- Fix mobile: unmount the off-screen menu (killed sideways scroll), cap logo
  width, responsive heroes and type
- Remove Firebase (config, tracked build output, placeholder pages, nix
  firebase-tools) now that hosting has moved
- Delete dead code: LoyaltyCardForm, ProductModal, LoadingSpinner, card-flip
  CSS, unused Playfair font
- Serve dev/start on port 2024
2026-07-14 17:48:00 -05:00
Austin d952371950 updated hours 2026-03-14 11:29:08 -05:00
austin 12c7f2ee49 added a dynamic favicon 2025-02-25 16:54:58 -08:00
Austin Bennett de4e7f4ed6 fixed hours & location 2025-02-21 18:27:37 -06:00
Austin Bennett e08127dcca fixed categories 2025-02-21 15:10:13 -06:00
Austin Bennett c0790f8a2a disabled contact page & fixed images 2025-02-21 15:07:16 -06:00
Austin Bennett 9b58d88977 fixed eslint issues 2025-02-21 14:51:41 -06:00
austin 84693e10b0 removed history page 2025-02-11 10:45:19 -06:00
austin 9d03bcf8ee 2.0 2025-02-08 14:24:51 -06:00
Paul Fresnel 51988cfb3d redirect fix 2024-11-09 17:40:08 +01:00
Paul Fresnel 8847904516 products modal added 2024-11-09 17:39:17 +01:00
Paul Fresnel f877a74467 products images added 2024-11-09 17:22:56 +01:00
Paul Fresnel b6a5e5455d card form added 2024-11-09 16:46:49 +01:00
Paul Fresnel 79a9187dea form added 2024-11-09 15:15:50 +01:00
Paul Fresnel a4a5c3bd80 fixed images path 2024-11-07 14:52:32 +01:00
Paul Fresnel c143e297a4 card finished 2024-11-07 14:40:25 +01:00
Paul Fresnel a5697e4422 card css flip effect 2024-11-07 14:17:37 +01:00
Paul Fresnel 494aa650f8 loaylty card css 2024-11-07 14:13:37 +01:00
Paul Fresnel 5f3ab98040 added branding 2024-11-07 10:08:49 +01:00
Paul Fresnel ea772a139d fixes deploy 2024-11-07 03:24:33 +01:00
Paul Fresnel be4dcdcedb added medias 2024-11-07 03:20:04 +01:00
Paul Fresnel c165c30aa1 init 2024-11-07 02:59:39 +01:00
Paul Fresnel 9e6b11930b Initial commit from Create Next App 2024-11-07 02:46:29 +01:00