Detailseite /community/<id>: große Karte, Titel, Herausgeber, „von …“, Datum,
Tags, Herunterladen (aircard-<slug>.png), „Als Vorlage gestalten“ und Melden-Dialog
(fünf Gründe, Dank-, Doppelt- und Drosselungs-Text). Autor: Zurückziehen; Admin:
Ausblenden/Einblenden, Löschen, Meldungszahl und Gründe. Fehlende oder
ausgeblendete Karten zeigen Besuchern „nicht (mehr) verfügbar“, Autor und Admin
sehen sie mit dem Hinweis „Ausgeblendet“.
Editor: /gestalten?vorlage=<id> übernimmt das Galerie-Vollbild als „Nur Bild“,
setzt saved, savedConfig und cardName zurück, ersetzt die Adresse durch /gestalten
und fragt vorher bei ungespeicherter Arbeit.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Startseite "/" mit kompaktem Hero (grosse schwebende Karte rechts: neueste
sichtbare Community-Karte, sonst das eigene Beispielmotiv hero-beispiel.png)
und direkt darunter der Galerie #community, damit Ueberschrift und Oberkante der
ersten Kartenreihe bei 1440x900 und 390x844 im ersten Bildschirm stehen.
- mountHomePage(root, deps): Suche ?q= und Tag ?tag= aus der Adresse (aktiver
Begriff mit "x"), Suchfeld der Kopfzeile per .value gefuellt, Mehr laden per
Cursor, Leer-/Kein-Treffer-/Fehlertexte, Admin-Filter Alle/Gemeldet/
Ausgeblendet (reagiert auf Anmelden/Abmelden), Anker nach dem Laden erneut
angesprungen (router.scrollToHash exportiert), Object-URLs beim Verlassen frei.
- mountGalleryGrid: Kacheln mit Vorschau (Object-URL, max. 6 parallel), Titel,
Herausgeber, bis 3 Tag-Knoepfe (Tag-Klick -> /?tag=<tag>#community), Link auf
/community/<id>; Moderations-Marken nur in den Admin-Ansichten.
- Hero hoechstens 60vh auf breiten, hohen Fenstern; Schwebe-Animation nur ohne
prefers-reduced-motion.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- publish.ts: bei Fehlern der API werden die hochgeladenen Dateien nur bei eindeutiger Ablehnung
(4xx außer 408/429, JWT-Fehler vor der Anfrage) gelöscht; bei offenem Ausgang (Netzfehler,
Zeitlimit, 5xx, 429, Antwort ohne id) bleiben sie liegen, damit keine öffentliche Zeile auf
gelöschte Bilder zeigt
- api.ts: ApiError.definitive und isDefinitiveFailure, Zeitlimit 15 s, gleichzeitige createJWT
werden geteilt
- gallery.ts: Tag-Filter (contains auf tags), Kurzsuche unter 3 Zeichen per contains,
loadGalleryImage prüft die Datei-ID
- geometry.ts: PREVIEW_WIDTH/PREVIEW_QUALITY an einer Stelle (Editor und Veröffentlichen)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- gallery.ts: Galerie aus Appwrite lesen (Abfragen für Liste, Suche, Cursor, Admin-Filter),
getGalleryCard (404 und ungültige ID ergeben null), eigene Veröffentlichungen, Meldungen, Bilder
- api.ts: Aufrufe von aircard-api mit JWT (Cache je Nutzer, 10 Minuten, geleert bei Auth-Änderung,
genau eine Wiederholung bei 401), ApiError mit code, Netz-/Proxy-Fehler als 503
- publish.ts: rendern, zwei Uploads in gallery-images, API; bei Fehler genau die zwei Dateien
dieses Versuchs löschen; normalizeTags
- cards.ts: eigenständiges fetchFile(bucketId, fileId); CardsApi.fetchFile bleibt Hülle
- appwrite.ts: IDS für gallery, reports, gallery-images
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Setup-Skript um Tabellen gallery und reports (Spalten boolean/integer/enum,
Volltext- und Key-Indizes) sowie den Bucket gallery-images erweitert.
DESIRED auf tables/buckets umgebaut, Vergleich je Spaltentyp und Index,
Indizes erst nach available-Spalten. Console-Anleitung um Abschnitt
Community (JWT an, Label admin, Key aircard-api) ergänzt.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- Router: Routen home, gestalten, cards, community/<id>, reset; Umleitung
/?karte=<id> nach /gestalten?karte=<id>; Titel je Route (titleFor);
Hash-Ziele (/#community) scrollen den Anker ins Bild, nur-Hash-Wechsel
bauen die Seite nicht neu auf.
- Kopfzeile: Navigation, Suche (Enter -> /?q=...#community), Spenden-Knopf,
Hell/Dunkel-Schalter, Menue unter 900 px, Konto als Avatar-Kreis mit Menue.
- Theme: data-theme auf <html> (Skript im <head> gegen Aufblitzen), helle
Tokens, danger-/warn-/ok-text-Tokens statt fester Farben.
- Spenden-Banner (schliessbar); ohne DONATE_URL bleiben Banner und Knopf weg.
- User.labels und isAdmin; Platzhalter fuer Startseite und Detailseite.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Die Maske hatte exakt die Kartenkante als Region und als weißes Feld; die
Kantenglättung wurde doppelt angewendet und ließ bei Vergrößerung einen
hellen Strich. Jetzt Standardregion der Maske und ein überstehendes weißes Feld.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Vorschau: Tastenkürzel mit Strg/Cmd/Alt gehören dem Browser (Seitenzoom).
- decodeImage lehnt Bilder über 40 Megapixel nach dem Laden, vor dem
Dekodieren ab (Meldung "Das Bild ist zu groß (max. 40 Megapixel).").
- Test, dass das Umbenennen-Feld den Namen markiert (tat der Code schon).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Endpoint-Standard ${origin}/v1, echte Projekt-ID im Traefik-Header, Console-
Einstellungen als Soll-Stand statt Tatsache, Test-Befehle je mit Verzeichnis;
Projekt-ID nicht mehr "aircard", Auth-/Dienste-Schritte als optionale Härtung.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Gäste/abgelaufene Sitzung: Appwrite antwortet mit 404; withLogin und
openSavedCard melden dann an (Dialog, einmal wiederholen) statt
„nicht gefunden“ zu zeigen.
- Öffnen einer Karte fragt vor dem Verwerfen eines ungespeicherten Entwurfs
nach; ein fehlgeschlagenes Öffnen setzt einen gefüllten Editor nicht zurück.
- Update ohne Bildwechsel schickt kein imageFileId mehr (veralteter Stand
zeigte sonst auf eine gelöschte Datei).
- Uploads werden nur nach eindeutiger Ablehnung (4xx ohne 408/429) gelöscht,
nicht bei Netzfehler, 5xx oder 429.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Editor: Seitenspalten geben nach (minmax), die Vorschau bleibt ab 1024 px
mindestens 360 px breit, einspaltig erst unter 1024 px. Router: navigate()
springt nach dem Rendern nach oben, Dokumenttitel je Route.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Name AirCard-IOS in Kopfzeile, Titel, Meta-Angaben (theme-color,
apple-mobile-web-app-title) und README
- Website-Icon: neues Logo als favicon.svg, favicon-32.png und deckendes
apple-touch-icon.png (180 x 180, ohne Rundung)
- Kopfzeile zeigt das Logo (28 px, auf schmalen Schirmen 24 px) vor dem Namen
- Karten-Marken neu aus dem Logo abgeleitet (einfarbig, currentColor):
Symbol mit drei gestaffelten Karten und ausgeschnittenen Wellen,
Text als Pfade (Nunito Sans 800); IDs unverändert
- Tests: Labels, Marken-Aufbau, Favicon, Icon-Dateien, index.html
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- Editor zeigt „Bearbeitet: <Name>“, solange eine gespeicherte Karte gebunden ist,
und bietet „Neue Karte“ (setzt zurück, bricht Laden ab, entfernt ?karte=;
fragt bei ungespeicherten Änderungen per eigenem Dialog „Verwerfen?“)
- EditorState.savedConfig als Vergleichsbasis für ungespeicherte Änderungen
- bindEditorToAuth: Abmelden leert den Editor, Kontowechsel A -> B entkoppelt die
Karte (Entwurf bleibt), Anmelden ohne Vorgänger und abgelaufene Sitzung behalten
den Entwurf; auth.onLogout unterscheidet eigenes Abmelden von bemerktem Ablauf
- Speichern nimmt den Schnappschuss pro Klick (auch für die Wiederholung nach 401)
- save: row_not_found beim Update legt eine neue Karte an (inkl. Aufräumen)
- Karten-Seite: Editor-Abgleich auch nach dem Verlassen der Seite, Löschen-Dialog
wird beim Verlassen geschlossen, keine doppelten Vorschau-URLs
- confirm-dialog als gemeinsames Modul (Löschen, Verwerfen)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- account/cards.ts: Kartendienst (neu/bestehend speichern mit Aufräumen halber
Uploads, Umbenennen, Löschen, Laden) über ein schmales CardsApi-Interface,
Appwrite-Anschluss mit 22.4.1-Objektparametern, fetchFile über
client.prepareRequest (Projekt-Header + Cookie, kein getFileView)
- account/with-login.ts: bei 401 Nutzer neu prüfen, einmal anmelden, wiederholen
- editor/save.ts: Speichern-Ablauf (ein Lauf zur Zeit, 401 -> Login -> einmal
wiederholen, deutsche Fehlermeldung)
- Editor: Speichern mit Schnappschuss und 480-px-Vorschau, Karte öffnen über
?karte=<id>, Bildwechsel während des Speicherns gesperrt
- pages/cards-page.ts: /karten mit Kacheln, Öffnen, Herunterladen, Umbenennen,
Löschen (eigener Dialog), Abmelde- und Leer-Ansicht
- Tests für Dienst, withLogin, Speichern-Ablauf, Karten-Seite und Editor-Anbindung
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- login(): bei user_session_already_exists aktuelle Sitzung beenden und genau
einmal neu versuchen; Meldung für den Restfall in errorMessage
- requireLogin(): schlägt showModal fehl, wird aufgeräumt und der Fehler geworfen,
damit spätere Aufrufe nicht an einem toten Promise hängen
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- appwrite 22.4.1 (exakt gepinnt); Client mit Endpoint aus VITE_APPWRITE_ENDPOINT
bzw. location.origin + /v1, Projekt aus VITE_APPWRITE_PROJECT_ID bzw. aircard
- auth.ts: getCurrentUser (401 -> null, ungültige Antwort -> Fehler), login, register,
logout, Passwort-Link anfordern/abschließen, onAuthChange, validatePassword
- errors.ts: deutsche Meldungen nach type, dann code (Tabelle aus dem Plan)
- Login-Dialog (Anmelden/Registrieren/Passwort vergessen) als gemeinsames <dialog>,
Konto-Menü im Seitenkopf, Seite /passwort-neu
- Tests: errors, auth, Dialog, Passwort-neu-Seite
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
web/scripts/appwrite-setup.mjs legt Datenbank aircard, Tabelle cards
(4 Spalten) und Bucket card-images idempotent per fetch an, wartet auf
Spalten-Status available und meldet Abweichungen, ohne sie zu ändern
(--check: nichts anlegen, Exit 1 bei Fehlendem/Abweichendem).
docs/appwrite-console.md ist die Klickliste für Projekt, Plattformen,
Auth, Dienste und API-Key. Tests laufen mit node --test gegen einen
Fake-Appwrite; Vitest nimmt nur src/**/*.test.ts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Store, Upload-Prüfung/Dekodierung und Download-Dateiname mit Tests; drei Spalten
(Vorlagen mit Live-Miniatur, Vorschau mit Ziehen/Zoom, Optionen), einspaltig unter 900 px.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
renderCard zeichnet in 1536 x 969 in fester Reihenfolge (Grund, Bild mit
begrenztem Ausschnitt, Chip, Kontaktlos, Nummer, PLATINUM, Logo, Netzwerk),
drawCard skaliert auf beliebige Canvas ohne Alpha, loadCardAssets wartet
auf Schrift und Logos, exportCard liefert PNG/WebP als Blob.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
loadMarkImage: Cache je (id, tone), eingefärbter Blob mit eigener Größe,
Freigabe der Blob-URL bei load und error, erneuter Versuch nach Fehler.
Neuer Test: jedes url(#...) zeigt auf eine id derselben SVG-Datei.
amex-outline: Rahmen nach außen verschoben, berührt "A" und "S" nicht mehr.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
18 Netzwerk-Logos, AirCards-Symbol/-Text und Apple als bereinigte SVGs
(Wikimedia Commons, gemeinfrei; abgeleitete Varianten selbst gebaut),
Register marks.ts mit Einfärben (currentColor) und Bild-Lader sowie
festfarbiges Favicon.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vite + TypeScript ohne UI-Framework in web/, exakte Versionen, History-Router
(matchRoute, navigate, startRouter mit Cleanup, a[data-link], popstate),
Grundlayout mit Kopfzeile, Fußzeile und Platzhalterseiten.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>