193 lines
12 KiB
Markdown
193 lines
12 KiB
Markdown
# 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.
|