This repository has been archived on 2026-09-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
itsthevine/README.md
T
austin f471462d05 Rewrite on the Bennett platform: Spring Boot + Vite/React SPA
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
2026-07-22 22:09:51 -05:00

2.8 KiB

The Vine Coffeehouse + Bakery — itsthevine.com

Site for The Vine, 215 E Main Street, Princeville, Illinois. Spring Boot serving a Vite/React SPA, on the Bennett platform.

Previously a Next.js app on Cloudflare, then self-hosted; the look is unchanged.

Shape

Backend Spring Boot 4 / Java 25, com.itsthevine.web
Frontend Vite + React 19 + TypeScript + Tailwind v4, served from the jar
Database Postgres (itsthevine on the shared app-db cluster), Flyway
Photos public MinIO bucket itsthevinenot in the repo or the image
Deploy Gitea CI → image → Watchtower → Caddy

What the server owns

The SPA renders; it doesn't decide anything.

  • /api/products, /api/categories — the catalogue, its curated order, the category filter and the absolute image URLs. This was a TypeScript array shipped to every visitor; it's now a table (V2__products.sql) read through ProductCatalog.
  • /api/contact — validates, records the enquiry, emails it, then fans out to the n8n hub. Recorded before sending on purpose: a relay outage costs a notification, not the enquiry. Undelivered ones are enquiry.delivered = false. Validation and delivery come from platform-starter-contact, shared with the other sites.
  • Per-page metadataPageMetaController rewrites <title>/<meta>/OG tags per route. Next used to server-render these; a plain SPA would hand crawlers and link-preview scrapers one generic shell.

Photos

Re-encoded to webp and uploaded to the bucket once (50 MB of originals → 14 MB), served with a year-long cache. site.assets.base-url says where they live. The originals remain in this repo's history. EXIF (including GPS from phone photos) is stripped by the re-encode.

Local development

# backend (needs Postgres on :5432 with an itsthevine database)
mvn spring-boot:run

# frontend, proxies /api to :8080
cd frontend && npm install && npm run dev   # http://localhost:2024

Build without the SPA for quick backend loops: mvn -DskipFrontend=true package.

Tests need Docker (Testcontainers):

mvn verify

Configuration

Variable Purpose
DB_URL / DB_USER / DB_PASSWORD Postgres
SMTP_SERVER / SMTP_PORT / SMTP_USERNAME / SMTP_TOKEN relay for the contact form
CONTACT_TO / CONTACT_FROM enquiry recipient and envelope sender
CONTACT_HUB_URL optional n8n webhook; best-effort, never blocks a submission
SITE_BASE_URL absolute base for og:url
VITE_ASSET_BASE / site.assets.base-url photo bucket

platform.contact.to unset disables the contact starter, and the app won't start with a ContactController that has nothing to send with — so a missing CONTACT_TO fails loudly rather than silently dropping enquiries.