A tab icon you can actually see, and photo uploads that accept a photo
build-and-publish / build (pull_request) Successful in 2m14s

Two unrelated things the bakery hit on the same afternoon.

THE FAVICON was not missing, it was unusable. The head pointed rel=icon at the 1000x1000 logo
PNGs, so a browser fetched 71 KB to paint 16 square pixels, and the mark is a vine branch drawn in
hairlines -- strokes thinner than one pixel at that size -- which arrives as a grey smudge. Replaced
with a real icon set built from one leaf of that branch, filled rather than stroked, because at 16px
a silhouette survives and an outline does not. A midrib was drawn first and cut the leaf into two
pale slivers at tab size, so it went; the tilt, the two points and the stem carry the shape. The SVG
answers prefers-color-scheme itself, which a .ico cannot, so the dark tab strip gets sage on
bakery-900 instead of a glowing cream tile. The .ico is listed first on purpose: a browser takes the
last format it understands, so reversing the two would hand Chrome the bitmap.

PHOTO UPLOADS failed on anything over 1 MB, which is every photo a phone takes. The cause was an
absence: nothing configured spring.servlet.multipart, so Boot's 1 MB default applied and the
container rejected the file with FileSizeLimitExceededException before it reached
ProductPhotoService -- the class whose entire job is turning "whatever came off a phone" into a
resized webp. The pipeline could never run on the input it was written for. Now 15 MB a file and
60 MB a request, the latter because the file input is `multiple`.

The failure was also ugly, and that is fixed separately: parsed eagerly, an over-sized part throws
from inside Tomcat's parameter parsing where no @ExceptionHandler can reach it, so the request died
as a 500 and then died again forwarding to /error, because that forward re-parsed the same too-large
request (the paired "Exception Processing [ErrorPage...]" lines in the log). resolve-lazily moves the
throw into argument binding, where AdminController now catches it and returns the same `problem`
flash the domain's other refusals use. max-swallow-size lets the body be discarded so the browser
receives that redirect rather than a connection reset.

The multipart numbers are asserted rather than trusted, because a default that was never set is
exactly the kind of thing that comes back silently.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
2026-07-27 18:45:46 -05:00
co-authored by Claude Opus 5
parent 9026b96629
commit 537273cb62
9 changed files with 206 additions and 2 deletions
+37
View File
@@ -0,0 +1,37 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="The Vine">
<!--
ONE LEAF, NOT THE LOGO. The wordmark's mark is a six-leaf vine branch drawn in hairlines, and at the
16px a browser tab actually paints it collapses into a grey smudge, because the strokes are thinner
than a pixel. So this takes the single recognisable unit of that branch, a lanceolate leaf, and draws
it filled rather than stroked: at this size a silhouette survives and an outline does not.
NO MIDRIB, deliberately. A vein was drawn first and rendered at 16px it split the leaf into two pale
slivers, which is the same legibility problem the outline had. It looked better at 32px and worse
where it counts, so it went. What identifies the shape is the two pointed ends, the tilt and the stem.
Sage on cream, both from the site's own palette (bakery-600 on bakery-50). An SVG favicon can answer
the browser's colour scheme, which a .ico cannot, so the dark variant swaps to bakery-400 on
bakery-900 rather than leaving a cream tile glowing in a dark tab strip.
-->
<style>
.ground { fill: #faf7f0; }
.leaf { fill: #5f6f52; }
.stem { stroke: #5f6f52; }
@media (prefers-color-scheme: dark) {
.ground { fill: #232b1e; }
.leaf { fill: #a2ae8b; }
.stem { stroke: #a2ae8b; }
}
</style>
<rect class="ground" width="64" height="64" rx="14"/>
<!-- Tilted so it reads as growing rather than floating. The stem's tip lands inside the tile after the
rotation: at -30 degrees it sits at roughly (46, 56) of 64. -->
<g transform="rotate(-30 32 32)">
<!-- Pointed at both ends: two mirrored curves from tip to tip, which is what makes it a leaf and
not an eye. -->
<path class="leaf" d="M32 7 C47 22 47 41 32 53 C17 41 17 22 32 7 Z"/>
<path class="stem" fill="none" stroke-width="3.4" stroke-linecap="round" d="M32 53 L32 60"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB