spring: application: name: itsthevine datasource: url: ${DB_URL:jdbc:postgresql://localhost:5432/itsthevine} username: ${DB_USER:itsthevine} password: ${DB_PASSWORD:changeme} jpa: hibernate: ddl-auto: validate open-in-view: false flyway: enabled: true servlet: multipart: # THIS BLOCK IS THE WHOLE REASON PHOTO UPLOADS FAILED. Unset, Boot defaults to a 1 MB max-file-size, # and a photo off a phone is 3-12 MB — so every real upload died with FileSizeLimitExceededException # before it reached ProductPhotoService, which exists precisely to resize "whatever came off a phone". # The resizing pipeline could never run on the input it was written for. max-file-size: 15MB # The file input is `multiple`, so one submit can carry several photos; this bounds the whole request # rather than each part. Four full-size photos at once is a realistic morning's worth of new stock. max-request-size: 60MB # Parse when the controller asks for the files, not while Tomcat is reading parameters. Eagerly, an # oversize part throws from inside the container's parameter parsing, which no @ExceptionHandler can # reach — the request dies as a 500 and then the forward to /error re-parses and throws again (the # "Exception Processing [ErrorPage...]" pairs in the log). Lazily, it surfaces as a # MaxUploadSizeExceededException during argument binding, where AdminController can catch it. resolve-lazily: true mail: host: ${SMTP_SERVER:localhost} port: ${SMTP_PORT:25} username: ${SMTP_USERNAME:} password: ${SMTP_TOKEN:} properties: mail: smtp: # Only authenticate when we were actually given credentials — the LAN relay takes mail # from the docker network without them. auth: ${SMTP_AUTH:false} starttls: enable: ${SMTP_STARTTLS:false} # The local relay / Proton Bridge presents a self-signed cert (CN=127.0.0.1). This trusts # only the configured host, not every server we might ever talk to. ssl: trust: ${SMTP_SERVER:localhost} server: tomcat: # Read and discard the rest of an over-sized body instead of resetting the connection, so the browser # actually receives the redirect and the message rather than "connection reset". Only reachable now for # a genuinely enormous file, but that is exactly when a clear answer matters. max-swallow-size: -1 platform: web: spa: # OFF. The platform's fallback forwards every extension-less path to /index.html so a React SPA can # own routing; this site is server-rendered, and /index.html is now only the admin shell. Left on, # a mistyped URL would answer with a blank JavaScript page and a 200 instead of the site's own 404. # SiteController maps /admin to the shell explicitly — that one route is all the SPA is for. enabled: false data: auditing: enabled: true contact: to: ${CONTACT_TO:} from: ${CONTACT_FROM:} hub-url: ${CONTACT_HUB_URL:} security: # Unset means the platform's permit-all chain, which is what a brochure site wants and what the # web contract expects (an unknown /api path must 404, not 401). Set SECURITY_MODE=OIDC in the # deployment to turn on Authentik login — that, and only that, brings the admin endpoints into # existence. Leaving it unset in dev keeps `mvn spring-boot:run` working with no identity provider. mode: ${SECURITY_MODE:NONE} permit-paths: - /api/products - /api/categories - /api/contact - /actuator/health/** authenticated-paths: - /api/admin/** # The admin screen itself, not just its API. The platform sends /api/** a bare 401 (right for # fetch) but bounces everything else to Authentik, so protecting the page means a browser that # opens /admin lands on the login form and comes back signed in — rather than loading an editor # whose every request immediately fails. It also keeps the page out of strangers' hands entirely. - /admin/** storage: # Only consulted when someone uploads a photo, i.e. only in a deployment that also set OIDC above. # Blank endpoint leaves the storage auto-config switched off, so tests and local runs boot without # MinIO credentials. endpoint: ${STORAGE_ENDPOINT:} access-key: ${STORAGE_ACCESS_KEY:} secret-key: ${STORAGE_SECRET_KEY:} # Absolute URLs for og:url. Only matters to link-preview scrapers, which need a full URL. site: base-url: ${SITE_BASE_URL:https://itsthevine.com} # Hung on the stylesheet URL as ?v=… The SPA's bundles had content hashes in their filenames; one # hand-written stylesheet does not, so without this a returning visitor keeps the CSS they cached # before the deploy. The CI build already passes the commit sha to the image. build: ${GIT_SHA:dev} assets: # Where uploaded photos land. The key stored on a product is bucket-relative and excludes the # prefix, because ProductCatalog re-adds `/images/` when it builds the public URL. bucket: ${STORAGE_BUCKET:itsthevine} key-prefix: images/ management: endpoints: web: exposure: include: health,info endpoint: health: probes: enabled: true health: mail: # OFF deliberately. Boot's mail contributor opens an SMTP connection on every health check, so a # relay outage would report the container unhealthy and get it restarted — taking a perfectly # good website down over a side feature. Enquiries are persisted either way, and a failed send # is already surfaced to the visitor and the log. enabled: false