vinterliste/server
Ole-Morten Duesund 6e005fc2d7 feat(activity): per-viewer archive and hide
Two new per-viewer flags on activities, mirroring the heart/done shape:

- ARCHIVE: any viewer (incl. the owner) can archive a row. Out of
  sight by default but the permalink still resolves. For owners,
  archive also filters the row out of their /<bruker>/liste public
  page — "I'm done sharing this."
- HIDE: only non-owners. "This doesn't appeal to me." Endpoint
  returns 400 cannot_hide_own when the owner tries it (they should
  delete or archive instead).

Both default-filtered from GET /api/activities. Opt-in via query
params with three modes each: exclude (default), include (1), only.
?archived=1&hidden=1 includes both; ?archived=only shows just the
archive. The list endpoint composes the SQL filters per-viewer
(anonymous viewers have no rows in either table → no-ops).

Schema: two new tables user_archived_activities and
user_hidden_activities, both composite-PK on (user_id, activity_id),
cascade on both refs. Same shape as the existing engagement tables.

Types: viewer_archived + viewer_hidden on every Activity variant.
viewer_hidden on private is always false (the endpoint refuses);
docstring on the type explains why.

Bulk lookups extended so the list endpoint stays at constant queries.
Single-row paths get per-row viewerArchived/viewerHidden helpers.
fetchRowForViewer keeps preserving the viewer's custom sort_position
on toggles.

UI: two new buttons in ActivityRow's action row — "📦 Arkiver" /
"📦 Arkivert" (everyone) and "🙈 Gjem" / "🙈 Skjult" (non-owners
only). Two new checkboxes near the search field on /hjem: "📦 Vis
arkivert" and "🙈 Vis skjult". Toggling either re-fetches from the
server because the filtering is server-side. When an archive/hide
flips the row out of the current view, Home.svelte triggers a
refetch so the row disappears in real time.

Public-list endpoint (/api/users/:bruker/list) also filters out the
owner's own archived rows — consistent with "archive means filed
away from active view."

Tests: 3 new in engagement.test.ts — viewer archives + per-viewer
isolation, owner's archive filters their public list, hide refuses
on own row + ?hidden=only path. Suite goes 102 → 105.
2026-05-25 20:19:44 +02:00
..
activities.ts feat(activity): per-viewer archive and hide 2026-05-25 20:19:44 +02:00
admin.ts Admin role, root/home URL split, activity permalinks 2026-05-25 13:23:13 +02:00
auth.ts External profile links (max 5 per user) 2026-05-25 16:20:04 +02:00
db.ts feat(activity): per-viewer archive and hide 2026-05-25 20:19:44 +02:00
feedback.ts fix(feedback): stop exposing done_by user id in API responses 2026-05-25 13:54:07 +02:00
friends.ts Friends + friends-only visibility + blocking 2026-05-25 14:47:20 +02:00
index.ts refactor: Norwegian URL paths 2026-05-25 18:20:50 +02:00
invites.ts fix(invites): build share URL on the client, not the server 2026-05-25 16:25:55 +02:00
og.ts refactor: Norwegian URL paths 2026-05-25 18:20:50 +02:00
reset-password.ts feat(ops): emergency password-reset CLI + deployment docs 2026-05-25 20:04:57 +02:00
roles.ts Admin role, root/home URL split, activity permalinks 2026-05-25 13:23:13 +02:00
session.ts Scaffold Vinterliste — end-to-end encrypted winter activity list 2026-05-25 12:27:14 +02:00
settings.ts Self-registry toggle, invite links with attribution, first-user-admin 2026-05-25 13:45:32 +02:00
tags.ts feat(tags): moderators and admins can delete public tags 2026-05-25 17:57:33 +02:00
users.ts feat(activity): per-viewer archive and hide 2026-05-25 20:19:44 +02:00