39 Commits

Author SHA1 Message Date
irrlicht 13363cb568 Mailadresse aktualisiert 2026-07-01 10:08:34 +02:00
irrlicht e4389de288 Image from clipboard also in replies 2026-06-29 00:16:58 +02:00
irrlicht aa0def2949 Sigils added to rule page 2026-06-28 19:57:52 +02:00
irrlicht ba0d0d62f2 Metaline in deleted posts 2026-06-24 10:24:26 +02:00
irrlicht 32c70ad0f8 New Meta-Line 2026-06-24 10:21:40 +02:00
irrlicht 112e1f82ca Metaline styling 2026-06-24 09:46:10 +02:00
irrlicht 308eec734f Buttons neu sortiert 2026-06-24 09:34:00 +02:00
irrlicht 01be0c523e Repost 2026-06-22 11:40:27 +02:00
irrlicht c30399e498 Fixed /stats layout 2026-06-19 22:49:01 +02:00
irrlicht 4d99074bd5 Header aktualisiert 2026-06-17 23:58:54 +02:00
irrlicht 8be8ecedc9 Statistik-Seite: Kennzahlen, Reichweite, ASN und Verlaeufe
Neue Seite /stats.html: Basiszahlen, Reichweite, Netze nach Betreiber
(ASN), Aufrufe pro Tag und beliebteste Seiten. Diagramme als CSS-Balken
(Breite per CSSOM, kein Inline-style) statt Chart-Library -- bleibt
CSP-konform. Verlinkt in der Legal-Nav aller Seiten.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 23:21:17 +02:00
irrlicht bbd4bc27ba Compose: Button "Posten" -> "Eintrag erstellen"
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 14:23:09 +02:00
irrlicht def6a13782 Compose: Bild aus Zwischenablage per Strg+V einfügen
paste-Listener am Formular übernimmt ein Clipboard-Bild in den File-Input
(via DataTransfer), benennt es zu zwischenablage.<ext> und zeigt einen
grauen Hinweis über dem Datei-Input. Kein Bild -> normaler Text-Paste.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 14:22:14 +02:00
irrlicht e7a7ef8d20 Tagline: Body-Textgröße, schwarz, enger an den Titel
font-size auf 1rem, Farbe schwarz, margin 0 (entfernt den 0.2rem-Abstand
zum Titel; verbleibender Mini-Abstand stammt aus dem h1-Margin).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 08:48:40 +02:00
irrlicht d9028a8400 Header: Statuszeile "Ohne Datenverlust seit n Tagen" + Kennzahlen zurückholen
Schlanke Wiederbelebung des alten Uptime-Schriftzugs aus der Python-Version,
jetzt als kleine Zeile direkt unter dem Titel: Tage seit fixem Startpunkt
(13.12.2025, Kontinuität) plus aktuelle Profil- und Beitragszahlen.

- /stats: neuer öffentlicher Endpunkt (COUNT user / COUNT entry WHERE deleted=0)
- app.js: renderStats() rechnet die Tage und füllt #stats per textContent
- index.html: <p id="stats" class="tagline"> unter der h1
- app.css: kleine graue .tagline-Zeile

Kein Inline-JS/CSS -> strikte CSP bleibt unangetastet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 08:46:05 +02:00
irrlicht 0089bc5909 feed.js: HTML-Injection in linkify schließen (escapeHtml deckt nun Quotes ab)
escapeHtml nutzte den textContent->innerHTML-Trick, der laut HTML-Spec nur
& < > escaped, aber keine Anführungszeichen (in Textknoten harmlos). linkify
steckt den Wert anschließend in ein href="..."-Attribut, wo ein rohes " das
Attribut vorzeitig schließt und beliebige Attribute (on...=, style=) am <a>
einschleusbar macht -- HTML-Injection. Die CSP (default-src 'self', kein
'unsafe-inline') verhinderte nur die Ausführung, nicht die Injektion.

Ersetzt durch einen spec-korrekten Entity-Escaper, der auch " und ' abdeckt,
sodass der Wert in Text- UND Attributkontext sicher ist.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 07:52:18 +02:00
irrlicht 85c283404d Legal-Docs: Header an Hauptseite angleichen, app.css statt main.css
- Header-Markup wie web/index.html (nav#legal + zentrierte h1), gleiche
  Schrift/Beton-Hintergrund, weil jetzt dasselbe /css/app.css geladen wird
- Inhalt in <main><div class="doc"> -> weiße Spalte mit 5px Padding
- verwaiste static/css/{main.css,main.scss,normalize.css} entfernt (wurden
  nur von den Docs referenziert)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 21:18:50 +02:00
irrlicht 642fe9466a security.txt (RFC 9116) + aktualisierte Rechtsdokumente
- security.txt unter /.well-known/ mit Contact, Expires, Canonical (kver.xyz)
- Impressum + Beitragsordnung aus aktueller Prod übernommen (sauberes HTML
  ohne Jinja/htmx/jQuery-Reste, § 5 DDG statt TMG)
- fehlende normalize.css ergänzt (wurde von allen Docs referenziert -> 404)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 21:05:32 +02:00
irrlicht ad2c08d93a Thread-Layout: Strich als Flex-Geschwister, mittig unter dem Avatar
Strich neben dem Content wird über ein eigenes Flex-Element mit
align-self: stretch gezeichnet statt über eine Border am Content –
dadurch exakt so hoch wie der Inhalt, kein Über-/Unterstehen mehr.
Vorfahren und Antworten teilen denselben Mechanismus (Antworten ohne
Border). Strichposition und -dicke über CSS-Variablen an die halbe
Avatargröße gekoppelt, sodass die Linie mittig unter dem Byline-Avatar
sitzt. Antworten-Label in die Byline verschoben, vertikaler Abstand
unter den .body-Container.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 06:49:56 +02:00
irrlicht 15ef7db5f7 Profilbilder: Avatar-Upload, Anzeige auf Profil & Feed
- user.avatar-Spalte (Schema, migrate.sh, Migrationsdoku)
- POST /user/avatar (geschützt): Upload via storeImage, ersetzt/löscht altes Bild
- avatar in /u/{name}/info, /user/info und im entrySelect-Join (Feed-Karten)
- Account-Löschung entfernt auch das Avatar-File
- Frontend: Avatar im Profilkopf + Byline der Karten (50px), Upload-Form,
  Platzhalterbild no_profile_pic.jpg als Fallback
- .card img per :not(.avatar) von Beitragsbildern getrennt

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 18:20:14 +02:00
irrlicht cad1fa5c5c Infinite Scroll: nachladen, bis Sentinel aus dem Viewport wandert
Der IntersectionObserver feuert nur bei Zustandswechseln. Füllte die erste
Feed-Seite den Viewport nicht über den Sentinel hinaus (Hauptfeed mit 198
Roots), kam es nie zu einem Übergang und damit nie zum Nachladen. loadMore
prüft jetzt nach jedem Fetch, ob der Sentinel noch sichtbar ist, und lädt
aktiv weiter; rootMargin 300px lädt zudem vorausschauend.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 18:05:24 +02:00
irrlicht 466049ee9d User-Page: Profil & Posts in einem weißen Container
Profilname, "Mitglied seit", Einstellungen und Feed liegen jetzt in einer
gemeinsamen weißen section statt als getrennte Kästen mit Textur-Lücken.
"Beiträge"-Überschrift entfernt (samt JS-Logik für Deine/Beiträge von …).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 17:32:08 +02:00
irrlicht b4d03f8741 Frontend: Kommentarbereich, Ladezeit & Interaktionsleiste
- "Antworten"-Überschrift entfernt; direkte Antworten sind eine flache Liste
- Thread-Strich nur noch bei der Ahnenkette (#ancestors), Antworten nur eingerückt
- font-display: swap + korrekte format()-Hinweise -> kein FOIT mehr beim Laden
- Interaktionsleiste als Grid: Vote-Buttons zentriert, "n Antworten" links daneben

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 17:21:28 +02:00
irrlicht 5478e92253 Migration, Schema-NOT-NULL & klickbare Karten
migrate.sh erzeugt nicht-destruktiv eine frische kver.db aus original-kver.db
mit dem aktuellen Go-Schema (NULL/'none'-filepath normalisiert, Soft-Deletes
und Waisen verworfen). Das entry-Schema erzwingt jetzt NOT NULL DEFAULT '' auf
content/filepath – NULL-filepath ließ scanEntries Zeilen still überspringen.
Feed-Karten sind per Klick navigierbar (mit Hover-Highlight); DB-Artefakte
landen im .gitignore.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 17:07:05 +02:00
irrlicht 720d5d64d5 Header: Doku-Links, Profil-Button & Titel "Kontrollverlust"
Impressum/Datenschutz/Beitragsordnung als Links ueber der Ueberschrift,
Ueberschrift in "Kontrollverlust" umbenannt (verlinkt auf den Feed),
"mein Profil" und "zurueck zum Feed" im Button-Layout. datenschutz.html
aus bb6b966 wiederhergestellt, damit der Link nicht ins Leere fuehrt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 10:23:41 +02:00
irrlicht 2160920595 Design: Textur, EB-Garamond/Cheltenham-Fonts & Designsprache aus Python-Branch
Concrete-Textur als Hintergrund, EB Garamond als Fließtext und Cheltenham
Classic für die Überschriften, weiße zentrierte Inhaltsspalte, umrandete
Buttons und Threadline-Optik fuer Ahnen/Antworten -- uebernommen aus der
verwaisten Python-Linie bb6b966.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 10:23:41 +02:00
irrlicht ad469ab366 Bearbeiten: POST /entry/{pid}/edit (Inhalt ändern)
- handleEditEntry: Eigentümerprüfung, nicht-leer, content-only Update
- Bild und last_activity bleiben unverändert; gelöschte Posts nicht editierbar
- Frontend: Bearbeiten-Button + Inline-Formular auf der Focus-Seite

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 13:33:22 +02:00
irrlicht cb3da3bb24 Soft-Delete: Beiträge als [deleted] erhalten statt löschen
- entry.deleted; entrySelect LEFT JOIN + COALESCE(username)
- POST /entry/{pid}/delete: deleted=1, Inhalt/Bild/Autor geleert, Zeile bleibt
- Konto-Löschung soft-deletet die eigenen Beiträge (statt hartem DELETE),
  damit fremde Antworten nicht verwaisen
- Frontend: [deleted]-Platzhalter im Feed, Löschen-Button auf Focus-Seite
- notes/migrations.md: ALTER TABLE deleted

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 13:21:42 +02:00
irrlicht ba085eff4e Threading: Antworten (reply_to) + Focus-View
- entry: reply_to/reply_count/last_activity; reply_count bubbelt bis Root
- Hauptfeed nur Roots nach last_activity, Profil-Feed inkl. Antworten
- GET /entry/{pid}/thread (Ahnen+Antworten), GET /e/{pid} Focus-Seite
- Frontend: Antworten-Link im Feed, entry.html/entry.js Focus-Seite
- notes/migrations.md: ALTER TABLE fuer Prod

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 12:21:55 +02:00
irrlicht 844bbb44e7 Frontend+API: Namen ändern (POST /user/rename)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 11:47:44 +02:00
irrlicht 7ffc35808a User 2026-06-02 16:35:47 +02:00
irrlicht 2dcba21250 Frontend: roher Oldschool-Look, CSS auf 6 Zeilen
- Dark-Theme, Farbvariablen, Border-Radius, custom Form-Controls und
  Layout-Zentrierung entfernt -> natives Browser-Default-Rendering
- nur noch: 1px-Rahmen um Beitraege (eckig), graue Nebentexte, rote
  Fehler, fett fuer gewaehlte Stimme
- Textarea-Hoehe via rows-Attribut, <details> nativ (Danger-Klasse weg)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 10:47:02 +02:00
irrlicht f442138043 Frontend: CSS auf allgemeine Klassen verschlankt (82 Zeilen)
- ID-Selektoren (#account-info, #delete-form button) und verschachtelte
  Selektoren (.entry .meta, .interactions .vote) entfernt
- wiederverwendbare Klassen: .card, .muted, .row, .ghost
- globale a/h1/h2-Regeln, Farben als CSS-Variablen (--border, --danger)
- HTML/JS synchron umgestellt; counts-Span via querySelector("span")
- Cross-Check: keine toten CSS-Klassen, keine unbekannten Referenzen

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 10:29:40 +02:00
irrlicht d1a269db2f Frontend: Account-Bereich (GET /user/info, POST /user/delete)
- Account-Section nur sichtbar wenn eingeloggt; zeigt Nutzername und
  Mitglied-seit-Datum aus /user/info
- Konto loeschen in aufklappbarer Danger-Zone, Passwortbestaetigung
  plus zusaetzliche confirm()-Rueckfrage (unwiderruflich)
- nach Loeschung zurueck zur Login-Ansicht via refreshHeader

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 11:59:53 +02:00
irrlicht a47f41bbfa Frontend: Registrierung angebunden (POST /auth/newuser)
- Umschalter Login <-> Registrieren im Auth-Bereich
- Fehlerlisten-Anzeige ({"errors": [...]}) fuer newuser
- nach erfolgreicher Registrierung automatischer Login
- Logout setzt Ansicht auf Login zurueck

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 11:47:00 +02:00
irrlicht e210df3e2e Code-Cleanup: toter Check, none-Sentinel, Login-Jitter raus
- entry.go: redundantes stored != "" entfernt
- filepath-Sentinel "none" -> leerer String (Go-Zero-Value),
  Checks in entry.go/user.go und web/js/app.js vereinfacht
- auth.go: zufaelligen Login-Jitter samt loginJitter-Variable und
  Test-Seam entfernt (war nur Spielerei, kein echter Schutz)
- notes/migrations.md: einmalige "none"->"" Migration dokumentiert

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 11:33:41 +02:00
irrlicht 38da498754 Split voting into clean read/write endpoints
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>
2026-06-01 11:03:33 +02:00
irrlicht be8dbb4902 Implement left/right voting on entries
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>
2026-06-01 10:58:58 +02:00
irrlicht cb237c248e 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>
2026-06-01 10:17:02 +02:00