feat(briefwechsel): discovery landing grid + gap markers #338
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The Briefwechsel page is perceived as a constrained version of document search — "search filtered to sender/receiver". It lacks a distinct identity as a correspondence reader. Two changes address this:
Feature A — Discovery Landing Grid
Behaviour
When
/briefwechselloads with nosenderIdin the URL, the page shows a discovery grid of the archive's most prolific correspondences, sorted by letter count descending.The person selectors remain visible above the grid at all times — goal-directed users can type directly without touching the grid.
On card click:
/briefwechsel?senderId=…&receiverId=…— shareable and bookmarkable.Grid visibility rule: The grid is shown only when both selectors are empty (no
senderIdin URL). Clearing one selector while the other still has a value falls through to the existing single-person filter behaviour — the grid does not reappear in that case. Clearing both selectors restores the grid.Card Design
Each card:
bg-surface(#E4E2D7), border:border border-linebg-primary(#002850), white textbg-accent(#A6DAD8),text-primarytextborder-2 border-surfaceto visually separatefont-serif font-bold text-sm text-primary— e.g. "Käthe · Wilhelm"font-sans text-xs text-ink-3— e.g. "34 Briefe · 1912–1938"Grid layout:
gap-4Section label above grid:
text-xs font-bold uppercase tracking-widest text-ink-3— "Die aktivsten Korrespondenzen"Backend — New Endpoint
GET /api/documents/top-correspondencesReturns the top N person-pairs ranked by total letter count (both directions combined: Käthe→Wilhelm + Wilhelm→Käthe = one pair, one combined count).
Response (array):
Query parameter:
limit(default 10, max 20).Pair canonicalisation (to merge both directions into one): developer's choice at implementation time — lower UUID first or alphabetical by last name both work; pick one and document it (see OQ-01 below).
The
senderName/receiverNamein the response should be the person with the higher outgoing count of the pair (so the card reads naturally: the more prolific writer on the left).Feature B — Gap Markers
Behaviour
A gap marker is injected between two consecutive letter rows in the timeline when the gap between their dates is ≥ MIN_GAP_YEARS.
(Frontend equivalent if computed client-side:
const MIN_GAP_YEARS = 1;)The marker shows the duration in whole years, rounded down, with correct German plural:
Since letters are already grouped by year dividers, a gap marker only appears between entries in different years with a gap ≥ MIN_GAP_YEARS. It never appears between two letters in the same year.
Calculation (frontend, no backend change needed)
Visual Design
Tailwind classes:
flex items-center gap-3 px-4 py-3 text-ink-3flex-1 border-t border-dashed border-linefont-sans text-xs font-bold uppercase tracking-widest text-ink-3 whitespace-nowrapIntentionally quiet — the marker is a breath in the narrative, not an error state.
Acceptance Criteria
Feature A
Feature B
Open Questions
Future Direction
Gap markers are step one of a larger idea: Briefwechsel should contain more information than a document search with sender/receiver filters, not less. A correspondence has a shape — an arc, silences, a beginning and an end — that a flat search result list structurally cannot express. Gap markers make the silences visible. Contextual annotations (OQ-02, OQ-03) would make them meaningful. This is the direction worth pursuing.