Three small features and one UX bug.
1. **Hearts.** New `activity_hearts(activity_id, user_id, created_at)`
table with composite PK. POST/DELETE /api/activities/:id/heart for
logged-in users on any non-private activity. Idempotent — re-posting
is a no-op rather than a 409.
Activity serialisation now includes `heart_count` and
`viewer_hearted` on all three visibility variants (private is always
0/false; hearts make no sense there). ActivityRow renders a toggle
button with optimistic updates and a local override that snaps back
on network error, then propagates the server's authoritative state
to the parent list via a new `onChanged` callback.
2. **Admin can triage feedback.** Added `done_at` + `done_by` columns
to feedback (migrated via ensureColumn for older scaffold DBs). New
admin-only endpoints:
PATCH /api/feedback/:id — { done: boolean }; sets/clears done_at
DELETE /api/feedback/:id — drops the entry
The Feedback list view sorts open requests above done ones, and
admins see "Marker som ferdig" / "Marker som åpen" / "Slett" buttons
per entry. Open/done badges visible to everyone with read access
(i.e., moderators).
3. **Clicking an activity opens its permalink.** Activity titles in
ActivityRow are now anchor links to /a/:id, so clicking the title
navigates to the permalink view. Action buttons (heart, edit,
delete, del/copy-link) stay inside the card; the anchor only wraps
the title text, so taps elsewhere don't navigate.
Bundle gained 1 KB gzipped (30.2 → 31.2 KB). 26 tests still pass,
typecheck clean.