collab per-card unread, detail stale banner, image sync race fix

- per-card unread dot on board (collab-buckets): backend tracks
  last_seen_at per card, poll exposes unread_cards, frontend decorates
  matching board cards; cleared on any open path via detail.opened hook
- detail.opened + cards.reloaded hooks on the hyprcrd event bus
- stale banner in detail view with manual Reload when the currently
  viewed card got updated by a peer — no content swap under the user
- collab image sync: push attachments BEFORE card (race fix) + pull-side
  self-heal scans every collab card for missing uploads each poll
- relay user deletion now purges chat_messages sent by deleted user so
  ghost threads stop appearing for their peers
- calendar header nav buttons styled as square bordered buttons that
  honor --ui-radius-button; title bar widened to 280px so font variants
  don't wrap
- .toolbar-btn now uses var(--ui-radius-button) instead of hardcoded 3px

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
thandClaude Opus 4.6 committed 2026-04-14 22:39:32 +02:00
1 parent 39e94b8015
commit 26f95ba079
10 files changed
+324 -35

No files matched your search

+5
View File
@@ -82,6 +82,11 @@ if (preg_match('#^/api/users/(\d+)$#', $route, $m) && $method === 'DELETE') {
if ($id === (int)$sessionTenant['id']) {
jsonResponse(['error' => 'cannot delete yourself'], 400);
}
// chat_messages.recipient_id cascades via FK, but sender_id is ON DELETE
// SET NULL — that leaves sender_username populated so the deleted user
// keeps showing up as a chat thread for their peers. Purge those rows
// explicitly BEFORE the tenant delete, while sender_id is still matchable.
$db->prepare('DELETE FROM chat_messages WHERE sender_id = :id')->execute(['id' => $id]);
$db->prepare('DELETE FROM tenants WHERE id = :id')->execute(['id' => $id]);
jsonResponse(['ok' => true]);
}