docs: Community-Logos, Englisch und Reihenfolge Schema → API → Seite nachgetragen
Schlussreview F8. Die Dokumentation kannte die Community-Logos, die Herzen, die zweite Sprache und den GitHub-Link noch nicht. - README.md: Einleitung ohne „Netzwerk-Logo“, neuer Abschnitt „Funktionen“ (Editor, Community-Logos mit Herzen und Moderation, Galerie, Deutsch/Englisch mit GitHub-Link), Modulübersicht um logos/, community/, i18n/ und shell/ ergänzt und die Routen vervollständigt, Tabellen und Buckets (cards, gallery, reports, logos, logo_likes, logo_reports; card-images, gallery-images, logo-images), Testbefehle (API-Tests, Build mit tsconfig.build.json), Hinweis auf die Reihenfolge beim Einführen. - docs/appwrite-console.md: Schema-Liste (oben, Schritt 5, Abschnitt 7 und 8) mit den Tabellen und dem Bucket der Logos, das Label `admin` gilt auch für die Logos, die Scopes des Keys `aircard-api` genügen für die Logo-Endpunkte. - deploy/README.md: neuer Abschnitt „Reihenfolge bei Änderungen an Schema, API und Seite“: 1. Schema (--check, anlegen, noch einmal prüfen), 2. API (fünf Dateien, Neustart, Prüfung: POST /api/logos/herz ohne JWT ergibt 401 mit code unauthorized, 404 hieße alte API), 3. erst dann main pushen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7fec92c20a
commit
d85cce0bf3
3 files changed
+43
-14
No files matched your search
@@ -1,14 +1,25 @@
|
||||
# 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.
|
||||
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
|
||||
- `pages/` – Routen (`/`, `/karten`, `/passwort-neu` via History-API)
|
||||
- `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.
|
||||
|
||||
@@ -36,8 +47,9 @@ Im Frontend (`web/`):
|
||||
|
||||
```sh
|
||||
cd web
|
||||
npx vitest run # Unit-Tests (card/*, editor/*, account/*, pages/*)
|
||||
npx tsc --noEmit # TypeScript-Prüfung
|
||||
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:
|
||||
@@ -45,12 +57,15 @@ 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 `vite build` aus → Ergebnis nach `out/` → nginx `webklar-aircard` liefert.
|
||||
**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
|
||||
@@ -62,7 +77,7 @@ 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`).
|
||||
`aircard-api` ist der kleine API-Dienst der Community-Galerie und der Community-Logos (`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.
|
||||
|
||||
@@ -70,7 +85,7 @@ Die Appwrite-API wird über `/home/webklar/apps/traefik/dynamic/aircard.yml` ger
|
||||
|
||||
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)
|
||||
- Datenbank: `aircard`; Tabellen: `cards` (private Karten), `gallery` und `reports` (Community-Galerie, Meldungen), `logos`, `logo_likes` und `logo_reports` (Community-Logos, Herzen, Meldungen); 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:**
|
||||
|
||||
+15
-1
@@ -60,10 +60,24 @@ Kleiner Node-Dienst ohne Abhängigkeiten (`deploy/api/`), Container `webklar-air
|
||||
- **Route**: Traefik-Label am Dienst, Router `aircard-gallery-api` (``Host(`aircard-ios.org`) && PathPrefix(`/api`)``, Priorität 200, Port 8088). Der Name ist absichtlich nicht `aircard-api`: so heißt schon die Appwrite-Route (`/v1`) in `traefik/dynamic/aircard.yml`.
|
||||
- **Prüfen** nach dem Start: `curl -s https://aircard-ios.org/api/gesundheit` liefert `{"ok":true}`; `docker logs webklar-aircard-api` zeigt `listening on :8088`. Läuft der Dienst nicht, fehlt auch sein Traefik-Router: nginx antwortet dann auf `/api/*` mit `503` und `{"error":"Der Dienst ist gerade nicht erreichbar."}` (Content-Type `application/json`), nie mit der App.
|
||||
- **Ändern**: Dateien mit `cp` nach `aircard-ios.org/api/` ersetzen (alle fünf: `appwrite.js`, `common.js`, `app.js`, `logos.js`, `server.js`; `app.js` lädt `common.js` und `logos.js`, ohne sie startet der Dienst nicht), dann `cd /home/webklar/apps && docker compose restart aircard-api`. Nach einer Änderung der `.env` (Key, Salz) reicht `restart` nicht: `docker compose up -d aircard-api`.
|
||||
- **Logos brauchen das Schema**: Die Logo-Endpunkte schreiben in die Tabellen `logos`, `logo_likes`, `logo_reports` und den Bucket `logo-images`. Das Schema-Skript `web/scripts/appwrite-setup.mjs` legt sie an (zuerst mit `--check` ansehen, was fehlt, siehe [../README.md](../README.md)); das gehört vor den Neustart des API-Dienstes mit den neuen Dateien. Ohne die Tabellen antworten die Logo-Endpunkte mit `500` „Interner Fehler.“, die Karten-Endpunkte laufen weiter.
|
||||
- **Logos brauchen das Schema**: Die Logo-Endpunkte schreiben in die Tabellen `logos`, `logo_likes`, `logo_reports` und den Bucket `logo-images`. Das Schema-Skript `web/scripts/appwrite-setup.mjs` legt sie an (zuerst mit `--check` ansehen, was fehlt, siehe [../README.md](../README.md)); das gehört vor den Neustart des API-Dienstes mit den neuen Dateien. Ohne die Tabellen antworten die Logo-Endpunkte mit `500` „Interner Fehler.“, die Karten-Endpunkte laufen weiter. Die ganze Reihenfolge steht im nächsten Abschnitt.
|
||||
- **Log-Grenze**: Der Docker-Daemon des Servers hat keine eigenen Log-Optionen, deshalb steht im Service `logging: json-file` mit `max-size: 5m` und `max-file: 2` (höchstens 10 MB). Der Dienst selbst schreibt kein Zugriffsprotokoll und höchstens 120 Zeilen pro Minute.
|
||||
- **Kein Port nach außen**: der Dienst vertraut dem Header `X-Real-Ip` (setzt Traefik) für Rate-Limit und Melder-Hash, deshalb nie `ports:` ergänzen. Im Docker-Netz `webklar-network` erreichen ihn andere Container trotzdem und könnten `X-Real-Ip` setzen: akzeptiertes Risiko, siehe [api/README.md](api/README.md) (Client-IP). Vor einem AAAA-Eintrag für aircard-ios.org die Client-IP-Ermittlung prüfen.
|
||||
|
||||
## Reihenfolge bei Änderungen an Schema, API und Seite
|
||||
|
||||
Bringt eine Änderung neue Tabellen, neue Endpunkte und eine Seite mit, die beides braucht (wie die Community-Logos), gilt immer diese Reihenfolge. Die Seite geht zuletzt live: sonst ruft sie Endpunkte auf, die es noch nicht gibt, und ein Push von `main` baut sie sofort.
|
||||
|
||||
1. **Schema**: `node --env-file=/home/webklar/apps/.env web/scripts/appwrite-setup.mjs --check` zeigt, was fehlt (`FEHLT: …`). Ohne `--check` legt das Skript es an. Danach noch einmal mit `--check`: die Ausgabe muss mit `OK: Schema vollständig` enden (Exit-Code 0). Für die Logos sind das die Tabellen `logos`, `logo_likes`, `logo_reports` und der Bucket `logo-images`.
|
||||
2. **API**: alle fünf Dateien (`appwrite.js`, `common.js`, `app.js`, `logos.js`, `server.js`) mit `cp` nach `aircard-ios.org/api/` kopieren, dann `cd /home/webklar/apps && docker compose restart aircard-api`. `docker logs webklar-aircard-api` zeigt `listening on :8088`. Prüfen, dass die Logo-Endpunkte da sind: ein `POST` auf `/api/logos/herz` ohne JWT muss mit `401` und `"code":"unauthorized"` antworten (der Header `Content-Type: application/json` gehört dazu, sonst kommt `415`):
|
||||
|
||||
```sh
|
||||
curl -s -i -X POST -H 'Content-Type: application/json' -d '{}' https://aircard-ios.org/api/logos/herz
|
||||
```
|
||||
|
||||
Antwortet er mit `404`, läuft noch die alte API (Dateien oder Neustart prüfen). Das Schema prüft dieser Aufruf nicht, denn die Anmeldung kommt vor jedem Zugriff auf Appwrite: dafür ist Schritt 1 da.
|
||||
3. **Seite**: erst jetzt `main` pushen (Gitea-Webhook, siehe unten). Der Build führt `npm ci` und `npm run build` aus: Typprüfung ohne Testdateien (`web/tsconfig.build.json`), dann `vite build`.
|
||||
|
||||
## Manuell deployen
|
||||
|
||||
```sh
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Klickliste für Kenso. Dauer: etwa 5 Minuten. Console: <https://appwrite.webklar.com/console>
|
||||
|
||||
Alles passiert in der bestehenden Organisation. Das Schema (Datenbank, Tabellen `cards`, `gallery`, `reports` mit Spalten und Indizes, Buckets `card-images` und `gallery-images`) legt danach das Skript `web/scripts/appwrite-setup.mjs` an – dafür musst du nichts anklicken.
|
||||
Alles passiert in der bestehenden Organisation. Das Schema (Datenbank, Tabellen `cards`, `gallery`, `reports`, `logos`, `logo_likes` und `logo_reports` mit Spalten und Indizes, Buckets `card-images`, `gallery-images` und `logo-images`) legt danach das Skript `web/scripts/appwrite-setup.mjs` an – dafür musst du nichts anklicken.
|
||||
|
||||
**Hinweis:** Das Projekt wurde mit der automatisch generierten ID `6ac2130a00289343d6d5` angelegt (nicht mit einer selbst gewählten ID). Diese ID steht in `/home/webklar/apps/.env` unter `AIRCARD_APPWRITE_PROJECT_ID`; das Skript liest sie von dort, der Wert muss beim Aufruf verfügbar sein.
|
||||
|
||||
@@ -58,7 +58,7 @@ Dieser Key gehört nur dem Setup-Skript. Die Website selbst braucht ihn nicht.
|
||||
4. **Create** klicken.
|
||||
5. Auf der Seite des neuen Keys den **Secret**-Wert kopieren (Auge-Symbol zum Einblenden, dann kopieren).
|
||||
|
||||
Die Indizes der Tabellen `gallery` und `reports` legt das Skript mit denselben Scopes an; ein eigener Index-Scope ist nicht nötig.
|
||||
Die Indizes der Tabellen `gallery`, `reports`, `logos`, `logo_likes` und `logo_reports` legt das Skript mit denselben Scopes an; ein eigener Index-Scope ist nicht nötig.
|
||||
|
||||
## 6. Key auf dem Server eintragen
|
||||
|
||||
@@ -77,7 +77,7 @@ Der Key gehört in die Datei `/home/webklar/apps/.env`, nirgendwo sonst.
|
||||
|
||||
## 7. Community
|
||||
|
||||
Für die Community-Galerie (Tabellen `gallery` und `reports`, Bucket `gallery-images`, API-Dienst `aircard-api`) sind drei Dinge in der Console nötig. Das Schema dazu legt dasselbe Skript an (`node --env-file=/home/webklar/apps/.env web/scripts/appwrite-setup.mjs`, vorher mit `--check` ansehen, was fehlt).
|
||||
Für die Community-Galerie und die Community-Logos (Tabellen `gallery`, `reports`, `logos`, `logo_likes` und `logo_reports`, Buckets `gallery-images` und `logo-images`, API-Dienst `aircard-api`) sind drei Dinge in der Console nötig. Das Schema dazu legt dasselbe Skript an (`node --env-file=/home/webklar/apps/.env web/scripts/appwrite-setup.mjs`, vorher mit `--check` ansehen, was fehlt).
|
||||
|
||||
### 7.1 JWT muss an sein
|
||||
|
||||
@@ -85,7 +85,7 @@ JWT muss **an** sein – falls in Schritt 3 ausgeschaltet, wieder einschalten. A
|
||||
|
||||
### 7.2 Label `admin` am eigenen Konto
|
||||
|
||||
Das Label `admin` macht dich zum Admin der Galerie: Die Website zeigt dir dann Ein-/Ausblenden-Knöpfe und den Galerie-Filter „Gemeldet“/„Ausgeblendet“.
|
||||
Das Label `admin` macht dich zum Admin der Galerie und der Community-Logos: Die Website zeigt dir dann Ein-/Ausblenden-Knöpfe und die Filter „Gemeldet“/„Ausgeblendet“ (in der Galerie und im Logo-Bereich des Editors).
|
||||
|
||||
1. Linke Leiste → **Auth** → **Users** → dein Konto öffnen.
|
||||
2. Bei **Labels** den Wert `admin` eintragen → **Update**.
|
||||
@@ -100,7 +100,7 @@ Dieser Key gehört nur dem API-Dienst `aircard-api`, nicht dem Setup-Skript und
|
||||
- `documents.read` und `documents.write`
|
||||
- `files.read` und `files.write`
|
||||
|
||||
Die Console beschriftet die Zeilen-Scopes mit `documents.*`; das sind dieselben wie die `rows.read`/`rows.write` der Appwrite-API (Tabellen heißen dort Zeilen). Einen Eintrag `rows.*` gibt es in der Console nicht.
|
||||
Die Console beschriftet die Zeilen-Scopes mit `documents.*`; das sind dieselben wie die `rows.read`/`rows.write` der Appwrite-API (Tabellen heißen dort Zeilen). Einen Eintrag `rows.*` gibt es in der Console nicht. Dieselben vier Scopes genügen für die Logo-Endpunkte (Tabellen `logos`, `logo_likes`, `logo_reports`, Bucket `logo-images`).
|
||||
4. **Create** klicken und auf der Seite des Keys den **Secret**-Wert kopieren.
|
||||
5. Auf dem Server den Wert verdeckt in die `.env` schreiben. Der Befehl fragt den Wert ohne Anzeige ab (`read -rs`), schreibt bei leerer Eingabe nichts, beginnt mit einem Zeilenumbruch (so klebt die Zeile nie an einer letzten Zeile ohne Umbruch) und zeigt den Key nirgends an:
|
||||
|
||||
@@ -112,4 +112,4 @@ Dieser Key gehört nur dem API-Dienst `aircard-api`, nicht dem Setup-Skript und
|
||||
|
||||
## 8. Bescheid geben
|
||||
|
||||
Schreib Claude „Console fertig“. Danach legt Claude Datenbank `aircard`, die Tabellen `cards`, `gallery`, `reports` (mit Spalten und Indizes) und die Buckets `card-images`, `gallery-images` mit dem Skript an und prüft sie. Für die Community-Galerie schreib zusätzlich „Label und Key sind gesetzt“.
|
||||
Schreib Claude „Console fertig“. Danach legt Claude Datenbank `aircard`, die Tabellen `cards`, `gallery`, `reports`, `logos`, `logo_likes`, `logo_reports` (mit Spalten und Indizes) und die Buckets `card-images`, `gallery-images`, `logo-images` mit dem Skript an und prüft sie. Für die Community-Galerie schreib zusätzlich „Label und Key sind gesetzt“.
|
||||
Reference in new issue
Block a user