fix(config): Datenbank-Passwort mit Sonderzeichen bricht den Start

Die Verbindungszeichenkette wurde mit fmt.Sprintf zusammengeklebt. Ein
Passwort mit % und @ ergab eine kaputte URL:

  parse "postgres://aether:8UoNj%CoWJ7ze@qy@localhost:5432/aether":
  invalid URL escape "%Co"

Der Server kam nicht über die Migrationen hinaus. Die key=value-Form hätte
dasselbe Problem mit einem Leerzeichen gehabt, nur stiller.

config.DSN() liefert jetzt eine postgres://-URL, gebaut mit net/url und
net.JoinHostPort (klammert IPv6). pgxpool und golang-migrate nehmen sie
beide unverändert – dsnToURL, splitDSN, indexByte und orDefault in pkg/db
sind ersatzlos entfallen. Test deckt %, @, :, /, Leerzeichen und IPv6 ab.

Dazu: DB_HOST und DB_PORT fehlten in der schlanken .env.example, weshalb
localhost statt postgres gegriffen hat. APP_ENV ergänzt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Opus 5 committed 2026-08-24 11:20:01 +02:00
1 parent 16ab6f385b
commit 35ebf609b7
5 files changed
+153 -71

No files matched your search

+41
View File
@@ -646,6 +646,47 @@ breiteste.
---
## Datenbank-Passwort mit Sonderzeichen (24.08.2026)
Die Verbindungszeichenkette wurde mit `fmt.Sprintf` zusammengeklebt. Beim
ersten Aufbau einer frischen Umgebung fiel das sofort auf:
```
FTL migrations failed
error="parse \"postgres://aether:8UoNj%CoWJ7ze@qy@localhost:5432/aether\":
invalid URL escape \"%Co\""
```
`@` und `:` beenden den Anmeldeteil einer URL, `%` leitet eine Maskierung ein.
Die `key=value`-Form hätte dasselbe Problem mit einem **Leerzeichen** gehabt,
nur stiller: Der Rest dahinter wäre als eigener Schlüssel gelesen worden.
Jetzt baut `net/url` die Adresse, und die Umrechnung von Hand in `pkg/db` ist
ersatzlos weg.
- [ ] `DB_PASSWORD` mit `%`, `@`, `:`, `/` und Leerzeichen → Server startet,
Migrationen laufen, Anmeldung geht 🔎 (gemessen mit `8UoNj%CoWJ7ze@qy`
in einer eigenen Umgebung: `migrations up to date`, `/health` 200,
Login 200)
- [ ] `go test ./pkg/config/...` deckt die Fälle ab, ohne dass eine Datenbank
laufen muss 🔎
- [ ] IPv6 als `DB_HOST` (`::1`) wird geklammert, der Port bleibt erhalten 🔎
> **Keine Regel „welche Zeichen erlaubt sind".** Wer die erst nachschlagen
> muss, wählt am Ende ein schwächeres Passwort.
### Dazu: `DB_HOST` fehlte im schlanken Beispiel
Die `.env.example` im Wurzelverzeichnis führte `DB_NAME`, `DB_USER` und
`DB_PASSWORD`, aber nicht `DB_HOST`. Die Voreinstellung ist `localhost` – und
aus dem Container heraus ist das er selbst. Im Log stand deshalb
`@localhost:5432`, obwohl Postgres als `postgres` im Compose-Netz lief.
- [ ] Frische Umgebung nur aus `docker-compose.example.yml` + `.env.example`
startet ohne Nacharbeit
- [ ] `APP_ENV`, `DB_HOST` und `DB_PORT` stehen darin
---
## Handy: eine Kopfzeile statt zwei (24.08.2026)
Die eigene Leiste über der Kopfzeile („☰ Aether") ist weg. Sie enthielt nur