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
This commit is contained in:
2026-07-22 22:09:51 -05:00
parent 207415dbbe
commit f471462d05
164 changed files with 4223 additions and 14003 deletions
+32 -25
View File
@@ -1,30 +1,37 @@
# syntax=docker/dockerfile:1
# Multi-stage build for the Next.js (standalone) itsthevine.com site.
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
# framer-motion@11 declares a React 18 peer; project is on React 19 (as built on Vercel)
RUN npm ci --legacy-peer-deps
FROM node:22-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
# ---------- build ----------
FROM maven:3.9-eclipse-temurin-25 AS build
WORKDIR /src
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build
# Resolve the platform from the Gitea Maven registry (creds via BuildKit secrets); the Maven build also
# runs the Vite/React SPA build (frontend-maven-plugin) and folds it into the jar. Tests are skipped here
# because Testcontainers needs a Docker daemon — they run via `mvn verify`, not in the image build.
RUN --mount=type=secret,id=maven_user --mount=type=secret,id=maven_token \
MAVEN_USER="$(cat /run/secrets/maven_user)" MAVEN_TOKEN="$(cat /run/secrets/maven_token)" \
mvn -B -ntp -s .gitea/ci-settings.xml -DskipTests package \
&& cp "$(ls target/itsthevine-*.jar | grep -v original | head -1)" app.jar \
&& java -Djarmode=tools -jar app.jar extract --layers --destination extracted
FROM node:22-alpine AS runner
# ---------- runtime ----------
FROM eclipse-temurin:25-jre-alpine AS runtime
RUN apk -U upgrade --no-cache && apk add --no-cache curl
RUN addgroup -S spring && adduser -S -D -H -h /app -s /sbin/nologin -G spring spring
WORKDIR /app
ENV NODE_ENV=production \
NEXT_TELEMETRY_DISABLED=1 \
PORT=3000 \
HOSTNAME=0.0.0.0
RUN addgroup -g 1001 -S nodejs && adduser -S nextjs -u 1001
# standalone output already contains a minimal node_modules + server.js
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]
COPY --from=build --chown=spring:spring /src/extracted/dependencies/ ./
COPY --from=build --chown=spring:spring /src/extracted/snapshot-dependencies/ ./
COPY --from=build --chown=spring:spring /src/extracted/application/ ./
USER spring
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
CMD curl -fsS http://localhost:8080/actuator/health || exit 1
ARG GIT_SHA=unknown
LABEL org.opencontainers.image.title="itsthevine" \
org.opencontainers.image.source="https://git.thebennett.net/thevine/itsthevine" \
org.opencontainers.image.revision="${GIT_SHA}"
ENTRYPOINT ["java", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]