ki integration
This commit is contained in:
@@ -10,13 +10,13 @@
|
||||
|
||||
| | Stand |
|
||||
|---|---|
|
||||
| **Appwrite-Schema** | 15 Tabellen, Indizes, 4 Buckets, Team `internal` – angelegt durch `scripts/setup-appwrite.mjs`, idempotent |
|
||||
| **Appwrite-Schema** | ✅ **22 Tabellen, Indizes, 5 Buckets, Team `internal`** – live und vollständig, `scripts/setup-appwrite.mjs` reproduziert diesen Stand idempotent (Stand 14.08.2026) |
|
||||
| **Prompts** | P1–P18 als 22 Zeilen geseedet (P8 = Kern + 4 Adapter) via `scripts/seed-prompts.mjs`, versioniert |
|
||||
| **Regeln** | 4 globale Brand-Regeln in `rules` |
|
||||
| **Prototyp** | `prototyp-app.html`, 21 Screens, Handy-Ansicht, vollständig ohne Backend |
|
||||
| **App-Code** | **existiert noch nicht** – es gibt einen Expo-QR-Code, aber keine Anwendung |
|
||||
|
||||
**Der entscheidende Punkt:** Das Schema im Repo bildet den Stand **vor** dem Bild-/Feed-Konzept ab. Es fehlen alle Tabellen des neuen Produktteils. Wer jetzt anfängt, UI zu bauen, baut gegen Tabellen, die es nicht gibt.
|
||||
> **Nachtrag 14.08.2026 – E0 ist erledigt.** Der Abschnitt unten beschreibt den Stand vom 28.07. und ist ab hier **Historie, keine Aufgabenliste mehr**. Die Live-Datenbank war bereits vollständig migriert (alle 7 neuen Tabellen, alle 4 Enum-Erweiterungen, `attributes` aufgetrennt, 5. Bucket) – nur `setup-appwrite.mjs` im Repo hing auf dem alten Stand hinterher und hätte beim Ausführen die Score-Spalten in `attributes` wieder angelegt. Das Skript ist inzwischen auf den Live-Stand gezogen und gegen ihn geprüft: **0 angelegt, 251 existierten schon, 0 Warnungen.** Auch die beiden Enum-Entscheidungen aus §7.1 (Nischen-Liste, `typ_tags`) sind getroffen und stehen als `NISCHEN` und `TYP_TAGS` im Skript.
|
||||
|
||||
---
|
||||
|
||||
@@ -77,20 +77,39 @@ Dazu die aus dem alten Plan noch offenen: `elo-update`, `favorit-berechnen`, `ad
|
||||
|
||||
Jede Etappe hat ein Abnahmekriterium – etwas, das man vorführen kann. Ohne das ist nicht entscheidbar, ob sie fertig ist.
|
||||
|
||||
### E0 · Schema nachziehen
|
||||
**Inhalt:** `setup-appwrite.mjs` um die 7 neuen Tabellen, die geänderten Spalten, die Enum-Erweiterungen und den Bucket ergänzen. `attributes` auftrennen. `P_KEYS` auf 22. Skript einmal komplett gegen eine **leere** Datenbank laufen lassen.
|
||||
**Abnahme:** Skript läuft zweimal hintereinander fehlerfrei durch (idempotent), 22 Tabellen und 5 Buckets stehen in der Appwrite-Konsole.
|
||||
**Aufwand:** klein. Reine Skriptarbeit, kein UI.
|
||||
### E0 · Schema nachziehen ✅ **erledigt (14.08.2026)**
|
||||
**Inhalt:** `setup-appwrite.mjs` um die 7 neuen Tabellen, die geänderten Spalten, die Enum-Erweiterungen und den Bucket ergänzen. `attributes` auftrennen. `P_KEYS` auf 22.
|
||||
**Abnahme erfüllt:** 22 Tabellen und 5 Buckets stehen live; das Skript läuft ohne eine einzige Änderung durch (`0 angelegt, 251 existierten schon, 0 Warnungen`).
|
||||
**Datenbestand:** nur Stammdaten – 4 Zeilen `rules`, 22 Zeilen `prompt_templates` (P1–P18, P8 als Familie). Keine Brand-Daten. **Enum-Änderungen sind ab jetzt trotzdem nicht mehr gefahrlos**, weil `prompt_templates.key` gefüllt ist.
|
||||
|
||||
### E1 · Projektgerüst Expo
|
||||
**Inhalt:** Expo-Projekt anlegen, TypeScript, Navigation (Tabs + Stacks), Appwrite-SDK verdrahten, Theme aus dem Prototyp übernehmen (Farben, Typo, Glas-Effekte – **ohne** die Fake-Tastatur und ohne die Shader-Spielerei per `setInterval`).
|
||||
**Abnahme:** App startet auf Handy und im Browser, drei Tabs sind klickbar, jeder Tab zeigt einen leeren Screen mit seinem Namen.
|
||||
**Aufwand:** mittel. Hier entscheidet sich die Ordnerstruktur des Codes – sorgfältig sein.
|
||||
> **Lehre aus dieser Etappe:** Die Datenbank war der Quelle voraus, nicht umgekehrt. Wer `setup-appwrite.mjs` in diesem Zustand ausgeführt hätte, hätte die sieben Score-Spalten in `attributes` neu angelegt und die Auftrennung halb zurückgedreht – ein idempotentes Skript schützt nur vor doppeltem Anlegen, nicht vor einer veralteten Definition. Deshalb: **nach jeder Schema-Änderung an der Konsole das Skript nachziehen und mit `scripts/check-appwrite.mjs` gegenprüfen.**
|
||||
|
||||
### E2 · Auth und Mandant
|
||||
**Inhalt:** Registrieren, Anmelden, Abmelden. Bei der Registrierung: Appwrite-Team anlegen, `brands`-Zeile anlegen, Zeilenrechte setzen. Session-Persistenz.
|
||||
**Abnahme:** Zwei Konten anlegen; Konto B sieht **keine** Daten von Konto A – geprüft über die API, nicht über das UI.
|
||||
**Aufwand:** mittel. Die Rechte-Prüfung ist der eigentliche Inhalt, nicht die Formulare.
|
||||
### E1 · Projektgerüst Expo ✅ **erledigt im Browser (14.08.2026), nativ ungeprüft**
|
||||
**Inhalt:** Expo-Projekt in `client/`, TypeScript, Expo Router (Stack + Tabs), Appwrite-SDK verdrahtet, Theme aus dem Prototyp. Fake-Tastatur und `setInterval`-Shader sind bewusst nicht übernommen.
|
||||
**Abnahme:** `npx tsc --noEmit` fehlerfrei · `npx expo export --platform web` erzeugt alle drei Routen · im Browser rendern `/`, `/erstellen` und `/profil` mit Tab-Leiste, keine Konsolen-Fehler. **Offen: der Start auf einem echten Gerät** – dafür fehlt ein Testgerät bzw. ein Dev-Build.
|
||||
|
||||
**Struktur (`client/src/`):**
|
||||
|
||||
| Pfad | Inhalt |
|
||||
|---|---|
|
||||
| `app/_layout.tsx` | Wurzel-**Stack**, nicht direkt die Tabs – Willkommen/Anmelden liegen laut app-aufbau.md §3 vor den Tabs, das Onboarding als Modal darüber. Beide brauchen eine Ebene ohne Tab-Leiste. |
|
||||
| `app/(tabs)/` | Feed · Erstellen · Profil |
|
||||
| `lib/appwrite.ts` + `.web.ts` | plattform-getrennter Client. `react-native-appwrite` läuft nicht im Browser, das Web-SDK `appwrite` kennt kein React Native – beide exportieren dieselben Klassen, der Rest der App importiert nur `@/lib/appwrite`. |
|
||||
| `lib/config.ts` | Endpoint, Projekt-ID, DB-ID aus `app.json` → `expo.extra.appwrite`. **Kein Server-Key** – der landet sonst im Bundle. |
|
||||
| `theme/tokens.ts` | Farben, Radien, Abstände aus `prototyp-app.html`. Dark-only, weil der Prototyp kein Light-Theme hat. |
|
||||
|
||||
**Zwei bewusste Abweichungen:** Das ➕ ist vorerst ein normaler Tab statt des Popovers aus §3 – der kommt mit den drei Erstellen-Abläufen in E6. Und der Profil-Screen zeigt provisorisch Endpoint und Projekt-ID, damit belegt ist, dass der Client wirklich lädt; das fliegt in E2 raus.
|
||||
|
||||
### E2 · Auth und Mandant ✅ **erledigt (14.08.2026)**
|
||||
**Inhalt:** Willkommen/Registrieren/Anmelden/Abmelden, Session-Persistenz, bei der Registrierung Team + `brands`-Zeile mit Zeilenrechten.
|
||||
**Abnahme erfüllt:** `scripts/test-mandanten.mjs` legt zwei echte Konten an und prüft **über die API**: B listet nur die eigene Zeile · Direktzugriff B→A `404 row_not_found` · Schreibzugriff B→A `401 user_unauthorized` · Gegenprobe, dass der Server-Key beide Zeilen sieht. Räumt sich selbst auf.
|
||||
|
||||
**Der eigentliche Inhalt war das Rechte-Modell, nicht die Formulare.** Zwei Dinge, die vorher niemandem aufgefallen waren:
|
||||
|
||||
1. **Kein Client konnte irgendetwas anlegen.** Bei `rowSecurity: true` regeln Zeilenrechte lesen/ändern/löschen – aber eine Zeile, die es noch nicht gibt, hat keine Rechte. Ohne Tabellen-Recht zum Anlegen war jede Client-Schreiboperation blockiert. 16 Tabellen haben jetzt `create("users")`; `score_events`, `video_metrics`, `post_metrics` und `usage_records` bewusst **nicht** – sonst könnte ein Nutzer seine eigenen Elo-Werte und Feed-Signale fälschen (§11, „Manipulation des Feed-Scores").
|
||||
2. **`setup-appwrite.mjs` hat Rechte nie abgeglichen.** Bei bestehenden Tabellen lieferte `POST` nur ein 409, die Rechte blieben unangetastet. Das Skript vergleicht jetzt und zieht per `PUT` nach – sonst driftet das Rechte-Modell genauso wie zuvor das Schema.
|
||||
|
||||
**Nebenfund: SDK-Version passte nicht zum Server.** Appwrite läuft in **1.8.1**, `create-expo-app` hatte SDKs mit Response-Format 1.9.5 gezogen. Gepinnt auf `appwrite@23.0.0` und `react-native-appwrite@0.25.0` (beide Response-Format 1.8.0), **exakt statt Caret** – der Sinn der Pinnung ist ja gerade der Gleichstand mit dem Server.
|
||||
|
||||
> Das ist die Etappe, bei der man am ehesten schludert und es am teuersten wird. Die Mandantentrennung ist das Fundament des Rechte-Modells aus `datenbank-aufbau.md` §5.
|
||||
|
||||
@@ -99,20 +118,51 @@ Jede Etappe hat ein Abnahmekriterium – etwas, das man vorführen kann. Ohne da
|
||||
**Abnahme:** Nach dem Onboarding stehen in `brands` sechs ausgefüllte Felder und in `attribute_scores` die ersten Attribute auf der brand-weiten Ebene (`folder_id = null`).
|
||||
**Aufwand:** mittel.
|
||||
|
||||
### E4 · Modelle
|
||||
### E4 · Modelle 🟡 **Kern steht (14.08.2026), Verbessern-Strecke offen**
|
||||
**Inhalt:** Modell anlegen (Person, Produkt, **Kulisse**), echte Referenzbild-Uploads, Versionierung mit Release-Prinzip, Modelle-Übersicht im Profil.
|
||||
**Abnahme:** Ein Produkt-Modell mit 4 Referenzbildern anlegen, freigeben, in der Übersicht sehen. `assets.released_version_id` zeigt auf die richtige Version.
|
||||
**Aufwand:** mittel. Ohne Modelle kann nichts generiert werden – deshalb vor der Generierung.
|
||||
**Erledigt:** Anlegen mit Typwahl und Mehrfach-Bildauswahl (`modell/neu`), Upload nach `asset-references` mit Team-Rechten, Version 1 wird angelegt und sofort freigegeben, `assets.released_version_id` zeigt darauf. Übersicht im Profil nach Typ gruppiert, mit Titelbild aus der freigegebenen Version.
|
||||
**Belegt:** Vier Modelle (2 Produkte, 2 Kulissen) über `scripts/seed-demo.mjs` als **Client** angelegt – das beweist nebenbei, dass die Tabellen- und Bucket-Rechte aus E2 ausreichen. Alle vier Bilder laden in der App in Originalgröße.
|
||||
**Offen:** weitere Versionen anlegen und freigeben (Verbessern-Strecke), `merkmale` als Token-Lock, Einwilligungs-Upload für Personen.
|
||||
|
||||
### E5 · Ordner
|
||||
### E5 · Ordner ✅ **erledigt (14.08.2026)**
|
||||
**Inhalt:** Ordner-Liste, Anlegen mit den zwei Schaltern, Ordner-Detail, aktiver Ordner als App-Zustand. Function `ordner-initialisieren`.
|
||||
**Abnahme:** Zwei Ordner anlegen – einen mit `erben`, einen mit `aus_posts`. In `attribute_scores` stehen danach unterschiedliche Startwerte mit korrekt gesetzter `start_quelle`.
|
||||
**Aufwand:** mittel. Fachlich der anspruchsvollste Teil bis hierher.
|
||||
**Abnahme erfüllt** – nach dem Anlegen über die Oberfläche steht in `attribute_scores`:
|
||||
|
||||
### E6 · Post erstellen (erste echte Generierung)
|
||||
| Ordner | Modus | Scores | `start_quelle` |
|
||||
|---|---|---|---|
|
||||
| (brand-weit, `folder_id = null`) | – | 12 | `neutral` |
|
||||
| Sommerkampagne | `erben` | 12 | `geerbt` |
|
||||
| Cleane Studioshots | `aus_posts` | 0 | – |
|
||||
| Herbstlinie (über die App angelegt) | `erben` | 12 | `geerbt` |
|
||||
|
||||
Zweck und Startwerte sind als Auswahl **mit Erklärung** umgesetzt, nicht als nackter Schalter: wer sie missversteht, baut sich einen Ordner, der nicht tut, was er erwartet.
|
||||
|
||||
**Beim Erben wird der Wert kopiert, aber nicht die Sicherheit** – `k_factor` geht zurück auf 32, weil im neuen Scope noch nichts belegt ist.
|
||||
|
||||
**Abweichung:** `ordner-initialisieren` läuft vorerst im Client statt als Appwrite-Function. Vertretbar, weil nur eigene Zeilen kopiert werden und die Zeilenrechte das ohnehin begrenzen; beim Umzug in eine Function ändert sich nur der Ort.
|
||||
|
||||
### E6 · Post erstellen 🟡 **Rezept-Hälfte steht (14.08.2026), Generierung extern blockiert**
|
||||
**Inhalt:** Create-Screen mit Ordner, Format, Kette, Slots. `jobs` + `job-dispatcher` + Realtime-Wartezustand. P7 auf das Slot-System umbauen. P22 als Bild-Tagger. Post-Ergebnis mit privat/veröffentlichen.
|
||||
**Abnahme:** Ein Prompt erzeugt eine dreiteilige Bilderkette, die im Entwürfe-Screen auftaucht, auch wenn man die App zwischendurch schließt.
|
||||
**Aufwand:** groß. Hier hängt die Auswahl des Bildmodells dran – **offener Punkt 1**.
|
||||
|
||||
**Erledigt:** `erstellen/post` mit Ordnerwahl in der Kopfzeile, Format, Kettenlänge und Slot-Auswahl für Kulisse, Produkt und Person – als Bildkacheln, weil bei Kulissen und Produkten das Aussehen die Information ist und ein Name wie „Halle, Metallwand" nichts darüber sagt, ob es passt. Der Post entsteht **sofort** mit `status: entwurf`, bevor irgendetwas generiert wird; ohne diese Zeile gäbe es keinen Ort, an den man nach dem Warten zurückkehrt. Je Kettenbild eine `jobs`-Zeile. Ordner-Detail zeigt die Posts mit aufgelösten Slot-Namen.
|
||||
|
||||
**Nachweis über die Oberfläche:** Post „Serum auf Waschtisch" → Ordner Herbstlinie, `4:5`, 3 Bilder, `privat`, Slots Halle-Metallwand + Refine-&-Renew-Serum, dazu **3 Jobs `bild_gen/wartend` mit `prompt_template_key = P7`**.
|
||||
|
||||
**Job-Dispatcher steht** – `scripts/job-dispatcher.mjs`, serverseitig, weil der Anbieter-Schlüssel nicht ins Client-Bundle darf. Er baut aus Slot-Rezept, den Beschreibungen der freigegebenen Asset-Versionen, den Top-Attributen **des gewählten Ordners** und den globalen Regeln einen Prompt, erzeugt das Bild, legt es in `generated-images` mit Team-Rechten ab, schreibt `post_images` und setzt den Post auf `generiert`, sobald die Kette vollständig ist.
|
||||
|
||||
Drei Anbieter über `BILD_ANBIETER`:
|
||||
|
||||
| Wert | Ergebnis (geprüft 14.08.2026) |
|
||||
|---|---|
|
||||
| `stub` | ✅ erzeugt Platzhalterbilder – **die ganze Kette ist damit prüfbar, ohne einen Cent auszugeben** |
|
||||
| `ark` | ✗ `ModelNotOpen: account 3003959567 has not activated seedream-5-0` |
|
||||
| `openrouter` | ✗ `Insufficient credits. This account never purchased credits` |
|
||||
|
||||
**Durchgespielt mit `stub`:** Post „Serum auf Waschtisch" → 3 Jobs → 3 Bilder erzeugt, hochgeladen, Post auf `generiert`, Kette im Ordner-Detail sichtbar (3/3 geladen). Bei den echten Anbietern greift der Fehlerpfad: Job auf `fehler` mit der Anbieter-Meldung, Post auf `fehler`.
|
||||
|
||||
**Damit fehlt nur noch die Freischaltung.** Sobald eines der beiden Konten offen ist, liefert `BILD_ANBIETER=ark node scripts/job-dispatcher.mjs` echte Bilder – ohne Codeänderung.
|
||||
|
||||
**Offen:** Umzug des Dispatchers in eine Appwrite-Function (läuft jetzt lokal/per Cron), P7 als versionierter Prompt statt der Vorstufe im Skript, P22 als Tagger, Wartezustand mit Realtime, Ergebnis-Screen mit Veröffentlichen.
|
||||
|
||||
### E7 · Feed
|
||||
**Inhalt:** Veröffentlichen mit Zeilen-Permission, Feed-Deck mit den drei Reitern, Post-Detail, `post_metrics` schreiben, Function `feed-score-berechnen` mit Decay und Explorations-Slot.
|
||||
@@ -187,6 +237,6 @@ E0 Schema
|
||||
|
||||
## 7. Was vor E0 zu entscheiden ist
|
||||
|
||||
1. **Nischen-Liste** und **`typ_tags`-Liste** – beide sind Enums und wandern in E0 ins Schema. Später zu ändern heißt: dieselbe Migrationsfalle wie oben.
|
||||
2. **Bildmodell** – blockiert nicht E0, aber E6. Der Test dafür sollte parallel zu E1–E5 laufen.
|
||||
1. ~~**Nischen-Liste** und **`typ_tags`-Liste**~~ – ✅ entschieden und live. 20 Nischen, 17 Motiv-Tags, stehen als `NISCHEN` und `TYP_TAGS` in `scripts/setup-appwrite.mjs`.
|
||||
2. **Bildmodell** – blockiert nicht E0, aber E6. Der **Anbieter steht** (OpenRouter, siehe `projekt-uebersicht.md` §9); offen ist nur, welches der dortigen Bildmodelle die Multi-Referenz-Komposition trifft. Der Wegwerf-Test dafür sollte parallel zu E1–E5 laufen.
|
||||
3. **Mindestalter und Moderationsweg** – blockiert nicht den Code, aber E7 im Livebetrieb.
|
||||
|
||||
Reference in New Issue
Block a user