GET /entry/{pid}/interactions/{mode} now reads the vote tally and, for
mode=left/right (auth required), toggles the user's vote: new vote, repeat
same mode removes it, different mode switches. Returns {left, right,
selected}. A UNIQUE(uid, pid) constraint on the vote table prevents
duplicate votes. The JS frontend renders Links/Rechts buttons with live
counts under each entry.
This completes the voting feature that was left commented-out and broken
in the Flask version.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
5.1 KiB
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+ setztsession-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:
200bei Erfolg200+ Fehlerliste bei Validierungsfehler
GET /auth/logout
Session beenden und Cookie löschen.
Response: Redirect auf /
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:
201bei Erfolg400bei leerem Beitrag401wenn nicht eingeloggt
GET /entry/:pid/interactions/:mode
Abstimmungsstand lesen und optional die eigene Stimme umschalten.
Parameter:
| Name | Typ | Beschreibung |
|---|---|---|
pid |
int | Post-ID |
mode |
string | none (nur lesen), left oder right (abstimmen) |
Voting-Logik (nur bei left/right, Auth erforderlich):
- keine bisherige Stimme → neue Stimme
- gleiche Stimme erneut → Stimme zurückziehen (Toggle)
- andere Stimme → auf neuen Modus wechseln
Response:
{ "pid": 123, "left": 4, "right": 2, "selected": "left" }
selected ist none, wenn nicht eingeloggt oder keine Stimme abgegeben.
Bei left/right ohne Login → 401.
Hinweis: Mutation per GET ist aus dem ursprünglichen HTMX-Design übernommen. Sauberer wäre ein separater
POSTfürs Abstimmen — siehe offene Punkte.
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 densession-Cookie403bei falschem Passwort
Datenbankschema (SQLite)
CREATE TABLE user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
uid INTEGER UNIQUE,
username TEXT UNIQUE,
password BLOB,
created_at INTEGER,
last_login INTEGER
);
CREATE TABLE session (
id INTEGER PRIMARY KEY AUTOINCREMENT,
uid INTEGER,
value TEXT UNIQUE,
created_at INTEGER,
expires INTEGER,
description TEXT
);
CREATE TABLE entry (
id INTEGER PRIMARY KEY AUTOINCREMENT,
pid INTEGER UNIQUE,
uid INTEGER,
created_at INTEGER,
content TEXT,
filepath TEXT
);
CREATE TABLE vote (
id INTEGER PRIMARY KEY AUTOINCREMENT,
uid INTEGER,
pid INTEGER,
mode TEXT -- 'left' | 'right'
);
Offene Punkte
- Voting läuft per GET (HTMX-Erbe) — perspektivisch auf
POSTumstellen (CSRF/Idempotenz) - Kein Rate-Limiting außer dem zufälligen
sleepbeim Login session-Token ist nurrandbelow(999999999) + timestamp— sollte aufcrypto/randumgestellt werden- Fehler-Responses sind aktuell Plaintext/HTML — in der Go-API einheitlich JSON