localer plan

This commit is contained in:
2026-08-06 12:44:41 +02:00
parent 7e43f695fa
commit 7c63380b35
12 changed files with 3140 additions and 0 deletions

192
planung/programmier-plan.md Normal file
View File

@@ -0,0 +1,192 @@
# 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** | P1P18 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 |
| P12P18, 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 1520 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 E1E5 laufen.
3. **Mindestalter und Moderationsweg** blockiert nicht den Code, aber E7 im Livebetrieb.