Files
irrlicht c4a0c5c378 Datenschutz + Notes: Reichweitenmessung dokumentieren
Punkt 5 beschreibt die anonyme Reichweitenmessung inkl. ASN-Einordnung;
durchgaengig "anonymisierte IP-Adresse" und expliziter Hinweis, dass auch
fuer die ASN-Bestimmung nie die volle IP verwendet wird. IPv6-
Anonymisierung auf /32 (letzte 96 Bit) korrigiert.

Notes: Migration der asn-Spalte (ALTER TABLE) und neue Env-Var
KVER_GEOIP_ASN samt GeoLite2-Bereitstellung.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 23:21:17 +02:00

121 lines
4.1 KiB
Markdown

# Datenbank-Migrationen
Manuelle Schritte, die beim Deploy gegen eine **bestehende** Datenbank nötig sind.
Eine frische DB (Schema aus `db.go`) braucht keine davon.
---
## `avatar`-Spalte in `user`
**Wann:** beim Deploy der Profilbild-Version gegen eine bestehende `kver.db`.
**Hintergrund:** Profilbilder werden als Pfad (`static/media/...`) in der neuen Spalte
`user.avatar` gespeichert (leerer String = kein Bild, Frontend zeigt dann das
Platzhalterbild). `CREATE TABLE IF NOT EXISTS` ergänzt die Spalte bei einer
vorhandenen Tabelle nicht.
**Migration:**
```sql
ALTER TABLE user ADD COLUMN avatar TEXT NOT NULL DEFAULT '';
```
Bestehende Nutzer haben damit kein Bild (`''`). Nur einmalig ausführen.
---
## `filepath` NULL → leerer String
**Wann:** beim Umstieg auf die Go-Version, falls `entry.filepath` NULL-Werte enthält.
**Hintergrund:** `scanEntries` scannt `filepath` in ein Go-`string`-Feld (kein Pointer).
SQLite NULL in ein `string` scannen schlägt fehl; `scanEntries` überspringt diese Zeilen
still mit `continue`. Ergebnis: Einträge ohne Bild fehlen im Feed komplett.
Das aktuelle Go-Schema definiert `filepath TEXT NOT NULL DEFAULT ''`. `migrate.sh`
normalisiert NULL → `''` beim Kopieren aus der Quelldatenbank.
```sql
UPDATE entry SET filepath = '' WHERE filepath IS NULL;
```
---
## `filepath`-Sentinel `"none"` → leerer String
**Wann:** beim Umstieg auf die Go-Version, falls eine alte `kver.db` aus der
Python-Zeit weiterverwendet wird.
**Hintergrund:** Die Python-Version schrieb für Beiträge ohne Bild den
String `"none"` in `entry.filepath`. Die Go-Version nutzt stattdessen den
leeren String (Go-Zero-Value) und prüft nur noch auf `filepath == ""`.
Alte `"none"`-Zeilen würden sonst im Feed als Bildpfad interpretiert
(`<img src="/none">` → kaputtes Bild).
**Migration:**
```sql
UPDATE entry SET filepath = '' WHERE filepath = 'none';
```
Idempotent — kann gefahrlos mehrfach laufen.
---
## Threading-Spalten in `entry`
**Wann:** beim Deploy der Threading-Version gegen eine bestehende `kver.db`, die
die Tabelle `entry` noch ohne die Threading-Spalten hat.
**Hintergrund:** Das Threading führt `reply_to` (pid des Eltern-Posts, `0` = Root),
`reply_count` (Anzahl Antworten im gesamten Teilbaum) und `last_activity`
(Sortierschlüssel des Hauptfeeds) ein. `CREATE TABLE IF NOT EXISTS` ergänzt diese
Spalten bei einer vorhandenen Tabelle nicht.
**Migration:**
```sql
ALTER TABLE entry ADD COLUMN reply_to INTEGER NOT NULL DEFAULT 0;
ALTER TABLE entry ADD COLUMN reply_count INTEGER NOT NULL DEFAULT 0;
ALTER TABLE entry ADD COLUMN last_activity INTEGER;
UPDATE entry SET last_activity = created_at WHERE last_activity IS NULL;
```
Bestehende Zeilen werden so zu Root-Beiträgen (`reply_to = 0`, `reply_count = 0`)
mit `last_activity = created_at`. Nicht idempotent — die `ALTER TABLE`-Zeilen nur
einmalig ausführen.
---
## Soft-Delete-Spalte in `entry`
**Wann:** beim Deploy der Soft-Delete-Version gegen eine bestehende `kver.db`.
**Hintergrund:** Statt Beiträge hart zu löschen werden sie als `[deleted]`-Platzhalter
markiert (`deleted = 1`, Inhalt/Bild/Autor geleert), damit Antworten nicht verwaisen.
Das Frontend und die Feeds erkennen gelöschte Beiträge an dieser Spalte.
**Migration:**
```sql
ALTER TABLE entry ADD COLUMN deleted INTEGER NOT NULL DEFAULT 0;
```
Bestehende Beiträge bleiben damit sichtbar (`deleted = 0`). Nur einmalig ausführen.
---
## `asn`-Spalte in `impression`
**Wann:** beim Deploy der ASN-Auswertung gegen eine bestehende `impression`-Tabelle.
**Hintergrund:** Pro Impression wird das autonome System (Netzbetreiber) gespeichert,
aufgelöst aus der vollen Client-IP *vor* dem Maskieren (siehe `lookupASN`). Die Spalte
liegt bewusst **nicht** im Primärschlüssel — pro `anon_ip` ist das ASN deterministisch,
also entstehen keine Zeilen-Duplikate, und ein simples `ADD COLUMN` genügt (kein
Tabellen-Rebuild). `CREATE TABLE IF NOT EXISTS` ergänzt die Spalte bei einer
vorhandenen Tabelle nicht.
**Migration:**
```sql
ALTER TABLE impression ADD COLUMN asn TEXT NOT NULL DEFAULT '';
```
Bestehende Zeilen haben damit kein ASN (`''`, in der Auswertung „(unbekannt)"). Nur
einmalig ausführen.