Zum Inhalt

LLARS v1 Konferenz-Manager API

Version: 1.0 | Stand: Oktober 2026

Programmatische REST-API für den Konferenz-Manager: Forschungsgruppen lesen, Konferenzserien und Editionen pflegen (bestätigte Termine und geschätzte Zeitfenster), Paper samt Autoren, arXiv-/DOI-Links und Einreichungs-Historie verwalten und die KI-Aktualisierung starten, beobachten und abbrechen. Alle Endpunkte liegen unter /api/v1/conference-manager/*.

Authentifizierung

Identisch zur Scenario-API: X-API-Key (persönlich oder System) oder OAuth Bearer. Siehe v1 Scenario API. Persönliche Keys legst du unter Einstellungen → API-Keys an und wählst dort die Scopes conference:read und/oder conference:write.

Scopes

Scope Erlaubt RBAC-Fallback (OAuth, Keys ohne Scopes)
conference:read alle GET-Endpunkte unter /api/v1/conference-manager/* feature:conference_manager:view
conference:write alle POST / PATCH / PUT / DELETE, inklusive Start und Abbruch der KI-Aktualisierung; schließt Lesen ein feature:conference_manager:edit
admin:* überschreibt alles admin:permissions:manage

Die Konferenz-Scopes sind strikt von scenario:* und chatbot:* getrennt.

Scope und Recht zusammen: Ein Scope schränkt einen Key ein, er erweitert ihn nie. Zusätzlich zum Scope muss das Konto, dem der Key gehört, das passende Feature-Recht haben (feature:conference_manager:view zum Lesen, …:edit zum Schreiben; Admins immer). Wird einem Konto das Recht entzogen, funktionieren seine Konferenz-Keys sofort nicht mehr (403).

Forschungsgruppen und Sichtbarkeit

Jede Serie, Edition, jedes Paper und jeder KI-Lauf gehört zu genau einer Forschungsgruppe. Jeder Aufruf wird gegen die Gruppe geprüft:

Situation Antwort
Du bist Mitglied (Rolle owner oder member) Lesen und Schreiben
Du bist Mitglied mit Rolle viewer Lesen; Schreiben → 403
Du bist kein Mitglied 404 — exakt wie bei einer nicht existierenden ID
Admin / System-Key alle Gruppen

Die 404 bei fremden Gruppen ist Absicht: So lässt sich nicht per Statuscode abtasten, welche IDs es in anderen Gruppen gibt. Verweise im Body (series_id, conference_id) müssen in derselben Gruppe liegen wie das Objekt, sonst ebenfalls 404. Ältere Datensätze ohne Gruppe sieht nur ein Admin; die API legt nie Datensätze ohne Gruppe an (group_id ist beim Anlegen Pflicht und lässt sich später nicht ändern).

Antwort- und Fehlerformat

Erfolgreiche Antworten tragen "success": true und das Objekt unter seinem Namen (conference, series, paper, run, research_group). Listen sind paginiert:

{ "success": true, "conferences": [ ... ], "total": 42, "limit": 50, "offset": 0 }

limit ist höchstens 200 (größere Werte werden gekappt, Standard 50), offset beginnt bei 0. Fehler kommen einheitlich:

{
  "success": false,
  "error": "Invalid request body — Value error, submission_window_start must be on or before submission_window_end",
  "error_type": "validation_error",
  "details": { "errors": [ { "loc": [], "msg": "...", "type": "value_error" } ] }
}
Status Bedeutung
200 / 201 gelesen bzw. angelegt
202 KI-Lauf angenommen (läuft im Hintergrund)
400 ungültiger Body oder Query-Parameter (unbekanntes Feld, falsches Datum, Fenster mit start > end, ungültige DOI …)
401 kein oder ungültiger Key
403 Scope fehlt, Feature-Recht fehlt oder Gruppe nur lesbar (viewer)
404 existiert nicht oder gehört zu einer fremden Gruppe
409 Konflikt: Edition (acronym, year) oder Serien-Kürzel existiert schon; in der Gruppe läuft bereits ein KI-Lauf
503 KI-Aktualisierung auf diesem Server nicht verfügbar

Termine: bestätigt oder geschätzt

Jede Edition hat drei Meilensteine. Jeder kann einen exakten Termin (bestätigt) und/oder ein Zeitfenster (geschätzt) haben:

Meilenstein Exakter Termin Zeitfenster
Einreichung submission_deadline submission_window_start, submission_window_end
Autoren-Benachrichtigung notification_date notification_window_start, notification_window_end
Konferenz start_date, end_date conference_window_start, conference_window_end
  • Formate: Exakte Termine sind naive ISO-Datetimes YYYY-MM-DDTHH:MM:SS (in der Antwort immer so). Beim Schreiben ist auch ein reines Datum (2027-05-15 → 00:00:00) oder ein Offset (Z, +02:00) erlaubt; ein Offset wird nach UTC umgerechnet und dann entfernt. Fenstergrenzen sind reine Daten YYYY-MM-DD — eine Uhrzeit ist hier ein 400.
  • Regeln: start ≤ end je Fenster und start_date ≤ end_date, sonst 400. Ein PATCH, der nur eine Grenze ändert, wird gegen den gespeicherten Gegenwert geprüft. Unparsebare Werte sind immer ein 400 — nie ein stilles Löschen.
  • Der exakte Termin gewinnt: Kommt der echte Termin, setzt du ihn per PATCH. Das Fenster bleibt als Historie stehen, der Meilenstein gilt ab dann als bestätigt.
  • Abgeleitete Felder in der Antwort: milestones je Meilenstein mit status (confirmed | estimated | unknown), date bzw. start/end und window_start/window_end; is_estimated ist true, sobald ein Meilenstein nur geschätzt ist. estimation_basis (Freitext, z. B. „abgeleitet aus 2023–2026") und estimation_confidence (low | medium | high) erklären die Schätzung. Dazu kommen core_url (CORE-Portal), maps_url (Google Maps), last_refreshed_at und last_refresh_summary.

PATCH-Semantik (überall): Nur gesendete Felder werden geändert. Ein explizites null leert ein optionales Feld (z. B. "notes": null). Pflichtfelder (name, acronym, year, title) und core_ranking einer Edition dürfen nicht null werden — zum Entfernen des Rankings "Unranked" senden. Unbekannte Felder sind ein 400.

Endpunkte

Forschungsgruppen

Methode Pfad Scope Zweck
GET /api/v1/conference-manager/research-groups conference:read Eigene Gruppen mit user_role (Admins: alle)
GET /api/v1/conference-manager/research-groups/{id} conference:read Gruppe mit user_role, stats und members

Gruppen und Mitgliedschaften verwaltest du in der Oberfläche; die v1 legt keine Gruppen an.

Serien

Methode Pfad Scope Zweck
GET /api/v1/conference-manager/series?group_id=&search= conference:read Serien (ohne group_id: alle zugänglichen Gruppen)
POST /api/v1/conference-manager/series conference:write Serie anlegen (group_id, name, acronym, optional core_ranking, website_url, keywords, notes)
GET /api/v1/conference-manager/series/find?acronym=&group_id= conference:read Serie per Kürzel (Groß-/Kleinschreibung egal); series: null, wenn keine passt
GET /api/v1/conference-manager/series/{id} conference:read Serie mit ihren Editionen
PATCH /api/v1/conference-manager/series/{id} conference:write Teil-Update
DELETE /api/v1/conference-manager/series/{id} conference:write Löschen; Editionen bleiben, verlieren nur den Serien-Bezug

Serien-Kürzel sind serverweit eindeutig — ein vergebenes Kürzel ergibt 409.

Konferenzen (Editionen)

Methode Pfad Scope Zweck
GET /api/v1/conference-manager/conferences conference:read Editionen (Filter siehe unten)
POST /api/v1/conference-manager/conferences conference:write Edition anlegen (group_id, name, acronym, year + beliebige Felder aus dem Abschnitt „Termine")
GET /api/v1/conference-manager/conferences/{id} conference:read Edition lesen
PATCH /api/v1/conference-manager/conferences/{id} conference:write Teil-Update aller Felder inkl. Fenster
DELETE /api/v1/conference-manager/conferences/{id} conference:write Löschen; Paper bleiben, verlieren nur den Konferenz-Bezug
GET /api/v1/conference-manager/conferences/{id}/papers conference:read Paper dieser Edition

Weitere Felder einer Edition: series_id, core_ranking (A*, A, B, C, Unranked), city, country, website_url (nur http(s)://), keywords (≤ 50), notes. (acronym, year) ist serverweit eindeutig → 409.

Filter für GET /conferences (alle optional, kombinierbar):

Parameter Wirkung
group_id nur diese Gruppe (fremde Gruppe → 404); ohne: alle zugänglichen
year Jahrgang der Edition
search Teilstring in Name, Kürzel, Stadt oder Land
estimated true: nur Editionen mit mindestens einem geschätzten Meilenstein; false: keine solchen
from, to YYYY-MM-DD; eine Edition passt, wenn sich ihr Gesamtzeitraum (alle Termine und Fenster) mit [from, to] überschneidet. Editionen ganz ohne Termin fallen dann heraus.
core_ranking A*, A, B, C, Unranked

Sortiert wird nach Einreichungsfrist (bei geschätzten Editionen nach dem Fensterbeginn), Editionen ohne beides am Ende.

Paper, Autoren, Einreichungen

Methode Pfad Scope Zweck
GET /api/v1/conference-manager/papers?group_id=&conference_id=&status=&search= conference:read Paper (Suche in Titel und Beschreibung)
POST /api/v1/conference-manager/papers conference:write Paper anlegen
GET /api/v1/conference-manager/papers/{id} conference:read Paper mit Autoren, Einreichungen, Konferenz
PATCH /api/v1/conference-manager/papers/{id} conference:write Teil-Update; authors ersetzt die Liste
DELETE /api/v1/conference-manager/papers/{id} conference:write Löschen inkl. Autoren und Einreichungen
PUT /api/v1/conference-manager/papers/{id}/authors conference:write Autorenliste komplett ersetzen
POST /api/v1/conference-manager/papers/{id}/submissions conference:write Einreichung anhängen
PATCH /api/v1/conference-manager/papers/{id}/submissions/{sid} conference:write Einreichung ändern
DELETE /api/v1/conference-manager/papers/{id}/submissions/{sid} conference:write Einreichung löschen
  • Felder: group_id, title, status (planning, in_progress, submitted, accepted, rejected, published), conference_id, overleaf_url, external_url, arxiv_url, doi, keywords, description, notes, authors.
  • arXiv und DOI: arxiv_url nimmt arXiv:2401.12345, 2401.12345 oder einen arxiv.org-Link und speichert https://arxiv.org/abs/<id>. doi nimmt doi:10.…, https://doi.org/10.… oder die nackte DOI und speichert die nackte DOI. Die Antwort enthält zusätzlich arxiv_id und doi_url (https://doi.org/<doi>). Ungültige Werte sind ein 400.
  • Autoren: Liste in Reihenfolge, je Eintrag genau eines von user_id, username (LLARS-Konto) oder external_name (externe Person), optional author_order (Standard: Listenposition) und is_corresponding. Unbekannte oder doppelt genannte Konten sind ein 400; höchstens 50 Autoren.
  • Einreichungen: conference_id, status (submitted, accepted, rejected, withdrawn), submitted_at, decided_at (exakte Termine), notes. Das Paper übernimmt Konferenz und Status der neuesten Einreichung. Eine Einreichung ist nur über ihr eigenes Paper erreichbar — eine fremde sid im Pfad ergibt 404.

KI-Aktualisierung

Methode Pfad Scope Zweck
POST /api/v1/conference-manager/conferences/refresh conference:write Lauf für eine Gruppe starten → 202
POST /api/v1/conference-manager/conferences/{id}/refresh conference:write Lauf für genau diese Edition → 202
GET /api/v1/conference-manager/refresh-runs?group_id=&limit= conference:read Letzte Läufe der Gruppe, neueste zuerst, ohne progress (group_id Pflicht, limit ≤ 100, Standard 20)
GET /api/v1/conference-manager/refresh-runs/{id} conference:read Ein Lauf mit progress je Edition
POST /api/v1/conference-manager/refresh-runs/{id}/cancel conference:write Abbruch anfordern
POST /api/v1/conference-manager/refresh-runs/{id}/resume conference:write Abgebrochenen oder fehlgeschlagenen Lauf fortsetzen → 202

Start: Body {"group_id": 1, "conference_ids": [12, 13], "include_past_months": 3}. Ohne conference_ids nimmt der Lauf alle Editionen der Gruppe, deren letzter bekannter Termin (exakt oder Fenster) höchstens include_past_months Monate zurückliegt (0–36, Standard 3), plus Editionen ganz ohne Termin. Mit conference_ids genau diese (höchstens 200; sie müssen zur Gruppe gehören, sonst 404). Läuft in der Gruppe schon ein Lauf, kommt 409 mit details.run_id des laufenden Laufs. Die KI arbeitet nie von selbst — jeder Lauf wird manuell gestartet.

Lebenszyklus: queued → running → done | failed | cancelled. Die Editionen werden nacheinander bearbeitet (Websuche, Seiten lesen, LLM-Abgleich mit dem Bestand). Nur Werte, die die KI als bestätigt mit Quelle findet, überschreiben bestätigte Termine; Schätzungen füllen nur leere Fenster. Bei der Serie ARR legt der Lauf fehlende Zyklen (mit bestätigter Einreichungsfrist) als neue Editionen an.

Lauf-Objekt:

{
  "id": 7, "group_id": 1, "scope": "all", "conference_ids": [12, 13],
  "status": "running", "is_active": true, "started_by": "alice",
  "model_id": "Global/Mistral/Mistral-Small-3.2-24B-Instruct-2506",
  "started_at": "2026-10-02T09:15:00", "finished_at": null, "cancel_requested": false,
  "summary": { "total": 2, "done": 1, "changed": 1, "no_change": 0, "errors": 0 },
  "open_conference_ids": [],
  "progress": {
    "12": {
      "status": "done", "step": "…", "acronym": "EMNLP", "year": 2027, "name": "…",
      "sources": ["https://2027.emnlp.org/calls/main_conference_papers/"],
      "changes": [
        { "field": "submission_deadline", "old": null, "new": "2027-05-19T23:59:00",
          "confidence": "confirmed", "source_url": "https://2027.emnlp.org/…",
          "evidence": "Paper submission deadline: May 19, 2027" }
      ],
      "error": null, "started_at": "…", "finished_at": "…", "updated_at": "…"
    },
    "13": { "status": "searching", "step": "…", "sources": [], "changes": [], "error": null }
  }
}

progress[...].status je Edition: queued, searching, reading, analyzing, done (mit Änderungen), no_change, error, skipped. Ein API-Client fragt GET /refresh-runs/{id} alle paar Sekunden ab, bis is_active false ist (die Oberfläche bekommt dieselben Schritte live per Socket.IO).

Abbruch: setzt cancel_requested; der Lauf endet nach der Edition, an der er gerade arbeitet, und übrige Editionen werden skipped. Ein bereits beendeter Lauf bleibt unverändert, die Antwort ist dann sein Endzustand.

Fortsetzen: Ein Lauf kann auch ohne Abbruch enden, etwa wenn der Server bei einem Deploy oder Neustart den Prozess beendet; er steht dann auf failed (summary.error z. B. "Worker beendet"). open_conference_ids listet bei failed und cancelled die Editionen, die noch offen sind: mit Fehler (error) oder übersprungen (skipped), aber nicht gelöscht. Bei allen anderen Status ist die Liste leer. POST /refresh-runs/{id}/resume startet über genau diese Editionen einen neuen Lauf mit demselben scope und antwortet mit 202 und {"success": true, "run": {…}}. Der alte Lauf bleibt als Verlauf unverändert. Ist der Lauf nicht failed oder cancelled oder läuft in der Gruppe schon ein Lauf, kommt 409; ist nichts mehr offen, 400. Fremde Läufe ergeben 404 und ein Viewer bekommt 403.

Beispiele

export LLARS=https://llars.example.org
export K=llars_…   # persönlicher Key mit conference:write

# Eigene Forschungsgruppen
curl -s -H "X-API-Key: $K" "$LLARS/api/v1/conference-manager/research-groups"

# Serie anlegen
curl -s -X POST -H "X-API-Key: $K" -H "Content-Type: application/json" \
  -d '{"group_id":1,"name":"Empirical Methods in NLP","acronym":"EMNLP","core_ranking":"A*"}' \
  "$LLARS/api/v1/conference-manager/series"

# Geschätzte Edition (nur Zeitfenster)
curl -s -X POST -H "X-API-Key: $K" -H "Content-Type: application/json" \
  -d '{
    "group_id": 1, "series_id": 3, "name": "EMNLP 2027", "acronym": "EMNLP", "year": 2027,
    "submission_window_start": "2027-05-10", "submission_window_end": "2027-05-25",
    "notification_window_start": "2027-08-15", "notification_window_end": "2027-08-31",
    "conference_window_start": "2027-10-25", "conference_window_end": "2027-11-15",
    "estimation_basis": "abgeleitet aus 2023-2026", "estimation_confidence": "medium"
  }' \
  "$LLARS/api/v1/conference-manager/conferences"

# Termin steht fest: exakten Wert setzen (Fenster bleibt als Historie)
curl -s -X PATCH -H "X-API-Key: $K" -H "Content-Type: application/json" \
  -d '{"submission_deadline":"2027-05-19T23:59:00"}' \
  "$LLARS/api/v1/conference-manager/conferences/12"

# Alle noch geschätzten Editionen ab Januar 2027
curl -s -H "X-API-Key: $K" \
  "$LLARS/api/v1/conference-manager/conferences?group_id=1&estimated=true&from=2027-01-01"

# Paper mit DOI, arXiv und Autoren
curl -s -X POST -H "X-API-Key: $K" -H "Content-Type: application/json" \
  -d '{
    "group_id": 1, "title": "Our Paper", "status": "published", "conference_id": 12,
    "doi": "doi:10.18653/v1/2024.acl-long.1", "arxiv_url": "arXiv:2401.12345",
    "authors": [{"username": "alice", "is_corresponding": true}, {"external_name": "Jane Doe"}]
  }' \
  "$LLARS/api/v1/conference-manager/papers"

# Einreichung anhängen
curl -s -X POST -H "X-API-Key: $K" -H "Content-Type: application/json" \
  -d '{"conference_id":12,"status":"submitted","submitted_at":"2027-05-19T20:00:00"}' \
  "$LLARS/api/v1/conference-manager/papers/5/submissions"

# KI-Aktualisierung starten, beobachten, abbrechen
curl -s -X POST -H "X-API-Key: $K" -H "Content-Type: application/json" \
  -d '{"group_id":1}' "$LLARS/api/v1/conference-manager/conferences/refresh"
curl -s -H "X-API-Key: $K" "$LLARS/api/v1/conference-manager/refresh-runs/7"
curl -s -X POST -H "X-API-Key: $K" "$LLARS/api/v1/conference-manager/refresh-runs/7/cancel"
# … und später die offenen Editionen in einem neuen Lauf fortsetzen
curl -s -X POST -H "X-API-Key: $K" "$LLARS/api/v1/conference-manager/refresh-runs/7/resume"

Sicherheit / Hardening

  • IDOR-Maskierung (M1): Objekte fremder Gruppen antworten mit 404, nicht 403 — keine ID-Existenz-Lecks. Querverweise (series_id, conference_id) dürfen die Gruppe nicht verlassen.
  • Scope ∧ Recht: Ein Key wirkt nur, solange sein Konto das Feature-Recht hat.
  • Strikte Schemas: unbekannte Felder, ungültige Daten und Nicht-http(s)-Links sind ein 400 statt still verworfen.
  • Mengen-Grenzen: keywords ≤ 50, authors ≤ 50, conference_ids ≤ 200, limit ≤ 200.
  • Konflikte (Duplikate, laufender KI-Lauf) sind 409 statt 500.

Nicht enthalten

  • Forschungsgruppen und Mitgliedschaften anlegen oder ändern (nur in der Oberfläche)
  • Datensätze zwischen Gruppen verschieben
  • KI-Läufe löschen oder automatisch planen (die KI läuft nur auf Anforderung)