fix(shopping): stale-row cleanup, cache-busting, view persistence

Root cause of the doubled lists: the relay DB had stale rows from
previous activations that were never deleted. The composite PK
prevented same-uid duplicates but not leftover rows from cards that
were deactivated without a successful DELETE.

Fixes:
  - Client tick sends DELETE { keep: [active uids] } after every
    push cycle. The relay drops all rows for this tenant that aren't
    in the keep list — cleans up migration leftovers, failed deletes,
    old single-list sentinels, everything in one shot.
  - Relay DELETE endpoint accepts { keep: [...] } for bulk cleanup
    alongside the existing { card_uid } single-delete.
  - Relay layout.php adds cache-busting query strings on style.css
    and app.js via filemtime() so phone browsers pick up new code
    on deploy instead of serving stale cached versions.
  - showView persists the active view name to localStorage; after
    login the relay restores it instead of always landing on compose.
  - Shopping-list-box border/background removed — items have their
    own chrome, the box is just a flex grouper now.
  - View title is always "Shopping"; each list box keeps its own
    header with the card title. No more doubled name.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
thandClaude Opus 4.6 committed 2026-04-16 18:20:46 +02:00
1 parent 5c9e9254d1
commit 6fa42eb267
7 files changed
+46 -20

No files matched your search

+8 -1
View File
@@ -298,11 +298,18 @@ async function pullOne(card, relayState) {
async function tick() {
const activeCards = getActiveCards();
if (!activeCards.length) return;
const activeUids = activeCards.map(c => String(c.id));
// Push all active cards first.
for (const card of activeCards) {
try { await pushOne(card); } catch {}
}
// Tell the relay to drop any rows that aren't in our active set.
// This cleans up stale entries from previous activations that
// were never explicitly deleted (old single-list era, failed
// DELETEs, migration leftovers).
try {
await hyprcrd.api('api/shopping', { method: 'DELETE', body: { keep: activeUids } });
} catch {}
// Pull: fetch all lists from relay, match by card_uid.
try {
const res = await hyprcrd.api('api/shopping', { method: 'GET' });