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>
46 lines
2.7 KiB
Markdown
46 lines
2.7 KiB
Markdown
# 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).
|