Files
simonandClaude Opus 5.5 456f9816f4 Redesign the web app from a written design concept
Design concept and design system in docs/design/: principles (evidence
first, neutral, fair to the people shown, plain language, time as a
dimension, accessible and private), information architecture, core
patterns and a concept for every page; tokens with checked contrast,
component catalogue, content and accessibility rules.

web:
- neutral ink-indigo accent instead of flag red; party colours only as
  small markers next to the name; light/dark theme with a switcher
- stylesheets split into tokens, base, layout, components, print
- new header (search, filter count, language, theme, mobile menu) and
  footer; breadcrumbs, page headers, tabs with counts, filter bars that
  collapse on phones, pagination, notices and empty states
- claim cards with source meter, legal stage, innocence notice inside
  the card and a permalink; claim pages with citation (/angaben/{id})
- profiles with role timeline and key figures; party and organisation
  dashboards; vote list with position chips; calendar agenda on phones;
  tables that stack into cards; loading and error pages; favicon

backend:
- GET /api/v1/claims/{id} and MCP tool get_claim for permalinks
- parties list: evaluate person_status once instead of per party
  (30 s -> 1 s on the sample database, identical result)
- parliament calendar: HTML-decode titles ("84. Sitzung")

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 22:21:44 +01:00

29 KiB
Raw Permalink Blame History

Politrack design concept

How Politrack looks, reads and behaves, and why. This is the concept: goals, principles, information architecture, the core patterns and a concept for every page. The companion design-system.md is the implementation reference: tokens, components, CSS conventions and recipes for contributors.

Items marked (later) are designed here but not built yet; everything else is implemented in web/.

1. Goals

Politrack is a public record of what Austrian politicians do, where every fact links to its source. The interface has four jobs, in this order:

  1. Make every fact checkable. A reader is never more than one click from the document behind a statement on the screen.
  2. Be fair to everyone shown. The same layout, wording and weight for every person and party; the presumption of innocence and the limits of the data are visible where they matter, not in a footer.
  3. Answer common questions fast, on a phone. "Who is this?", "How did they vote?", "Who gave money to whom?" in a few seconds, with no app and no account.
  4. Support deep research on a desk. Dense tables, filters in the URL, time ranges, cross-links between people, organisations and money, and stable links for citing.

2. Audiences and their tasks

Audience Context Top tasks What the UI must provide
Interested citizens Phone, linked from news or social media, a few minutes Look up a politician, a party's votes, donations Search first, plain language, clear summaries, a readable profile on a small screen
Journalists and researchers Desktop, long sessions, need to cite Follow money between organisations, build a timeline, check a claim Filters and date ranges in the URL, dense tables, permalinks per fact, source details, consistent numbers
NGOs and activists Desktop and phone, recurring Monitor topics and people Topic filters, calendar, (later) alerts
The people profiled and their staff Desktop Check what is shown about them Fair presentation, visible sources, (later) a corrections form
AI agents No UI (MCP server, REST API) Retrieve facts with evidence Mentioned in the footer and methodology; the UI never shows anything the API doesn't

3. Principles

Each principle comes with the rules that make it concrete.

P1 Evidence first. The atom of the interface is the claim card: a one-sentence summary plus its sources. Rules: the number of sources is always visible; the source list is one click away; every external link opens the original; quotes are shown as quotes (marked, attributed); there is no UI element that states a fact without a claim behind it.

P2 Neutral by design. Rules: the interface accent is a colour no Austrian party uses (an ink indigo, not the flag red, which reads as SPÖ red); party colours appear only as small identity markers (a dot or a thin bar) and always next to the party's name, never as large backgrounds; every party and person gets the same layout; lists are ordered by neutral criteria (date, size, alphabet); copy uses reporting verbs ("laut", "gemeldet", "berichtet") instead of judgement.

P3 Show certainty honestly. One vocabulary for how sure we are (see §6.3), shown the same way everywhere: single vs. multiple sources, disputed facts, unverified accounts, unconfirmed status, publication date vs. event date.

P4 Fairness for legal matters. The procedural stage is the headline of a legal claim; "Es gilt die Unschuldsvermutung" sits inside the claim card, not in a footnote; legal claims are styled in a neutral caution tone, never in alarm red; no portraits inside legal claim cards or feeds of allegations; connections between people and organisations carry the note that a connection is not an accusation; profile overviews highlight work (votes, speeches, offices), not allegations.

P5 Plain language, German first. German is the default at /, English at /en. Technical terms (namentliche Abstimmung, Klub, Ministerrat, Diversion) are explained where they appear. Long German compounds must not break layouts: hyphenation is on and long tokens may wrap.

P6 Time is a first-class dimension. Every list can be narrowed to a date range, profiles have a timeline, a calendar shows what happened on a day, and "search in time" lists everything in a period. Dates say what they are ("Datum = Veröffentlichung der Quelle" where we only know the publication date).

P7 Fast, robust, accessible, private. Server-rendered pages that work without JavaScript; WCAG 2.2 AA; system fonts; no third-party scripts, fonts, embeds or trackers; print stylesheets that keep source URLs.

P8 Shareable and citable. Filters live in the URL; every claim has a permalink page with a ready-made citation; page titles name the person or topic.

4. Brand and tone

Name and mark. politrack in lowercase, set in the system font at heavy weight. The mark is a pair of square brackets around a dot: the citation bracket of a footnote with the piece of evidence inside. It is the favicon too. Tagline: Österreichs Politik, belegt.

Colour stance. Near-monochrome "paper and ink" neutrals carry the interface. One accent, an ink indigo, marks interaction (links, focus, active navigation, magnitude bars). A highlighter yellow marks quoted evidence and search hits. Semantic colours (positive, negative, caution) appear only in small badges and always with an icon and a word, never as colour alone. Party colours follow the rules in P2.

Voice. Sachlich, precise, friendly. We address readers with "du" (as the existing copy does) and use gender-inclusive forms with a colon (Politiker:innen). We describe what a source says, with the source: "Laut Rechnungshof spendete …", not "X kaufte sich Einfluss". Numbers are exact where the source is exact and labelled as reported ("Beträge wie gemeldet").

5. Information architecture

Sitemap

/                         Start: search, key figures, latest facts, explore
/suche                    Search (full text and "search in time": a date range without a query)
/personen                 People (filters: party, level, status)
  /personen/{slug}        Profile with tabs: overview, timeline, votes, travel & meetings,
                          statements, social media, money & network, media & career, legal
/ehemalige                Former politicians: what they do now
/parteien                 Parties
  /parteien/{slug}        Party: officials, votes, money, finances, affiliated organisations, channels
/organisationen           Organisations (companies, associations, authorities, media, lobbies)
  /organisationen/{slug}  Organisation: money in and out, counterparties, connected people
/geld                     Money explorer: donations, contracts, ads, subsidies, party funding
/abstimmungen             Votes (faction votes; roll calls)
  /abstimmungen/{id}      Vote: result, factions, individual votes, dissent
/kalender                 Calendar: sessions, committees, hearings, Council of Ministers, trips, meetings
/social                   Public posts from politicians' and parties' channels
/wikipedia                Wikipedia edits from parliament and government networks
/angaben/{id}             Claim permalink: one fact with all its sources and a citation
/einstellungen            My filters: trusted sources, topics
/methodik                 Methodology, statuses, legal stages, sources and their terms

Route names are German in both languages (/en/personen/…): one URL scheme, links stay valid when switching language.

Navigation

  • Header, primary: Personen, Parteien, Abstimmungen, Geld, Organisationen, Kalender; Mehr: Social Media, Wikipedia-Bearbeitungen, Ehemalige, Methodik & Quellen. Utilities: a search field, Meine Filter with the number of active filters, language, light/dark theme. Below 1024 px the navigation collapses into a menu (a native disclosure, no JavaScript) and the search field becomes a search button.
  • Footer: the full sitemap in three groups (Menschen, Entscheidungen, Geld & Einfluss), the principles in three lines, links for developers and agents.
  • Breadcrumbs on every detail page (Start › Personen › Name).
  • Cross-links everywhere: every person, party and organisation name is a link; money rows link both sides; lists on profiles end with a "Alle …" link into the explorer, pre-filtered.

URL conventions

All filters are query parameters on plain GET forms (/geld?kind=donation&since=2025-01-01), so every view can be bookmarked and shared. Personal source/topic preferences are the only state kept outside the URL (a cookie), and the header always shows when they are active.

6. Core patterns

6.1 The claim card

┌──────────────────────────────────────────────────────────────────────┐
│ ◇ SPENDE  ·  12. März 2026  ·  Österreichische Volkspartei     ●●○ 2 │  type, date, subject, sources
│                                                                      │
│ Die Muster GmbH spendete der ÖVP 25.000 €.                           │  summary (the fact)
│ 25.000 € · Muster GmbH → ÖVP · 2025                                  │  type-specific details
│ [Wirtschaft] [Parteifinanzen]                                        │  topics
│ ▸ 2 Belege                                              Permalink ↗  │  evidence disclosure
└──────────────────────────────────────────────────────────────────────┘
  • The header row is metadata in small type: type label with icon, date, subject (when the list mixes subjects), and the source meter on the right.
  • The summary is the largest text in the card. In English the English summary is used when available.
  • Type-specific details (amounts, counterparts, platforms, file numbers) come from a registry, one renderer per claim type.
  • The evidence disclosure lists each source with its publisher, source kind (Amtlich, Medien, …), title, date, stance (supports / mentions / contradicts) and quote. Quotes are set as block quotes with the highlighter mark.
  • A permalink opens the claim page (§7.17).
  • Disputed claims get a caution edge and the word "umstritten". Claims awaiting review are never public; if one is shown (admin views) it carries "Noch nicht redaktionell geprüft".

6.2 Evidence and corroboration

The source meter shows up to three dots: one filled dot = one source ("einfach belegt"), two or more filled = "mehrfach belegt" with the number. A disputed claim shows a caution triangle and the word "umstritten" instead. A tooltip gives the full wording ("bestätigt durch 3 unabhängige Quellen"). The meter never stands alone: the number is always written next to it.

6.3 Certainty vocabulary

Concept Values (German UI) Shown as
Claim status einfach belegt · mehrfach belegt · umstritten source meter; caution edge for umstritten
Person status Aktiv · Ehemalig · Ohne Amt (Parteimitglied) · Verstorben status badge; "Aktiv" without an official confirmation adds "nicht amtlich bestätigt"
Social account bestätigt · nicht bestätigt unconfirmed accounts get a dashed badge and a tooltip (source: Wikidata only)
Review Noch nicht redaktionell geprüft caution notice (admin views only)
Dates Ereignisdatum · Veröffentlichungsdatum footnote on calendar and trips: "Datum = Veröffentlichungsdatum der Quelle"
Amounts wie gemeldet · Kategorie exact amount, or the reported category ("über 50.000 €")
┌──────────────────────────────────────────────────────────────────────┐
│ ⚖ VERFAHREN  ·  3. Februar 2026  ·  Name                       ●○○ 1 │
│ [Ermittlungsverfahren]  § 302 StGB  ·  WKStA                         │  stage first, as a badge
│ Summary of what the source reports …                                 │
│ ⓘ Es gilt die Unschuldsvermutung.                                    │  inside the card
│ ▸ 1 Beleg                                                            │
└──────────────────────────────────────────────────────────────────────┘

The notice is shown for every stage except an undisputed final conviction (including acquittals, dropped proceedings and diversion, which confirm there is no finding of guilt). Automatically detected legal claims stay in review until a human approves them. Profiles count legal claims only on their tab, never in the "at a glance" figures.

6.5 Money

  • Amounts in euro with locale formatting (25.000 €, €25,000); large figures in summaries and bar lists are compact (1,2 Mio. €) with the exact value in the tooltip; tables show exact values.
  • Direction is always explicit: Von → An. Both sides are links when the organisation is known.
  • Every amount says what kind of money it is (Spende, öffentlicher Auftrag, Regierungsinserat, Förderung, Parteienförderung, politische Werbung, Kredit). Different kinds are never summed into one figure without a label.
  • "Beträge wie gemeldet" and the list of registers sit under every money table.
  • Money of organisations a person is connected to (side jobs, career) is labelled as the organisation's money and carries the connection note.

6.6 Votes

  • A vote shows date, item title, reference, stage, chamber, result and the position of every faction as position chips: party dot + short name + position icon (✓ dafür, ✕ dagegen, – Enthaltung, ○ abwesend), with a tinted background per position.
  • Roll calls are marked ("namentlich"); they show individual votes grouped by faction with counts, and members who voted against their faction are marked "gegen die eigene Fraktion".
  • On a person's vote list the position says whether it is the faction's vote or the person's own vote, because most Austrian votes are recorded per faction only. The note explaining this sits above the list.
  • Say vs. vote: when the person spoke on the item, a link to the speech appears under the vote.

6.7 Time

  • Dates in lists: 12. März 2026 (de-AT) / 12 Mar 2026 (en-GB). Months in charts: 03/2026.
  • The activity histogram (claims per month) on profiles links each bar to that month.
  • Date range fields on every list that supports them; with no query, search becomes "search in time" and lists everything in the range.
  • The role timeline on a profile draws offices and memberships as bars on a year axis.

6.8 Filters

Two kinds, never mixed up:

  • Page filters (party, level, kind, date …) live in the URL. Active filters are visible in the form; a reset link clears them. On phones the filter form is collapsed behind "Filter" with the number of active filters.
  • My filters (trusted sources, minimum trust, topics) are stored in a cookie and apply to every list. When they are active, the header badge shows the count and lists show a notice with a link to change them, so nobody is surprised by missing data.

6.9 Connections

Wherever the UI shows that a person is connected to an organisation (side job, career, meeting, party) or shows the organisation's money, the note "Eine Verbindung ist kein Vorwurf." is part of the section.

6.10 Social posts

Posts are shown as text cards with platform, author, date and a link to the original; no embeds, no third-party images or scripts. Accounts that only Wikidata attributes to a person are marked "Konto nicht bestätigt". The collection policy (official APIs only; no Facebook/Instagram scraping; no WhatsApp, Signal or private Telegram groups) is stated on the page.

6.11 Empty, loading and error states

  • Empty: an icon, one sentence that says why ("Keine Angaben mit deinen Quellen- und Themenfiltern.") and the most likely next step (reset filters, broaden the date range).
  • Loading: skeleton blocks in the page's layout, no spinners.
  • Error: what happened in one sentence, a retry button, a link home.

7. Page concepts

Every page uses one of four templates: index (header, filters, results, pagination, source note), profile (identity header, key figures, tabs, main column plus aside), detail (header, verdict, breakdown) and prose (methodology).

7.1 Start (/)

Purpose: orient, search, show that the data is alive.

┌ hero ───────────────────────────────────────────────────────────────┐
│ Politik in Österreich – nachvollziehbar.                             │
│ Lede: what Politrack is, "jede Angabe mit Quelle".                   │
│ [ Person, Thema oder Stichwort …                     ] [Suchen]      │
│ Schnellzugriff: Parteispenden · Namentliche Abstimmungen · Inserate  │
└──────────────────────────────────────────────────────────────────────┘
[ 1.234 Personen ] [ 56.789 Angaben ] [ 1.210 Abstimmungen ] [ 9.876 Geldflüsse ]   Stand …
┌ Neueste Angaben (claim feed) ──────────┐ ┌ aside ───────────────────┐
│ claim card …                            │ │ Parteien (dot, name, n)  │
│ claim card …                            │ │ Letzte Abstimmungen      │
└─────────────────────────────────────────┘ └──────────────────────────┘
Entdecken: 6 cards with icon, title, one line (Geld, Organisationen, Social, Wikipedia, Ehemalige, Kalender)
So arbeitet Politrack: Belege · Unabhängige Bestätigung · Unschuldsvermutung  → Methodik

7.2 Search (/suche)

A large search field with optional date range. Results are cards with type label, date, subject and a snippet with the query terms highlighted; document hits (news, releases) show the publisher. Without a query but with a date range, the page lists all claims in that period ("search in time"). Empty states suggest fewer words or a wider range.

7.3 People (/personen)

Index template. Filters: name, party, level (EU, Bund, Land, Gemeinde, Partei), status (default: aktiv). Results are person cards in a responsive grid: portrait or initials, name, current roles (two lines max), party tags, and the status for non-active people. Pagination at the bottom.

7.4 Person profile (/personen/{slug})

Start › Personen › Name
┌──────┐  [Aktiv]                                     Profile elsewhere:
│      │  Vorname Nachname                            Parlament ↗  Wikidata ↗  EP ↗
│ foto │  Abgeordnete zum Nationalrat · ● ÖVP
│      │  * 3. Mai 1970 · Kanäle: [Bluesky] [Telegram*]
└──────┘
[Überblick] [Zeitleiste 312] [Abstimmungen 120] [Reisen & Treffen 4] [Aussagen 58] [Social Media]
[Geld & Netzwerk 6] [Medien & Werdegang 40] [Rechtliches 1]

Overview:
┌ main ─────────────────────────────────────┐ ┌ aside ───────────────────────┐
│ Laufbahn (role timeline on a year axis)   │ │ Auf einen Blick              │
│ Neueste Angaben (claim cards)             │ │ 120 Abstimmungen · 58 Reden  │
│                                           │ │ Funktionen & Mandate (list,  │
│                                           │ │ each with its sources)       │
└───────────────────────────────────────────┘ └──────────────────────────────┘
  • Tabs are links (?tab=votes), so every tab is shareable; each shows its claim count.
  • Zeitleiste: activity histogram, date range, all claims in the range.
  • Abstimmungen: the faction-vote note, then the vote list with position, own/faction vote, dissent and say-vs-vote.
  • Geld & Netzwerk: connected organisations (via side job, career, meeting, party) with their money, the connection note, the organisations' money flows, then money-related claims.
  • Rechtliches: legal claims only, each with stage and the innocence notice.
  • "At a glance" counts work: votes, speeches and statements, questions, side jobs, appearances, media reports; not legal matters.

7.5 Former politicians (/ehemalige)

Index template ordered by latest media coverage. Each card: name, status, last role, last office end, latest headline with source link and date, latest career entry. Party filter.

7.6 Parties (/parteien)

Cards with a thin top bar in the party colour, short name, full name, active officials and people tracked. Ordered by the number of active officials.

7.7 Party (/parteien/{slug})

──────── party colour bar ────────
Start › Parteien › ÖVP
ÖVP  Österreichische Volkspartei
[ 312 Funktionsträger:innen ] [ 1.020 Ehemalige ] [ 830 Abstimmungen ] [ 4 abweichende Mandatar:innen ]
┌ Stimmverhalten (proportion bar) ──┐ ┌ Geld nach Jahr und Art (table) ─────┐
└───────────────────────────────────┘ └─────────────────────────────────────┘
Funktionsträger:innen grouped by level (EU · Bund · Land · Gemeinde), multi-column
┌ Rechenschaftsberichte ────────────┐ ┌ Nahestehende Organisationen ────────┐
┌ Ehemalige ────────────────────────┐ ┌ Abweichendes Stimmverhalten ────────┐
Letzte Abstimmungen · Kanäle der Partei · Belegte Angaben

7.8 Organisations (/organisationen)

Index template with a table: name, kind badge, paid, received (compact amounts, exact in tooltip). On phones the table stacks into cards. Filters: name, kind.

7.9 Organisation (/organisationen/{slug})

Header with kind badge and parent organisation; identifiers (Firmenbuch, ZVR, UID, Wikidata, EU transparency register) in the aside with links where a public register page exists. Key figures (received, paid, counterparties). Counterparties as two bar lists ("zahlte an", "erhielt von"). Connected people with the connection note. Money flow table, then all claims. Parties redirect to their party page.

7.10 Money (/geld)

Explorer template. Filters: kind, name, date range, minimum amount. Unfiltered, the page opens with two bar lists, largest payers and largest recipients, each row labelled with the kind of money. Then the money table: date, kind, from, to, amount, sources. Footer: registers used and "Beträge wie gemeldet".

7.11 Votes (/abstimmungen) and vote (/abstimmungen/{id})

The index is a list of vote rows: date, title, reference, roll-call marker, result badge, position chips per faction. Filter: roll calls only. The vote page shows the verdict as a large result badge, links to the item and the protocol, faction positions, and for roll calls a proportion bar over all individual votes and the members grouped by faction with dissent marked. The protocol wording sits in a disclosure.

7.12 Calendar (/kalender)

Month grid (Monday first) with previous/next month as header actions. Each event shows its kind (colour stripe + label), title (linked to the source) and participants. Days with only claim activity link to "search in time" for that day. Today is highlighted. On phones the grid becomes an agenda: only days with events, in order. A legend explains the kinds; the footnote states the date precision.

7.13 Social media (/social)

Feed of post cards in one or two columns. Filters: platform, party. Each card: platform badge, author (person or party channel), date, title, text (clamped to a few lines), "Original ansehen ↗", unconfirmed marker. The collection policy closes the page.

7.14 Wikipedia edits (/wikipedia)

The framing comes first: a notice that an edit from a network says nothing about which person made it. Then a table: date, network (organisation), article (linked to the diff), size change, edit comment.

7.15 My filters (/einstellungen)

Two sections. Quellen: grouped by kind (Amtlich, NGO, Medien, Datenbanken, Soziale Medien, Community, Abgeleitet); each source is a switch row with name, trust value as a small meter, and its terms in the tooltip; a minimum-trust slider below. Themen: topic chips that toggle; none selected = all. A sticky action bar with Speichern, Zurücksetzen and the saved status. Stored in a cookie only.

7.16 Methodology (/methodik)

Prose template with a table of contents: how claims and evidence work, the status vocabulary with live badges, the legal stages glossary, the sources table (publisher, licence, access method, trust meter, terms notes), what we deliberately don't collect, corrections.

One fact on its own page: type, date, subject, the summary as the title, details, legal notice where applicable, all sources expanded with quotes, and a citation box: Politrack: „{Zusammenfassung}“. Angabe #{id}, abgerufen am {Datum}. {URL}. The page ignores personal source filters, so a shared link shows the same content to everyone.

7.18 Not found and errors

Not found: an empty state with the search field and links to Personen, Parteien and Start. Errors: one sentence, "Erneut versuchen", link home.

8. Responsive behaviour

Width Behaviour
< 640 px one column; tables stack into labelled cards; filter forms collapse; role timeline labels above the bars; tabs scroll horizontally
< 768 px the calendar becomes an agenda (only days with events)
640–1023 px two-column card grids; tables scroll horizontally inside their container; menu still collapsed
≥ 1024 px full header navigation with search field; profile pages get the aside column; two-column sections
≥ 1280 px content width caps at 76 rem; more cards per row

9. Accessibility (WCAG 2.2 AA)

  • Contrast ≥ 4.5:1 for text and ≥ 3:1 for UI parts in both themes (token values are chosen and checked for it, see the design system).
  • Never colour alone: positions, results, statuses and party identity always have text, and an icon or a shape where possible.
  • Keyboard: skip link, visible focus ring on everything, tabs and disclosures are native links and details elements, no keyboard traps.
  • Structure: one h1 per page, headings in order, landmarks (header, nav, main, footer), aria-current for the active page and tab, tables with header cells, charts with text equivalents.
  • Language: lang on the document; English summaries are marked when shown in the German UI.
  • Motion: no animation beyond short hover transitions; prefers-reduced-motion removes them.
  • Targets at least 24 × 24 px; form fields have visible labels.

10. Privacy and performance

  • No third-party requests from the page itself: system fonts, no analytics, no embeds, no CDNs. Portraits and logos still come from Wikimedia and the parliament; they load lazily with referrerpolicy="no-referrer". (later) an image proxy so visitors' IP addresses never reach third parties.
  • Server-rendered HTML; client JavaScript only for the filter settings, the theme switch, the language switch and active-link marking.
  • Budget: under 100 kB of CSS and JavaScript per page (compressed), first content without waiting for scripts.

11. Before going public

Not design work, but the design depends on them; flagged here so they are not forgotten:

  • Impressum and Offenlegung (§ 5 ECG, § 25 MedienG) and a privacy policy: footer links and a prose page each.
  • A corrections and right-of-reply path (§ 9 MedienG): a contact on the methodology page and, later, a form linked from every claim page.
  • The X deletion sync (see the roadmap) before X data is shown publicly.

12. Later

  • Claim permalinks are implemented; (later) a "Fehler melden" button on them.
  • Compare two people or parties side by side (votes, money, statements).
  • Topic pages (/themen/{slug}): everything on one topic across people and parties.
  • Alerts (e-mail or RSS) for people, parties and topics.
  • A review queue for editors in the web UI (today politrack review on the command line).
  • A map of trips and appearances.
  • Share images (Open Graph) generated per profile and claim.
  • CSV export of every table.