Politrack: track Austrian politicians from public sources

Initial import of Politrack, a self-hosted service that tracks Austrian
politicians from federal to municipal level - roles, votes, money flows,
statements, meetings, social media and legal proceedings - with every claim
linked to its sources.

- backend: FastAPI + Postgres/pgvector; adapter framework (fetch -> parse ->
  load -> enrich) with robots.txt/TDM-aware fetching, a raw-response archive
  for reparsing, and a claim/evidence model with corroboration
- sources: Parliament, Wikidata, EU Parliament/Commission, Council of
  Ministers, Rechnungshof party reports and donations, procurement, RTR media
  transparency, political ad libraries, WKStA, news feeds, Wikipedia edits,
  Bluesky, Mastodon, public Telegram channels, YouTube and X (official API)
- web: Next.js frontend in German and English with typed API client
- mcp: MCP server for AI agents and RAG
- docs: architecture, data model, sources, legal notes, Unraid deployment and
  contributor guides; Docker Compose setup for Unraid

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Simon DiesenreiterandClaude Opus 5.5 committed 2026-10-28 19:47:14 +01:00
commit 9da5a1dc48
187 files changed
+39890

No files matched your search

+45
View File
@@ -0,0 +1,45 @@
# Extending the API (and the MCP server)
Data flows out through three layers that are kept deliberately thin:
```
politrack/queries/<domain>.py SQL, returns dicts (shared by REST API and MCP server)
politrack/api/schemas.py Pydantic response models (the contract → OpenAPI → TypeScript)
politrack/api/main.py FastAPI endpoints (parameters, 404s, response_model)
politrack/mcp_server.py MCP tools for AI agents (same query functions)
```
## Adding an endpoint, step by step
1. **Query** – add a function to the matching module in `politrack/queries/` (people, organizations,
claims, votes, money, search, admin) and export it from `queries/__init__.py`.
* Only show visible claims: use `VISIBLE` (published, not merged) from `queries/common.py`.
* Respect the user's source filter: take a `SourceFilter` and use `evidence_json(source_sql)` to
aggregate evidence – claims whose evidence is entirely filtered out must disappear.
* Always parameterise (`%(name)s`), never format user input into SQL. `LIMIT/OFFSET` on lists.
2. **Response model** – add a class to `api/schemas.py` (inherit from `Model`). Field names = column names.
3. **Endpoint** – in `api/main.py`, with `response_model=...`. Reuse the dependencies `DB`, `Sources`,
`Limit`, `Offset`; comma-separated list parameters go through `csv_list()`.
4. **Types for the web app**:
```bash
cd backend && politrack openapi --ts ../web/src/lib/api-types.ts
```
Then add a typed function to `web/src/lib/api.ts`. Commit the regenerated `api-types.ts`.
5. **MCP tool** (if agents should use it) – a `@mcp.tool()` in `mcp_server.py` with a docstring that tells
the agent what the data means and how to cite it.
6. **Test** – extend the API smoke test (see [testing.md](testing.md)).
## Conventions
* URLs: `/api/v1/<plural noun>[/<slug>[/<sub-resource>]]`; slugs, never internal ids, for people,
parties and organisations (vote events use ids – they have no natural slug).
* Every claim-like object carries `evidence: [{url, title, source, published_at, quote, …}]` and
`source_count`.
* Legal matters always include `legal_stage`; the client decides about the presumption-of-innocence
notice (`needsInnocenceNotice` in the web app, the `instructions` in the MCP server).
* Admin endpoints require `Authorization: Bearer $POLITRACK_ADMIN_TOKEN` and are excluded from the schema.
## Read-only database access for agents and BI tools
The role `politrack_reader` (password `POLITRACK_READER_PASSWORD`) can `SELECT` everything. Useful views:
`claim_with_evidence`, `person_status`, `person_identifier`. See [../data-model.md](../data-model.md).