ClaudeandClaude Opus 5.5 8205f7c37f fix(card): fehlendes Logo bricht nur ab, wenn die Vorlage es zeichnet; Download aus „Meine Karten“ meldet es
Entscheidung des Controllers zu Task 5: Ein fehlendes Community-Logo ist beim Rendern einer gespeicherten Karte nur dann ein
Problem, wenn die Vorlage es zeichnet (layoutFor(template).logo). Bei „Nur Bild“ wird ein Logo nie gezeichnet, dort fehlt
nichts. Der Editor-Hinweis (Auswahlzustand) und der Download im Editor bleiben unverändert.

- community/publish.ts: neue gemeinsame Prüfung assertLogoAvailable(config, assets); sie wirft LOGO_MISSING_PUBLISH, wenn
  assets.logoMissing gilt und die Vorlage das Logo zeichnet (minimal, classic, signature). renderForGallery nutzt sie: bei
  einer zeichnenden Vorlage Abbruch vor dem Rendern (nichts hochgeladen), bei „Nur Bild“ wird normal gerendert und
  veröffentlicht.
- pages/cards-page.ts: der Download einer gespeicherten Karte ruft dieselbe Prüfung. Statt stillschweigend ohne Logo
  herunterzuladen, zeigt die Kachel den Text LOGO_MISSING_PUBLISH über den vorhandenen Fehlermechanismus (run() und
  failureText() schreiben in .card-msg), übersetzt mit t(); es wird nichts exportiert oder gespeichert. Bei „Nur Bild“ läuft
  der Download normal.
- Tests: publish.test.ts (classic/minimal/signature mit fehlendem Logo brechen ab, „Nur Bild“ veröffentlicht normal,
  Wahrheitstabelle für assertLogoAvailable) und cards-page.test.ts (Download mit fehlendem Logo: Meldung, kein Download;
  „Nur Bild“ und vorhandenes Logo: Download wie sonst; zweiter Versuch; Englisch). Vitest 45 Dateien, 1338 Tests grün, tsc
  und Build sauber.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 20:38:23 +00:00

AirCard-IOS

Inoffizielles Hobbyprojekt, mit dem man eigene Kartenmotive für Apple Wallet unter https://aircard-ios.org gestalten kann. Bilder hochladen, Vorlage und Netzwerk-Logo wählen, herunterladen – oder mit Konto speichern. Keine Verbindung zu Apple, Visa, Mastercard, UnionPay, American Express, JCB oder Discover.

Aufbau

web/ – Vite + TypeScript ohne Framework. Frontend-Module in src/:

  • card/ – Geometrie, Zuschnitt, Canvas-Rendering (keine DOM-Abhängigkeiten, einzeln testbar)
  • editor/ – UI (Vorlagen, Vorschau, Download, Speichern)
  • account/ – Appwrite-Client, Auth, Kartenverwaltung
  • pages/ – Routen (/, /karten, /passwort-neu via History-API)

deploy/ – Webhook-Router (Port 8087), Build-Skript (deploy.sh), nginx-Config, Traefik-Route für Appwrite.

docs/ – Spec, Plan, Appwrite-Konfiguration.

Lokal entwickeln

cd web
npm ci
npm run dev          # Entwicklungsserver http://localhost:5173

Login und Speichern brauchen die Appwrite-API. Ohne Einstellung gilt als Endpoint ${location.origin}/v1 (der Entwicklungsserver hat keinen Proxy dafür, es würde also der Vite-Server selbst gefragt). Für die lokale Entwicklung deshalb in web/.env.local (steht über .env* in .gitignore) den Endpoint setzen:

VITE_APPWRITE_ENDPOINT=https://appwrite.webklar.com/v1

Die Projekt-ID ist als Standard im Code hinterlegt (6ac2130a00289343d6d5, VITE_APPWRITE_PROJECT_ID überschreibt sie). Damit Appwrite den lokalen Host akzeptiert, muss die Web-Plattform localhost in der Appwrite-Console eingetragen sein (Projekt → Overview → Integrations → Platforms). Der Produktions-Build bekommt VITE_APPWRITE_ENDPOINT=https://aircard-ios.org/v1 aus der Container-Umgebung (deploy/compose-snippet.yml).

Tests

Im Frontend (web/):

cd web
npx vitest run               # Unit-Tests (card/*, editor/*, account/*, pages/*)
npx tsc --noEmit             # TypeScript-Prüfung

Im Repo-Wurzelverzeichnis:

node --test deploy/webhook-server.test.js        # Webhook-Server (deploy.sh wird dort durch einen Stub ersetzt)
node --test deploy/deploy.test.js                # deploy.sh (echtes Skript, lokaler git-Remote, npm-Stub)
node --test web/scripts/appwrite-setup.test.mjs  # Appwrite-Schema-Skript

Deploy

Automatisch: Push auf main → Gitea-Webhook → Container webklar-aircard-build führt npm ci und vite build aus → Ergebnis nach out/ → nginx webklar-aircard liefert.

Manuell:

docker exec webklar-aircard-build sh /deploy.sh

Starten nur mit:

docker compose up -d aircard-build aircard aircard-api

aircard-api ist der kleine API-Dienst der Community-Galerie (deploy/api/, Route aircard-ios.org/api, siehe deploy/api/README.md).

Die Appwrite-API wird über /home/webklar/apps/traefik/dynamic/aircard.yml geroutet (Vorlage: deploy/traefik/aircard.yml): Requests auf aircard-ios.org/v1 mit Header X-Appwrite-Project: 6ac2130a00289343d6d5 gehen an den Appwrite-Container. Ohne diesen Header antwortet der nginx der Seite mit 404.

Appwrite

Projekt „AirCard“ auf appwrite.webklar.com:

  • Projekt-ID (öffentlich, von Appwrite generiert): 6ac2130a00289343d6d5. Sie steht in deploy/traefik/aircard.yml, in /home/webklar/apps/.env (AIRCARD_APPWRITE_PROJECT_ID) und als Standard in web/src/account/appwrite.ts.
  • Datenbank: aircard, Tabelle: cards, Bucket: card-images (das Skript unten legt sie an und prüft sie)
  • Console-Einstellungen laut docs/appwrite-console.md (Soll-Stand, nicht maschinell geprüft; --check prüft nur das Schema): Auth mit E-Mail + Passwort, Sitzungsdauer 30 Tage, max. 5 Sitzungen pro Nutzer, Nutzerlimit 2000, Web-Plattformen aircard-ios.org und localhost. Schritte 3 und 4 dort (Auth-Härtung, Dienste abschalten) sind optional und am Live-Projekt unbestätigt.

Schema prüfen:

node --env-file=/home/webklar/apps/.env web/scripts/appwrite-setup.mjs --check

Schema erstmalig anlegen:

node --env-file=/home/webklar/apps/.env web/scripts/appwrite-setup.mjs

Umgebungsvariablen (in /home/webklar/apps/.env):

  • AIRCARD_APPWRITE_PROJECT_ID – Projekt-ID (idempotent im Skript lesbar)
  • AIRCARD_APPWRITE_API_KEY – API-Key aircard-provision (nur für Setup)

Hinweis

Inoffizielles Hobbyprojekt. Alle Marken gehören ihren Inhabern.

S
Description
No description provided
Readme
1.9 MiB
0 Stars 1 Watchers 0 Forks
Languages
TypeScript 74.9%
JavaScript 21.8%
CSS 2.8%
Shell 0.4%
HTML 0.1%