Replaces the GET-mutates-state interactions route with a proper split:
- GET /entry/{pid}/votes reads the tally (public, read-only)
- POST /entry/{pid}/vote casts/toggles the vote (auth, mode in body)
Shared voteTally/writeTally helpers back both handlers. Invalid mode now
returns 400. Frontend updated to read via GET and vote via POST.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.9 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/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)
400bei ungültigem Modus401ohne 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 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
- 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