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 27821cd. 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.
This commit is contained in:
2026-07-23 13:10:46 -05:00
parent 8a489409fd
commit 91219efbaa
26 changed files with 1790 additions and 1037 deletions
+6 -4
View File
@@ -62,8 +62,10 @@
<groupId>net.thebennett.platform</groupId>
<artifactId>platform-starter-contact</artifactId>
</dependency>
<!-- Admin needs a login, and uploading a product photo needs the bucket. The public site
still reads photos straight from the bucket's public URLs. -->
<!-- The site is still a public brochure, but the catalogue is now editable from it: the admin
screens sign in against Authentik (OIDC) and upload photos to the bucket. Both are off
unless platform.security.mode=OIDC, which is what gates the admin endpoints existing at
all — see AdminProductController. -->
<dependency>
<groupId>net.thebennett.platform</groupId>
<artifactId>platform-starter-security</artifactId>
@@ -85,8 +87,8 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- springSecurity() for MockMvc: without it the filter chain is absent and every protected
path answers 200, which would make a security test prove the opposite of what it says. -->
<!-- springSecurity() for MockMvc without it the filter chain is absent and every protected
path answers 200, so a security test would prove the opposite of what it claims. -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>