Board scaling: no sideways scrolling
- Revert the pannable narrow canvas. The canvas fits the viewport again and
`.viewport` goes back to `overflow: clip`, so a board can never widen the
document or scroll horizontally.
- Fix the unreadable-narrow-board regression at the real cause instead: cap the
inverse UI compensation at 2x (50% canvas scale). Down to 50% text and
controls keep their physical size; below it the board zooms out as a whole, so
a 200x200 logical tile hosts at most 28px logical text rather than 96px and
content stops overlapping its neighbours.
Touch editing
- Add `touch-action: none` to `.board-grid-entry`, the dnd-kit draggable and its
own drag handle. The 200ms touch activation delay is useless if the browser
has already handed the gesture to page panning and emitted `pointercancel`.
Only edit mode renders this element.
Custom widgets
- Memoize the merged `data`/`status`/`options` passed to `CustomJsxRenderer`.
They were rebuilt every render, so the compiled-template memo never hit and
the new reference-identity boundary key changed on every render, resetting the
error boundary and forcing an extra reconciliation of the widget subtree.
- Keep the cache key when the shared Redis cache is unavailable so the
process-local cache still absorbs polling instead of sending every widget
refresh upstream.
- Reclaim the shared cache's LRU/size/byte bookkeeping for TTL-expired entries
and touch the LRU in the same script, so expired ghosts stop consuming the
64 MiB budget and a read costs one round trip instead of two.
Forwarded IP
- Restore `ipAddressFromHeaders` to the full forwarding chain and add
`trustedIpAddressFromHeaders` for the last hop. Repointing the shared helper
had collapsed MCP failed-auth rate limiting into a single bucket for every
client behind a reverse proxy and replaced the client IP with the proxy IP in
API-key auth logs.
Runtime and restore
- Make the new /appdata ownership migration best-effort. Under `set -e` a mount
that rejects chown (CIFS/SMB, fixed-uid NFS) turned into a container that
refuses to start, and /appdata was never chowned before.
- Report malformed metadata.json as such instead of blaming the archive.