Choose a cover in two parts, and let the app be installed

A cover is a colour *and* a pattern now, chosen in turn. Offering every
combination as its own entry meant fifteen colours times a dozen patterns
in a grid nobody could take in — and in practice only the handful someone
had thought to write out. Each pattern is previewed over the colour in
hand, so what is on screen is the cover as it will be. `cover_pattern` is
its own column: they are two decisions, and folding them into one number
would mean renumbering every cover the day a pattern is added.

For one day the patterns *were* twelve appended entries. Those indices
are read back as the colour-and-pattern pair they were drawn as, so
nothing chosen then looks different now.

And three separate reasons the install button never appeared, none of
them in anyone's configuration:

- `beforeinstallprompt` fires once, early — usually before React has
  mounted — and is never fired again. A listener added from inside a
  component simply missed it. It is caught at the top of index.html now.
- A `<link rel="manifest">` is fetched with credentials omitted unless it
  says otherwise. Behind a reverse proxy that authenticates in front of
  the app, that one request comes back as the proxy's login page and the
  browser reads it as an invalid manifest — while the app itself works
  perfectly, because its own requests carry the cookie.
- The service worker cached whatever came back, so a lapsed session could
  be stored as the application itself. The app would then "work offline"
  by showing a login screen it could never get past, curable only by
  clearing the site's data. Only successful, unredirected responses are
  cached now, and the cache name is bumped to drop anything already
  stored under the old rules.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-08-12 02:20:37 +02:00
1 parent 0d8d1180de
commit 8ca1ed6e06
17 files changed
+455 -221

No files matched your search

+31
View File
@@ -8,6 +8,37 @@ not from the output of `docker push`.
---
## Unreleased
**Changed**
- **A cover is now a colour and a pattern, chosen in turn**, rather than a list
with the combinations someone happened to write out. Every combination is
available, and each pattern is previewed over the colour in hand. Covers saved
during the day the patterns were one list are read back as the pair they were
drawn as, so nothing repaints itself.
**Fixed**
- **The install button never appeared, even over HTTPS.** Two causes, both in
this app rather than in anyone's configuration:
- `beforeinstallprompt` fires once, early — usually before React has mounted —
and is never fired again, so a listener added from inside a component simply
missed it. It is caught at the top of `index.html` now.
- The manifest is fetched **without credentials** unless the link says
otherwise. Behind a reverse proxy that authenticates in front of the app,
that request comes back as the proxy's login page and the browser reads it
as an invalid manifest — while the app itself works perfectly, because its
own requests carry the cookie. The link now says
`crossorigin="use-credentials"`.
- **The service worker could cache a proxy's login page as the application.**
Nothing checked that a response was the thing that had been asked for, so a
lapsed session could be stored as the app shell: it then "worked offline" by
showing a login screen it could never get past, curable only by clearing the
site's data by hand. Redirected and unsuccessful responses are no longer
cached, and the cache name is bumped so anything already stored under the old
rules is dropped.
---
## 2026-08-12 — Making the phone work
**Images** — web `sha256:5ea846f3…`, server unchanged at `sha256:06f94f43…`