Files
Kontrollverlust/notes/api.md
T
irrlichtandClaude Opus 5.5 2714fdb1a5 Datenbank von SQLite auf Postgres umgestellt
Verbindung über KVER_DSN; Tabelle user heißt jetzt account (reserviertes
Wort in Postgres). kver import-sqlite übernimmt die alte Datei einmalig in
einer Transaktion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiXsPUqw7oeomZ8wZrQW5q
2026-09-26 22:22:07 +02:00

4.4 KiB
Raw Blame History

kver API Definition

Abgeleitet aus dem bestehenden Flask-Code. Basis für die Go-Reimplementierung.


Authentifizierung

Sessions werden als Cookie (session) übertragen. Alle geschützten Endpunkte erwarten diesen Cookie.


Auth

POST /auth/login

Einloggen.

Request (form-encoded):

Feld Typ Beschreibung
user string Nutzername
pass string Passwort
timeout int Session-Dauer in Sekunden

Response:

  • 200 + setzt session-Cookie → Redirect auf /
  • 200 + Fehlertext bei falschen Credentials

GET /auth/login

Login-Seite anzeigen (wird in der Go-API nicht benötigt, Frontend übernimmt das).


POST /auth/newuser

Neuen Account registrieren.

Request (form-encoded):

Feld Typ Beschreibung
user string Nutzername (3–32 Zeichen, [a-zA-Z0-9._\s-])
pass1 string Passwort (min. 10 Zeichen)
pass2 string Passwort-Bestätigung

Response:

  • 200 bei Erfolg
  • 200 + Fehlerliste bei Validierungsfehler

POST /auth/logout

Session beenden und Cookie löschen. POST statt GET: SameSite=Lax schützt GET-Navigationen nicht, ein fremder Link könnte Nutzer sonst ausloggen (CSRF).

Response: 200 {"status": "ok"}


GET /auth/headerbar

Gibt zurück ob der Nutzer eingeloggt ist (für die UI-Headerleiste).

Response: HTML-Partial (in Go-API: JSON)


GET /auth/sessioninfo

Infos zur aktuellen Session.

Auth: erforderlich

Response:

{
  "uid": 123456,
  "created_at": 1700000000,
  "expires": 1700086400,
  "description": ""
}

Entries (Beiträge)

GET /entry/feed/:page

Paginierter Feed aller Beiträge, neueste zuerst.

Parameter:

Name Typ Beschreibung
page int Seite (0–100), 20 Einträge pro Seite

Response:

[
  {
    "pid": 123456789,
    "created_at": 1700000000,
    "uid": 42,
    "content": "...",
    "filepath": "static/media/...",
    "username": "max"
  }
]

Leeres Array [] wenn keine weiteren Einträge vorhanden.


POST /entry/create

Neuen Beitrag erstellen.

Auth: erforderlich

Request (multipart/form-data):

Feld Typ Beschreibung
content string Text (max. 1000 Zeichen)
file file (optional) Bild (JPG oder GIF, wird auf max. 1024px skaliert)

Mindestens content oder file muss vorhanden sein.

Response:

  • 201 bei Erfolg
  • 400 bei leerem Beitrag
  • 401 wenn nicht eingeloggt

GET /entry/:pid/votes

Abstimmungsstand eines Beitrags lesen (read-only).

Response:

{ "pid": 123, "left": 4, "right": 2, "selected": "left" }

selected ist none, wenn nicht eingeloggt oder keine Stimme abgegeben.


POST /entry/:pid/vote

Eigene Stimme abgeben oder umschalten.

Auth: erforderlich

Request (form-encoded):

Feld Typ Beschreibung
mode string left oder right

Voting-Logik:

  • keine bisherige Stimme → neue Stimme
  • gleiche Stimme erneut → Stimme zurückziehen (Toggle)
  • andere Stimme → auf neuen Modus wechseln

Response: wie GET /entry/:pid/votes (aktualisierter Stand)

  • 400 bei ungültigem Modus
  • 401 ohne Login

User

GET /u/:username

Öffentliche Profilseite eines Nutzers.

Response: Nutzerprofil + Beiträge (Details noch offen)


GET /user/info

Eigene Account-Informationen.

Auth: erforderlich

Response:

{
  "uid": 42,
  "username": "max",
  "created_at": 1700000000
}

POST /user/delete

Eigenen Account dauerhaft löschen. Beiträge, Votes und Sessions werden mitgelöscht, zugehörige Mediendateien best effort entfernt.

Auth: erforderlich

Request (form-encoded):

Feld Typ Beschreibung
pass1 string Passwort zur Bestätigung

Response:

  • 200 {"status": "deleted"} + löscht den session-Cookie
  • 403 bei falschem Passwort

Datenbankschema

Postgres; maßgeblich ist die Konstante schema in db.go.


Offene Punkte

  • Kein Rate-Limiting außer dem zufälligen sleep beim Login
  • session-Token ist nur randbelow(999999999) + timestamp — sollte auf crypto/rand umgestellt werden
  • Fehler-Responses sind aktuell Plaintext/HTML — in der Go-API einheitlich JSON