- Schema: Tabelle `profiles` (Zeilen-ID = Konto-ID, `username` und `usernameKey`
je 20 Zeichen, Unique-Index `username_key` auf `usernameKey`, rowSecurity an,
keine Tabellenrechte) im Setup-Skript.
- Neues Modul `deploy/api/profiles.js`: `POST /api/profil` legt das Profil an
oder ändert es (Zeilenrecht genau read("any"), Sperre je Konto). Muster,
Sperrliste und Schlüssel (`usernameKey`) stehen in `common.js`; vergeben ->
409 `usernameTaken`, auch wenn erst der Unique-Index bei einem Rennen
entscheidet. Dazu die MSG-Texte `usernameInvalid`, `usernameReserved`,
`usernameTaken`, `usernameRequired`.
- `POST /api/logos/hochladen` und `POST /api/veroeffentlichen` antworten 403
`usernameRequired`, wenn das Konto kein Profil hat (`hasProfile`, nach der
Anmeldung und vor allen anderen Prüfungen).
- Fake-Appwrite: Tabelle `profiles` mit Unique-Index (409), `addProfile`,
`holdNext`. API-Dienst besteht jetzt aus sechs Dateien (READMEs).
- Client: die vier API-Texte in `API_MESSAGES` und `en.ts` (Gleichlauf mit MSG).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
108 lines
7.0 KiB
Markdown
108 lines
7.0 KiB
Markdown
# AirCard-IOS
|
||
|
||
Inoffizielles Hobbyprojekt, mit dem man eigene Kartenmotive für Apple Wallet unter https://aircard-ios.org gestalten kann. Bild hochladen, Vorlage und Community-Logo wählen, als PNG herunterladen – oder mit Konto speichern und in der Community-Galerie veröffentlichen. Keine Verbindung zu Apple, Visa, Mastercard, UnionPay, American Express, JCB oder Discover; Logos und Motive stammen von Nutzern, alle Marken gehören ihren Inhabern.
|
||
|
||
## Funktionen
|
||
|
||
- **Editor** (`/gestalten`): Bild hochladen, Vorlage, Ausschnitt, Details (Hell/Dunkel) und das Logo oben links (AirCard-IOS) wählen, als PNG herunterladen oder mit Konto speichern („Meine Karten“, `/karten`).
|
||
- **Community-Logos** unten rechts auf der Karte: Angemeldete laden Logos hoch (PNG, JPG, WebP oder SVG; der Browser schneidet sie zu, verkleinert sie auf höchstens 720 × 250 px und lädt ein PNG hoch), alle können sie wählen. Eingebaute Marken-Logos gibt es nicht. Je Konto und Logo gibt es ein Herz (nur angemeldet); die Herzen bestimmen die Sortierung „Beliebt“. Logos lassen sich melden (ab 3 Meldern aus verschiedenen Netzen werden sie ausgeblendet) und vom Hochlader löschen; Admins (Label `admin`) sehen zusätzlich „Gemeldet“ und „Ausgeblendet“.
|
||
- **Community-Galerie** (Startseite `/` und `/community/<id>`): Karten veröffentlichen, ansehen, melden und zurückziehen.
|
||
- **Deutsch und Englisch**: Die Sprache folgt der Browsersprache; der Sprachknopf in der Kopfzeile schaltet ohne Neuladen um und merkt sich die Wahl. Daneben steht ein GitHub-Link zum Original-Projekt [AirCard-iOS](https://github.com/Mak5er/AirCard-iOS).
|
||
|
||
## 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)
|
||
- `logos/` – Community-Logos: Lesen aus Appwrite, Auswahl mit Herzen und Infozeile (Melden, Löschen, Admin), Hochladen mit Aufbereitung im Browser (Zuschnitt, Verkleinern, PNG)
|
||
- `community/` – Galerie: Lesen, Veröffentlichen, Melden, Aufrufe des API-Dienstes
|
||
- `account/` – Appwrite-Client, Auth, Kartenverwaltung
|
||
- `i18n/` – Deutsch und Englisch: `t('Deutscher Text')` und `msg('…')`, Wörterbuch Deutsch → Englisch in `en.ts` (ein Test verlangt für jeden Text einen Eintrag)
|
||
- `pages/` – Routen (`/`, `/gestalten`, `/karten`, `/community/<id>`, `/passwort-neu` via History-API)
|
||
- `shell/` – Kopfzeile (GitHub-Link, Sprachknopf, Hell/Dunkel), Fußzeile, Spenden-Banner
|
||
|
||
**`deploy/`** – Webhook-Router (Port 8087), Build-Skript (`deploy.sh`), nginx-Config, Traefik-Route für Appwrite.
|
||
|
||
**`docs/`** – Spec, Plan, Appwrite-Konfiguration.
|
||
|
||
## Lokal entwickeln
|
||
|
||
```sh
|
||
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:
|
||
|
||
```sh
|
||
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/`):
|
||
|
||
```sh
|
||
cd web
|
||
npx vitest run # Unit-Tests (alle Module unter src/)
|
||
npx tsc --noEmit # TypeScript-Prüfung, auch der Tests
|
||
npm run build # Produktions-Build; die Prüfung davor nutzt tsconfig.build.json (ohne Tests)
|
||
```
|
||
|
||
Im Repo-Wurzelverzeichnis:
|
||
|
||
```sh
|
||
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 "deploy/api/*.test.js" # API-Dienst (Glob in Anführungszeichen)
|
||
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 `npm run build` (Typprüfung ohne Tests, dann `vite build`) aus → Ergebnis nach `out/` → nginx `webklar-aircard` liefert.
|
||
|
||
**Reihenfolge, wenn eine Änderung auch Schema und API braucht** (wie die Community-Logos): erst das Schema anlegen, dann die API-Dateien ersetzen und neu starten, zuletzt `main` pushen. Die Schritte stehen in [deploy/README.md](deploy/README.md), Abschnitt „Reihenfolge bei Änderungen an Schema, API und Seite“.
|
||
|
||
**Manuell:**
|
||
```sh
|
||
docker exec webklar-aircard-build sh /deploy.sh
|
||
```
|
||
|
||
Starten nur mit:
|
||
```sh
|
||
docker compose up -d aircard-build aircard aircard-api
|
||
```
|
||
|
||
`aircard-api` ist der kleine API-Dienst der Community-Galerie, der Community-Logos und der Benutzernamen (`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`; Tabellen: `cards` (private Karten), `gallery` und `reports` (Community-Galerie, Meldungen), `logos`, `logo_likes` und `logo_reports` (Community-Logos, Herzen, Meldungen) und `profiles` (Benutzernamen, eine Zeile je Konto, Unique-Index auf dem klein geschriebenen Namen); Buckets: `card-images`, `gallery-images` und `logo-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:**
|
||
```sh
|
||
node --env-file=/home/webklar/apps/.env web/scripts/appwrite-setup.mjs --check
|
||
```
|
||
|
||
**Schema erstmalig anlegen:**
|
||
```sh
|
||
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.
|