pageta/STATUS.md
Till JS 28ca5a5792 Listen-Import gebaut — die Landing versprach ihn seit Monaten
Die Pocket-Seite beschrieb „Lese-Liste → URLs hinzufügen → Pocket-Export
(.zip)". Diese Schaltflaeche gab es nie: kein Treffer fuer .zip, jszip
oder eine Datei-Annahme im ganzen Web- und API-Code. Gleichzeitig lag der
Bulk-Weg der API (POST /api/v1/imports, 200 je Auftrag) seit Lambda-5
fertig da — api.startBulkImport() war definiert und wurde von keiner
Zeile aufgerufen.

Also gebaut statt gestrichen:

- $lib/url-list.ts zieht Adressen aus beliebigem Text (CSV, HTML-Ausfuhr,
  eingefuegte Liste). Bewusst kein Format-Erkenner — Spaltennamen
  unterscheiden sich je Dienst und je Jahr, Adressen nicht. Entdoppelt
  ueber Schluss-Schraegstrich, Fragment und Wirt-Schreibweise, wirft
  Bilder und Skripte raus. 13 Tests.
- Neuer erster Abschnitt in /lese-liste/settings: Datei waehlen oder
  einfuegen, zaehlen, importieren. Ueber 200 Adressen laufen als mehrere
  Auftraege NACHEINANDER — parallel staenden bei 5000 Adressen 25
  Auftraege in derselben Extraktions-Kette. Fortschritt, Abbruch, und
  beim Verlassen der Seite haelt die Schleife an.
- ZIP wird nicht ausgepackt, und die Oberflaeche sagt das.

Ein Test fand einen Fehler, den der Code nicht zeigte: der Adress-Sucher
endet am Semikolon (es trennt in CSV und HTML die Felder), damit wurde
"...?a=1&b=2" zu "...?a=1&amp". Entitaeten werden jetzt vor dem
Suchen aufgeloest.

Dazu drei Stellen, an denen Text und Stand auseinanderliefen:

- getpocket.com/export ist zu (gemessen: 302 auf /home; Mozilla hat die
  Daten am 2025-11-12 geloescht). Die Seite schickte Leute trotzdem hin.
  Jetzt sagt sie, was heute noch geht.
- Das PWA-Manifest bewarb "Feed, Lese-Liste, Recherche" und legte
  Verknuepfungen auf /feed und /recherche — beide ruhen seit 2026-06-01
  und leiten weiter. Ein installiertes Symbol fuehrte ins Leere.
- /konto sagte Gaesten, die Lese-Liste brauche ein Konto, und nannte die
  ruhende Recherche. Jetzt steht dort der Satz aus der i18n-Quelle, den
  auch die Native-App zeigt.
- llms.txt versprach Maschinen ".zip inkl. Tags und Highlights" und
  "Export aller Daten als JSON jederzeit". Beides unwahr.

Offen und nicht selbst entschieden: eine Ausfuhr der ganzen Liste auf
Knopfdruck gibt es nirgends — der Text ist jetzt ehrlich, der Knopf
fehlt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MhVjQpDUkFZGtFWsLid4PT
2026-09-05 12:53:25 +02:00

27 KiB
Raw Permalink Blame History

Pageta — Status

Letzter Stand: 2026-09-05. LIVE 🚀 + voll-featured

2026-09-05 — Der Umzugs-Weg gab es nur auf dem Papier

Ein Durchgang durch App, Landing und Doku hat eine Lücke gefunden, die niemand meldet, weil beide Seiten für sich stimmig aussahen: die Landing beschrieb einen Import, den die App nicht hatte.

  • /pocket-import sagte „Lese-Liste → ‚URLs hinzufügen' → ‚Pocket-Export (.zip)'". Diese Schaltfläche gab es nie. Im ganzen Web- und API-Code steht kein einziger Treffer für .zip, jszip oder eine Datei-Annahme.
  • Sie schickte Leute auf getpocket.com/export. Gemessen am 2026-09-05: 302 auf /home. Mozilla hat den Export geschlossen und die Konten-Daten am 2025-11-12 gelöscht. Der Weg war also nicht nur unbeschrieben, er war zu.
  • Der Bulk-Weg der API (POST /api/v1/imports, 200 je Auftrag) lag seit λ-5 fertig da — ohne jede Oberfläche. api.startBulkImport() war im Client definiert und wurde von keiner Zeile aufgerufen.

Gebaut statt gestrichen. Die Zusage war die richtige, nur ohne Umsetzung — also hat die App jetzt den Import, den die Landing versprach:

  • $lib/url-list.ts — zieht Adressen aus beliebigem Text (CSV, HTML- Ausfuhr, eingefügte Liste). Bewusst kein Format-Erkenner: die Spaltennamen unterscheiden sich je Dienst und je Jahr, Adressen nicht. Entdoppelt über Schluss-Schrägstrich, Fragment und Wirt-Schreibweise, wirft Bilder/Skripte raus. 13 Tests.
  • Neue Fläche in /lese-liste/settings (erster Abschnitt): Datei wählen oder einfügen → zählen → importieren. Listen über 200 laufen als mehrere Aufträge nacheinander (nicht parallel — sonst stehen bei 5 000 Adressen 25 Aufträge gleichzeitig in derselben Extraktions-Kette). Fortschritt, Abbruch, und beim Verlassen der Seite hält die Schleife an.
  • ZIP wird nicht ausgepackt und die Oberfläche sagt das, statt eine Binärdatei zu durchsuchen und „nichts gefunden" zu melden.

🛑 Der Test hat einen Fehler gefunden, den der Code nicht zeigte: der Adress-Sucher endet am Semikolon (es trennt in CSV und HTML die Felder) — …?a=1&amp;b=2 wurde damit zu …?a=1&amp. Entitäten werden jetzt VOR dem Suchen aufgelöst. Ohne den einen Test wäre jede Adresse mit zwei Abfrage-Feldern aus einer HTML-Ausfuhr still kaputt importiert worden.

Drei weitere Stellen, an denen Text und Stand auseinanderliefen:

  • Das PWA-Manifest bewarb „Feed, Lese-Liste, Recherche" und legte Verknüpfungen auf /feed und /recherche. Beide ruhen seit 2026-06-01 und leiten weiter — ein installiertes Symbol führte ins Leere. Jetzt: Lese-Liste, Markierungen, Artikel speichern.
  • /konto sagte Gästen „Lese-Liste, Markierungen und Recherche brauchen ein mana-Konto" — nannte die ruhende Recherche und widersprach der local-first-Zusage der eigenen i18n-Quelle. Jetzt steht dort der Satz aus mana/i18n/pageta.de.json, den auch die Native-App zeigt.
  • llms.txt versprach Maschinen „Pocket-Import (.zip) inkl. Tags und Highlights" und „Export aller Daten als JSON jederzeit". Beides unwahr; korrigiert.

🔴 Offen und bewusst nicht selbst entschieden: eine Ausfuhr der ganzen Liste auf Knopfdruck gibt es nicht. Weder pageta noch das mana-Konto haben eine Schaltfläche dafür; die DSGVO-Route ist Service-Key-gesichert, ein Mensch muss sie auslösen. Die Landing hat das bis heute als „jederzeit verfügbar" behauptet — der Satz ist jetzt ehrlich („auf Anfrage"), aber der Wert datensouveraenitaet verlangt den Knopf. Local-first heisst: die Daten liegen im Gerät, eine Ausfuhr wäre clientseitig und klein.

🛑 Und ein Betriebsfund: pnpm --filter @pageta/web check scheiterte mit einem unverständlichen vite-Typfehler — zwei vite-Instanzen im Baum (terser 5.49 gegen 5.51), obwohl das Lockfile nur eine kennt. pnpm install räumt es weg, danach 0 Fehler. Wer den Fehler liest, sucht sonst im eigenen Code.

2026-07-30 — Tagging am echten Bestand: drei Funde

40 Artikel über die Mana-Cloud getaggt (claude-haiku-4.5, ~1,5 s je Artikel). Die Tag-Qualität stimmt (Handelspolitik, Justizirrtum, Kinderschutz, Batterietechnik), aber der erste Blick auf die Karte hat drei Dinge aufgedeckt:

  1. Nabenknoten. tech (der einzige Alt-Tag) wurde an 39 von 40 Artikeln vorgeschlagen und zog die Karte zu einem Stern zusammen. Tags ab 80 % Anteil werden jetzt aus der Zeichnung genommen — benannt statt verschwiegen, abschaltbar, am Artikel bleiben sie.
  2. Beschriftungs-Salat. Das Kräfte-Layout trennt Kreise, nicht Wörter. Neu: Beschriftungslängen fließen ins Layout ein, und label-placement.ts setzt jedes Wort deterministisch unten / oben / gar nicht.
  3. Vokabular wuchs nicht mit. Der Stapel lud die vergebenen Tags einmal beim Öffnen — Artikel 40 kannte nur den Stand vor Artikel 1. Folge: 60 Tags auf 40 Artikel (fast jeder genau einmal, also kaum Verbindungen) plus Dubletten wie „Kryptografie" neben „Kryptographie". GrowingVocabulary reicht jetzt das mitwachsende Vokabular in jeden Prompt.

Zweiter Durchlauf nachgeholt (nach Neu-Login). Mit mitwachsendem Vokabular kamen 84 Tags für 38 Artikel — und diesmal überwiegend vorhandene (Recht, Kinderschutz, Prompting, Nachhaltigkeit, Energieeffizienz). Genau die Querverbindungen, die vorher fehlten: aus einem Feld von Zweier-Inseln wurde ein zusammenhängendes Netz.

Dritter Fund dabei: das dichte Netz war unlesbar — 43 von 75 Beschriftungen fielen weg. Mehr Fläche hilft nicht (ein größerer viewBox skaliert die Schrift proportional mit herunter; gemessen: 2000×1350 = 0 Kollisionen bei ~8 px Schrift, höher-statt-breiter bringt 12→7). Bei deutschen Komposita passen ~40 Wörter auf einen Bildschirm, nicht 75. Also filtert die Karte auf wiederkehrende Tags (ab 2 Artikeln) — selbst- entscheidend ab 45 Knoten und nur, wenn danach ≥8 übrig bleiben, sonst wäre eine kleine Lese-Liste leer. Ergebnis: 30 Knoten, 2 ausgeblendete Wörter.

Stand jetzt: 32 Tags aus 46 getaggten Artikeln, keiner mehr ohne Tag (die letzten 6 lagen nur an der 40er-Obergrenze je Lauf und wurden nachgezogen).

Dubletten-Werkzeug (packages/pageta-domain/src/tag-merge.ts): findTagVariants gruppiert Schreibvarianten (ß→ss, ph→f, Bindestriche weg) und Tippfehler (Editierdistanz 1, erst ab 8 Zeichen + gleicher Wortanfang). Am Bestand gefunden und zusammengeführt: Kryptografie/Kryptographie, Music-/Musik-Streaming, Webstandards/Web-Standards. Die Zielform wählt der Mensch — bei Gleichstand entscheidet die Heuristik alphabetisch und schlug prompt „Music-Streaming" für eine deutsche Liste vor.

2026-07-29 — Themenkarte + Tag-Vorschläge

Zwei Stufen, live unter /rueckblick/themen und im Werkzeug-Menü der Lese-Liste.

  • Themenkarte (packages/pageta-domain/src/graph.ts, apps/web/src/lib/graph-layout.ts): Tags als Ko-Vorkommens-Graph — Knoten sind Tags (auf Wunsch auch Quellen), eine Kante heißt „kommt am selben Artikel vor". Kein LLM, kein Server: Zählarbeit über den lokalen Event-State, Layout als eigenes Fruchterman-Reingold, deterministisch (Goldwinkel-Spirale statt Math.random) und einmal fertig gerechnet statt laufender Simulation. Die Lese-Liste versteht jetzt ?tag=.
  • Tag-Vorschläge (packages/pageta-domain/src/autotag.ts): Vokabular- Weg über das Modell (die bereits vergebenen Tags gehen in den Prompt, höchstens EIN neuer Begriff — sonst Wildwuchs) mit KI-freiem Rückfall über TF-IDF gegen die eigene Liste. Einzeln im Reader, im Stapel aus der Lese-Liste (max. 40 je Lauf). Geschrieben wird erst auf Bestätigung, über das bestehende ArticleTagsSet-Event — bewusst kein eigener Event-Typ, das hätte @mana/shared-schemas mitgezogen.
  • Neue Route POST /api/v1/tags/suggest (JWT, 60/min), greift nur bei erlaubtem Cloud-Pfad.

Am Live-Bestand geprüft, zwei Funde: die ganze Lese-Liste trug genau 1 Tag (die Karte blieb also leer — Auto-Tagging war die Voraussetzung, nicht die Kür), und der statistische Weg schlug anfangs Wortformen statt Begriffe vor („Ausländischer", „Führte", „Kilometern"). Behoben über die deutsche Großschreibung als Substantiv-Signal plus vorsichtige Grundform-Zusammenführung.

Offen: ohne lokales Modell und ohne erlaubte Mana-Cloud bleibt nur der statistische Weg; dessen Labels sind Wörter, keine Begriffe. Der Vokabular-Weg ist ungetestet gegen ein echtes Modell, weil im Testkonto beides aus ist.

2026-07-27 — Mehrseitige Artikel kommen vollständig an

Bookmarklet und Erweiterung sammeln Folgeseiten jetzt im Tab des Nutzers und schicken sie als Liste; der Server extrahiert jede Seite einzeln und fügt sie in Lese-Reihenfolge zusammen.

Anlass: golem.de/news/…-2607-211258.html hat drei Seiten, gespeichert wurde bisher nur Seite 1 (911 von rund 2400 Wörtern). Serverseitig ist da nichts zu holen — Golem beantwortet auch Seite 2 ohne Zustimmungs-Cookie mit der Abfrage. Ein fetch aus dem Tab bekommt sie (gemessen: 200, kein Redirect).

  • Folgeseiten-Erkennung ohne quellenspezifische Selektoren (apps/web/src/lib/page-collector.js): ein Link zählt, wenn seine Adresse sich von der aktuellen nur in einem Seitenzähler unterscheidet (-2.html, ?page=2, /seite/2/); ohne Seitenliste folgt es rel="next". Deckel: 20 Seiten, 6 MB, 300 ms Pause je Abruf.
  • Gestrippt vor dem Senden — <style>/<noscript>/<template> raus, Skript-Inhalte geleert, Tags/Attribute und JSON-LD bleiben (sonst verlören siteNameFromJsonLd und die CMP-Signaturen in consent-wall.ts ihre Grundlage). Gemessen: Golem 401 → 145 KB, Extraktions-Ergebnis nachweislich unverändert (Titel, Wortzahl, siteName, Bild, Datum identisch an the-decoder.de und winfuture.de).
  • API: POST /articles/extract/preview nimmt zusätzlich pages (max 20), antwortet mit pageCount. html bleibt gültig — Bookmarklets liegen im Lesezeichen des Nutzers und werden nicht mitdeployt.
  • Ehrlich bei Lücken: kam eine erkannte Folgeseite nicht durch, springt die add-Seite nicht weiter, sondern sagt „x von y Seiten".
  • Am Golem-Artikel verifiziert: 3 Seiten, 0 fehlend, 298 KB statt ~1,2 MB.

Wer schon ein Bookmarklet installiert hat, muss es einmal neu ablegen — ein altes speichert weiterhin nur Seite 1. Der Hinweis steht in den Einstellungen.

Offen: pageCount wird nicht im Event gespeichert (bräuchte ein Feld in evt_article_saved_v1/evt_article_enriched_v1, also @mana/shared-schemas mit 14 Konsumenten). Server-seitiges Nachladen für die Wege ohne Browser (Bulk-Import, Feed-Archiv, „Neu extrahieren") steht ebenfalls noch aus — derselbe Detektor, aber im API-Prozess.

2026-07-23 — Quellen / Blog-Hub

Artikel können einer Quelle (source:<hostname>) zugeordnet werden. Hub unter /quelle/howtomarketagame.com. Feed-Import legt Quelle an und verknüpft Artikel; ältere Imports nachträglich unter Settings. Lese-Liste zeigt Quellen-Chips + Filter ?quelle=. Schema @mana/shared-schemas 0.1.23 (SourceUpserted / ArticleSourceLinked) — vorerst Vendor-Tarball, bis Verdaccio-Publish wieder greift.

2026-07-23 — Blog/Feed einmalig importieren

Unter /lese-liste/settings: Blog- oder Feed-URL → Vorschau → Batch-Save in die Lese-Liste. Backend: POST /api/v1/imports/from-feed[/preview] (RSS-Discovery, WP-?paged=N, optional Sitemap-Fallback). Bulk-Worker schreibt jetzt nach sync2 (emitArticleSaved), nicht mehr in die legacy Postgres-saved_articles. Cap Feed-Archiv: 1000.

2026-06-03 — Rechtsklick-Kontextmenü auf der Lese-Liste

Geteiltes @mana/shared-ui/organisms ContextMenu auf jedem Artikel-<li>: Lesen / Original öffnen / Status (gelesen·ungelesen) / Archivieren bzw. Aus-Archiv / Taggen / Löschen — dieselben api.batch*-Handler wie die Batch-Toolbar, aber direkt pro Artikel ohne Auswahl-Modus. Ergänzt die sichtbaren Aktionen (Touch/Mobile bleibt bedienbar). svelte-check 0 neue Fehler, build grün, Screenshot verifiziert, live auf app.pageta.com. (683ff3f)

Folge-Sprint 2026-05-22 — Web-/Native-Parität + Cross-Device

Landing-Cutover 2026-05-22 19:30

Subdomain-Migration ausgeführt (LANDING_CUTOVER.md): pageta.com zeigt jetzt auf die Astro-Marketing-Landing (pageta-landing:3201), die App lebt unter app.pageta.com (pageta-web:3100, war vorher pageta.com).

  • GET https://pageta.com/ → 200 Marketing-Landing (Title: „pageta — Pocket ist tot. Lies in Ruhe weiter.")
  • GET https://pageta.com/{ueber,mitwirken,pocket-import} → 200
  • GET https://pageta.com/sitemap.xml → 200 (4 Marketing-URLs)
  • GET https://pageta.com/.well-known/apple-app-site-association → 200 application/json (Universal Links bleiben funktional)
  • GET https://pageta.com/{lese-liste,article/*,feed,konto,markierungen,recherche,auth/*} → 301 → app.pageta.com/...
  • GET https://app.pageta.com/ → 307 → /lese-liste (App-Default)
  • GET https://app.pageta.com/{lese-liste,feed,konto,markierungen} → 200
  • GET https://pageta-api.mana.how/healthz → {"status":"ok"}
  • POST https://pageta-api.mana.how/api/v1/summarize (kein JWT) → 401 ✓

Offene Punkte aus dem Cutover:

  • Native iOS-App-AASA hardcoded auf pageta.com — Universal-Links auf /article/* und /lese-liste/* werden weiterhin vom Landing-nginx korrekt ausgeliefert (gleicher JSON-Payload, gleiche App-IDs). Im nächsten TestFlight-Build verifizieren.
  • Erst-Login auf app.pageta.com bei einem User, der vorher auf pageta.com eingeloggt war: ggf. erneutes Login nötig, weil App- spezifische Cookies (falls vorhanden) auf der alten Apex-Domain verwaisen. mana-auth-Cookie auf .mana.how ist nicht betroffen.

warning: string | null lebt jetzt im event-sourced ArticleState, nicht mehr in localStorage. Zwei neue Events:

  • ArticleWarningFlagged setzt state.warning (heute nur "probable_consent_wall")
  • ArticleWarningCleared löscht ihn (UI „Hinweis ausblenden")

Bewusst eigene Events statt ArticleSaved-Payload-Erweiterung — evt_article_saved_v1 bleibt frozen. Native + Web schreiben + lesen beide via ev/article:<id>-Aggregat; Banner zeigt sich auf jedem Gerät, das den Event-Stream replayed hat.

Schaden + Recovery 2026-05-22 13:43: Beim ersten Publish-Versuch wurde @mana/shared-schemas versehentlich komplett unpublished (DELETE auf /-rev/latest). 0.1.1/0.1.6/0.1.7/ 0.1.8/0.1.10 sind weg, nur 0.1.11 ist live. Recovery via Lockfile-Bump

  • pnpm install in allen 8 Schwester-Apps (uload/moodlit/werdrobe/ comicello/nutriphi/wordeck/mukke/herbatrium) auf ^0.1.11. Funktional unkritisch — Schema-Änderungen nur in pageta-Sub-Schema, andere Sub-Schemas byte-gleich.

Konkret eingefügt, alles im Web:

  • Routing-Restructure: / redirected auf /lese-liste (= Standardseite, wie Native). Feed-Tab lebt jetzt auf /feed. Tab-Reihenfolge im Layout spiegelt Native: Lese-Liste · Markierungen · Feed · Recherche · Konto.
  • /konto neue Seite: E-Mail/Tier/Konto-ID, Abmelden + „Konto verwalten ↗", ThemeToggle + VariantPicker (alle 8 mana-Themes), Bookmarklet-Link, Über-Sektion (Datenschutz/Verein/pageta.com). ThemeToggle ist aus dem Header raus (lebt jetzt in /konto), genau wie bei Native.
  • Save-from-Feed: Feed-Items haben jetzt einen „+ In Lese-Liste"-Button (zuvor read-only, nur Original-Link).
  • Vor/Nach-Sibling-Navigation im Reader-Footer (Pfeil + Titel-Karte, identisch zur Native-Variante).
  • Cookie-Wall-Banner im Web-Reader. Lokal-persistiert via localStorage-Map keyed by articleId (Schema-Bump in @mana/shared-schemas vermieden). Banner mit „Original im Browser öffnen" + „Hinweis ausblenden".
  • Tag-Read-back: Article.tags durchgereicht aus ArticleState. Reader zeigt Tags als Pills + Tag-Hinzufügen-Input; emittiert ArticleTagsSet. Native kann Tags ab sofort auch sehen, sobald sie das DTO-Feld liest (eigener Followup, betrifft pageta-native/Sources/Core/Domain/Article.swift).
  • Reading-Progress persistiert: Window-Scroll-Listener mit Debounce (1.5 s), emit ArticleProgressUpdated ab 2 %-Differenz; beim Re-Open springt der Reader an die gespeicherte Position. beforeunload-Hook flusht Pending-Progress vor Tab-Close.
  • LLM-Zusammenfassung im Reader: neue Route POST /api/v1/summarize in pageta-api ruft mana-llm mit Alias mana/fast-text. Client-Sektion „Zusammenfassen ✨" im Reader, ohne Persistierung (Volltext bleibt Source-of-Truth). Pendant zum Native ArticleSummarySection (Foundation Models / Gemma).

Phase

λ-0 ✅ + λ-1 ✅ + λ-2 ✅ + λ-3 ✅ + λ-4 ✅ + λ-5 ✅ + λ-6 ✅ + Lift-A ✅ + Lift-B ✅ + CI ✅ + Deploy ✅ + Login-Flow ✅ + Verein-Landing ✅ — pageta.mana.how ist erreichbar, alle ursprünglich geplanten λ-Phasen sind live.

Folge-Sprint 2026-05-17

  • Echter Login-Flow — Cards-Pattern: SSO-Cookie → /auth/refresh → JWT in localStorage. apps/web/src/lib/auth/session.svelte.ts, apps/web/src/routes/auth/callback/+page.svelte, AuthGate im Layout mit silent-refresh + Redirect zum Auth-Portal. mana-auth-web hat lesen in der App-Allowlist (Forest-Branding, pageta.mana.how + localhost:3100 als erlaubte Redirect-Origins).
  • Verein-Landing — mana-ev.ch zeigt Lesen als 12. App-Card + Intro „elf eigenständige Produkte". Eigenes lesen.svg.
  • λ-5 Bulk-Import — POST /api/v1/imports (cap 200/Job), Tick-Worker alle 2s mit Postgres pg_try_advisory_lock, State-Machine pending → extracting → saved/duplicate/error. Worker bootet im Container.
  • λ-6 Tool-Handler — 5 Tools live unter /api/v1/tools/:name (save_article, list_articles, archive_article, add_article_tag, add_article_highlight). Alle JWT-gated + zod-validated. JSON-Schemas pro Tool im app-manifest.json#tools[] für mana-mcp-Discovery.

Live-Smoke (2026-05-16 19:13)

  • GET https://pageta.mana.how/ → 200 (SvelteKit-SSR)
  • GET https://pageta-api.mana.how/healthz → {"status":"ok","app":"pageta"}
  • GET https://pageta-api.mana.how/.well-known/mana-app.json → Manifest
  • GET https://pageta-api.mana.how/api/v1/feed (kein JWT) → 401
  • POST https://pageta-api.mana.how/api/v1/dsgvo/export (kein Key) → 401
  • POST .../dsgvo/export (Service-Key) → 200, leerer User-Export
  • mana-news-pool Tick: 1133 Artikel im Pool

Container (alle healthy)

Container Port Wo
pageta-postgres 127.0.0.1:5447 pageta-postgres-Volume /Volumes/ManaData/pageta/postgres/
pageta-api 127.0.0.1:3099 im Netz pageta_default + manacore-monorepo_default
pageta-web 127.0.0.1:3100 im Netz pageta_default
mana-news-pool 127.0.0.1:3079 im Netz manacore-monorepo_default, DB mana_news_pool auf mana-infra-postgres

Was steht

Phase Inhalt Status
λ-0 Repo-Skelett: pnpm-workspace, turbo, tsconfig, prettier, docker-compose ✅
λ-0 apps/api Hono-Skeleton (/healthz, /.well-known/mana-app.json) ✅
λ-0 apps/web SvelteKit-Skeleton mit drei Tab-Stubs ✅
λ-0 packages/pageta-domain Pure-TS Feed-Engine + Types + Sources, 9/9 Tests grün ✅
λ-0 PORTS.md-Eintrag in mana/ (pageta-api: 3099, pageta-web: 3100) ✅
λ-1 DB-Schema (Drizzle, 8 Tabellen in Schema reader), db:push grün ✅
λ-2 Auth-Middleware (JWKS + serviceKey), /dsgvo/export+delete, /search, /share/receive, /tools/:name ✅
λ-3 Core-API: /feed (Pool-Proxy + Server-side-Ranking), /articles CRUD, /highlights, /preferences, /reactions mit Auto-Weight-Diff, /extract/preview ✅
λ-4 Web-UI: 3 Tabs, API-Client, Feed + Lese-Liste, Reader-Detail /article/[id] mit Highlight-Selection (4 Farben, Selection-Listener, Plain-Text-Offsets, Highlight-Liste mit Delete), Status-Toggles, Favorit, Delete ✅
CI .github/workflows/ci.yml — install, type-check, db:push, build, web-check, domain-tests ✅
Compose infrastructure/docker-compose.production.yml + Dockerfiles für api/web; .env.production.example ✅
λ-5 Bulk-Import-Worker (Job/Items/Pickup-Pipeline gegen 200 URLs/Job) offen
λ-6 Föderation: accepts: [url] Handler vollständig, Tools-Handler-Implementierungen offen
λ-7 Deployment auf mana-server (pageta.mana.how, pageta-api.mana.how) bereit, ausstehend

Plattform-Lifts (parallel, vor λ-7)

Phase Inhalt Status
Lift-A @mana/shared-rss aus managarten nach mana/packages/ + Verdaccio ✅ (Code in mana/packages/shared-rss/, npm publish pending)
Lift-B news-ingester aus managarten → mana-news-pool Plattform-Service (Port 3079) ✅ (Code in mana/services/mana-news-pool/, eigene DB mana_news_pool, Schema pool, Dockerfile, Compose-Snippet im CLAUDE.md)
Lift-C News-Research-Endpoints in mana-research integrieren deferred

Verifizierter Stand (lokal, 2026-05-16)

  • pnpm install grün
  • pnpm docker:up → Postgres :5443
  • pnpm --filter @pageta/api db:push → 8 Tabellen + 11 Indizes in Schema reader
  • pnpm --filter @pageta/api type-check → grün
  • pnpm --filter @pageta/api dev → bootet auf :3099
    • GET /healthz → 200
    • GET /.well-known/mana-app.json → Manifest 200
    • GET /api/v1/feed (ohne Auth) → 401
    • GET /api/v1/articles (ohne Auth) → 401
    • POST /api/v1/articles/extract/preview (ohne Auth) → 401
    • POST /api/v1/dsgvo/export (ohne Service-Key) → 401
    • POST /api/v1/dsgvo/export (mit Service-Key + userId) → 200 leerer Export
  • pnpm --filter @pageta/domain test → 9/9 grün
  • pnpm --filter @pageta/web check → 0 errors / 0 warnings (252 files)
  • pnpm --filter @pageta/web build → grün, adapter-node Bundle

Was noch fehlt für „real benutzbar"

Historisch — Stand λ-6, Mai 2026. Alles in dieser Liste ist seither erledigt (Auth, Reader, Recherche-Anbindung, CI, Deploy). Sie bleibt als Protokoll stehen; wer den heutigen Stand sucht, liest die Einträge oben.

  • Echte Auth-Integration: heute localStorage['pageta.dev_token']-Stub. Migration auf @mana/shared-auth mit Auth-Portal-Redirect kommt mit λ-6 (oder mit dem Auth-Portal-Plan im Memory project_auth_portal_migration).
  • Echter Pool-Endpoint: /api/v1/feed ruft MANA_NEWS_POOL_URL/feed — zeigt heute auf localhost:3066 (managartens news-ingester). Nach Lift-B wechseln auf mana-news-pool:3079.
  • Reader-Detail-View /article/[id] mit Highlight-Selection
  • Recherche-Tab (heute Stub) braucht mana-research-Endpoints
  • CI (.github/workflows/ci.yml)
  • Deploy (docker-compose.macmini.yml + Cloudflared)

Offene Punkte

  • Port-Range knapp: 3099+3100 sind die letzten freien. Memoro/Who-Range (3100+) wird damit bewusst angekratzt — beide haben eigene Repos.
  • Encryption AUS — überholt, seit 2026-08-02 falsch. Verschlüsselt wird auf JEDEM Schreibpfad, Client wie Server (enc:1:…, fail-closed). Die geltende Fassung steht als Invariante 4 in CLAUDE.md — dort nachlesen, nicht hier.
  • shared-rss vendored: Code-Copy in apps/api/src/lib/shared-rss/. Wechsel auf Verdaccio-Paket nach Lift-A.
  • Tier-Gate: Manifest sagt tier_required: "public". Wenn Lesen Beta bleiben soll bis Mature, hier umstellen + auth.apps-Eintrag bei mana-auth.
  • Source-Liste: SOURCES_META in packages/pageta-domain/src/sources.ts muss synchron mit mana-news-pool bleiben. Heute Source-of-Truth ist managarten/services/news-ingester/src/sources.ts. Drift-Risiko bis Lift-B durch.
  • DEV-Token-Setup: kein lokaler mana-auth gestartet → man kann lokal keine Live-Calls testen. Quick-Fix: pageta.dev_token im Browser- LocalStorage von einem mana-auth-Token aus einer anderen App übernehmen. Sauber: Login-Flow gegen auth.mana.how in λ-6.