# Programmier-Plan **Stand:** 28. Juli 2026 **Repo:** `git.webklar.com/knso/videogen` · Backend: Appwrite `appwrite.webklar.com/v1`, Projekt `6a5cee34002bb8360c34`, DB `brandloop` **Grundlage:** `app-aufbau.md` (Screens) · `konzept-bilder-feed.md` (Konzept) · `datenbank-aufbau.md` (Schema) --- ## 1. Ausgangslage – was schon da ist | | Stand | |---|---| | **Appwrite-Schema** | 15 Tabellen, Indizes, 4 Buckets, Team `internal` – angelegt durch `scripts/setup-appwrite.mjs`, idempotent | | **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. --- ## 2. Schema-Delta – was konkret fehlt Abgeglichen gegen `scripts/setup-appwrite.mjs`. ### 2.1 Neue Tabellen (6) | Tabelle | Zweck | |---|---| | `folders` | Wissens-Scope: `brand_id`, `name`, `theme_md`, `zweck`, `startwert_modus`, `ist_default`, `post_count`, `signal_count` | | `attribute_scores` | Score je Attribut je Ordner – **Herzstück** | | `posts` | Slot-Rezept, `slot_summary`, `sichtbarkeit`, `feed_score` | | `post_images` | Bilderkette, `typ` = motiv \| text_overlay | | `post_folders` | m:n Post ↔ Ordner, `ist_fremd`, `quelle` | | `post_metrics` | Views, Likes, Kopien, Social-Reichweite | ### 2.2 Neue Tabelle wegen des Folgen-Konzepts (1) | Tabelle | Zweck | |---|---| | `follows` | `follower_brand_id`, `followed_brand_id`, unique auf beide, Index in beide Richtungen | ### 2.3 Änderungen an bestehenden Tabellen | Tabelle | Änderung | Art | |---|---|---| | `brands` | `+ nische`, `+ plan`, `+ anzeigename`, `+ avatar_file_id`, `+ follower_count`, `+ ist_oeffentlich` | Spalten ergänzen | | `attributes` | `− score, k_factor, start_value, used_count, wins, losses, last_used_at` → wandern nach `attribute_scores`; Index `idx_topn` entfällt hier | **Umbau** | | `categories` | `+ folder_id` | Spalte + Index | | `assets` | `+ nische`, `+ typ_tags[]`, `+ feed_score`, `+ feed_score_updated_at`, `+ ist_teilbar`; `typ`-Enum **um `kulisse`** | Spalten + **Enum-Änderung** | | `score_events` | `+ folder_id`, `+ post_id`; `event_type`-Enum **um `feed_import`, `post_reichweite`** | Spalten + **Enum-Änderung** | | `scenes` | `+ folder_id` | Spalte | | `jobs` | `typ`-Enum **um `slot_analyse`, `ordner_vorschlag`, `werbetext`** | **Enum-Änderung** | | `prompt_templates` | `key`-Enum **P18 → P22** (`P_KEYS` im Skript: `length: 18` → `22`) | **Enum-Änderung** | ### 2.4 Neuer Bucket `generated-images` – öffentlich lesbar, sobald der zugehörige Post veröffentlicht ist. ### 2.5 Neue Functions (4) `ordner-initialisieren` · `feed-score-berechnen` (Cron) · `feed-import` · `social-reichweite-holen` (Cron) Dazu die aus dem alten Plan noch offenen: `elo-update`, `favorit-berechnen`, `ads-metriken-holen`, `kategorie-durchschnitt`, `archivierung`, `job-dispatcher`. ### 2.6 Zwei Fallen bei der Migration **Enum-Änderungen sind kein Anhängen.** Vier Spalten brauchen neue Enum-Werte (`assets.typ`, `score_events.event_type`, `jobs.typ`, `prompt_templates.key`). Appwrite behandelt das als Spaltenänderung, nicht als Ergänzung – je nach Version bedeutet das Löschen und Neuanlegen der Spalte, also **Datenverlust**. Das ist der Grund, warum diese Änderung **jetzt** passieren muss, solange die Tabellen leer sind. In sechs Wochen mit echten Daten ist es ein Migrationsprojekt. **Die `attributes`-Auftrennung ist ein Umbau, kein Zusatz.** Sieben Spalten verschwinden aus einer Tabelle und tauchen in einer neuen wieder auf, mit einer zusätzlichen Dimension. Solange keine Brand existiert, ist das eine Textänderung im Setup-Skript. Danach ist es eine Datenwanderung mit Ausfallzeit. > **Deshalb ist „Fundament zuerst" nicht nur die aufgeräumte, sondern die einzig günstige Reihenfolge.** --- ## 3. Etappen 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. ### 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. ### 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. > 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. ### E3 · Onboarding **Inhalt:** Die vier Onboarding-Screens mit echten Feldern, inklusive **Nische**. Uploads in den Bucket `uploads`. P2 als erster echter LLM-Aufruf über `jobs`. **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 **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. ### E5 · Ordner **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. ### E6 · Post erstellen (erste echte Generierung) **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**. ### 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. **Abnahme:** Ein veröffentlichter Post von Konto A erscheint im Feed von Konto B. `prompt_sent` ist über die API von Konto B **nicht** abrufbar. **Aufwand:** groß. ### E8 · Kopieren **Inhalt:** P19 (Slot-Analyst), Kopier-Screen mit Chips und Kompatibilitätsprüfung, P21 (Werbetext), Function `feed-import`, `copied_from_post_id`, Kopien-Zähler. **Abnahme:** Konto B kopiert den Post von Konto A, ersetzt beide Modelle, generiert – und in der Knowledge Base von Konto B stehen danach neue Attribute mit `start_quelle = feed_import` im gewählten Ordner. **Aufwand:** groß. Das ist der Moment, in dem das Produkt das tut, was es verspricht. ### E9 · Folgen **Inhalt:** `follows`, Fremdprofil, Folgen-Button, Reiter „Folge ich" chronologisch, Blockieren und Melden. **Abnahme:** Konto B folgt Konto A und sieht dessen neuen Post im Reiter „Folge ich", vor allem anderen. **Aufwand:** mittel. ### E10 · Video-Strecke **Inhalt:** Die bestehende Video-Strecke aus dem Prototyp echt machen: `scenes`, P3/P4/P5/P8, `videos`, Vote, `elo-update`, gezielte Frage. **Abnahme:** Ein Prompt erzeugt vier Videos von vier KI-Modellen; nach dem Vote haben sich Scores in `attribute_scores` messbar verändert und `score_events` hat die passenden Zeilen. **Aufwand:** sehr groß, und mit laufenden Kosten ab dem ersten Test. --- ## 4. Reihenfolge und Abhängigkeiten ``` E0 Schema └─ E1 Gerüst └─ E2 Auth ──────────────┐ ├─ E3 Onboarding │ ├─ E4 Modelle ───────┤ └─ E5 Ordner ────────┤ └─ E6 Post erstellen ├─ E7 Feed │ ├─ E8 Kopieren │ └─ E9 Folgen └─ E10 Video ``` **E3, E4 und E5 sind untereinander unabhängig** – sie können in beliebiger Reihenfolge oder parallel entstehen. Alles ab E6 hängt an allen dreien. **E10 (Video) steht bewusst hinten,** obwohl es das Kernprodukt ist: Es ist die teuerste Strecke in der Umsetzung *und* im Betrieb, und der Bild-Strang erzeugt vorher die Daten, mit denen sich der Video-Teil überhaupt sinnvoll testen lässt. --- ## 5. Was im ersten Durchgang bewusst wegbleibt | Weggelassen | Warum | |---|---| | Desktop-Ansicht | Handy zuerst; der Handoff im Repo ist laut dir noch nicht gültig | | Stripe / Abrechnung | Preismodell ist offen (offener Punkt 3) – ohne Entscheidung nicht baubar | | Meta-/TikTok-Ads-Anbindung | App-Reviews dauern; Antrag trotzdem **jetzt** stellen, unabhängig vom Code | | Social-Reichweite (echte Instagram-Zahlen) | eigene App-Review; bis dahin läuft der Feed-Score nur auf In-App-Signalen | | P12–P18, P20 | nachrüstbar, ohne sie funktioniert der Loop | | Verbessern-Strecke | vorhanden im Prototyp, aber nicht auf dem kritischen Pfad | | Developer-Modus | intern, kein Nutzerwert – erst wenn es echte Prompts zu debuggen gibt | --- ## 6. Risiken | Risiko | Wirkung | Gegenmaßnahme | |---|---|---| | **Enum-Migration nach dem Livegang** | Datenverlust in vier Spalten | E0 vor allem anderen, solange die DB leer ist | | **Multi-Referenz-Komposition** (Person + Produkt + Kulisse konsistent in einem Bild) | Der Kern des Bild-Modus funktioniert nicht wie gedacht | Vor E6 mit zwei, drei Kandidatenmodellen einen Wegwerf-Test fahren – **bevor** UI dafür gebaut wird | | **Generierungskosten im Test** | schleichende Kosten ohne Gegenwert | `jobs.cost_usd` ab E6 mitschreiben und ein hartes Tageslimit einbauen | | **Leerer Feed** | E7 ist nicht bewertbar, E8 nicht testbar | Vor E7 mit dem eigenen Konto 15–20 Posts erzeugen | | **Prototyp als Vorlage überschätzt** | Screens werden 1:1 übernommen inklusive der Attrappen | `app-aufbau.md` §6 ist die verbindliche Liste, nicht die HTML-Datei | | **Öffentlich/privat nur im UI durchgesetzt** | fremde Knowledge Bases werden über die API auslesbar | Abnahme von E7 ausdrücklich **über die API** prüfen, nicht über den Bildschirm | --- ## 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. 3. **Mindestalter und Moderationsweg** – blockiert nicht den Code, aber E7 im Livebetrieb.