Rewrite backend in Go with JSON API and JS frontend
Reimplements the Flask app as a Go HTTP API (chi + modernc sqlite) with a minimal vanilla-JS frontend in web/. Endpoints mirror the original Flask routes but return JSON instead of HTML. - auth: login/logout/register/sessioninfo/headerbar with crypto/rand tokens - entry: paginated feed (single JOIN), create with image scaling - user: profile, userinfo; delete still a stub - requireAuth middleware passes uid via context - notes/api.md documents the API and schema Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+229
@@ -0,0 +1,229 @@
|
||||
# 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
|
||||
|
||||
---
|
||||
|
||||
### `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:**
|
||||
```json
|
||||
{
|
||||
"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:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"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/interactions/:mode`
|
||||
|
||||
Abstimmung auf einen Beitrag. (*Aktuell nicht implementiert.*)
|
||||
|
||||
**Parameter:**
|
||||
| Name | Typ | Beschreibung |
|
||||
|------|-----|--------------|
|
||||
| `pid` | int | Post-ID |
|
||||
| `mode` | string | `left` oder `right` |
|
||||
|
||||
---
|
||||
|
||||
## User
|
||||
|
||||
### `GET /u/:username`
|
||||
|
||||
Öffentliche Profilseite eines Nutzers.
|
||||
|
||||
**Response:** Nutzerprofil + Beiträge (Details noch offen)
|
||||
|
||||
---
|
||||
|
||||
### `GET /user/info`
|
||||
|
||||
Eigene Account-Informationen.
|
||||
|
||||
**Auth:** erforderlich
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"uid": 42,
|
||||
"username": "max",
|
||||
"created_at": 1700000000
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `GET /user/delete`
|
||||
|
||||
Account löschen. (*Noch nicht implementiert.*)
|
||||
|
||||
---
|
||||
|
||||
## Datenbankschema (SQLite)
|
||||
|
||||
```sql
|
||||
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
|
||||
|
||||
- `/entry/:pid/interactions/:mode` ist auskommentiert — Voting-Logik muss neu designed werden
|
||||
- `/user/delete` ist noch ein Stub
|
||||
- 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
|
||||
Reference in New Issue
Block a user