tomdeboneandClaude Opus 5 ec8fe187fe docs: Deployment-, Architektur- und Release-Doku; README aktualisiert
docs/ war leer. Jetzt drei Dateien, jede Behauptung am Code verifiziert:

* deployment.md — docker compose, Migrationsweg, vollständige Env-Referenz
  mit den Fallstricken (P-256-taugliches PDS_JWT_SECRET, Pflicht-aber-tot
  S3_BUCKET_APPVIEW), Release-Build, systemd-Units, Reverse-Proxy inkl. des
  Hinweises, dass die AppView CORS Any liefert und der Proxy den Header
  ersetzen statt ergänzen muss, Health-Checks und Cursor-Verhalten beim
  Neustart.
* architecture.md — Crate-Verantwortlichkeiten, ASCII-Datenfluss, beide
  DB-Schemata. Hält fest, was die Topologie erklärt: die eigene PDS speist
  keinen Firehose, eigene Records erreichen die AppView nur über den
  Best-Effort-Push.
* tauri-release.md — Signing-Keys, v2-Updater-Config, latest.json, Build pro
  Plattform. Der _comment in tauri.conf.json war irreführend: active/dialog
  sind v1-Reste, die der v2-Updater ignoriert; dass nichts passiert, liegt
  daran, dass niemand check() aufruft und das Plugin nicht installiert ist.

README bekommt Phase 8, eine Doku-Übersicht, korrigierte Testanleitung
(src-tauri ist ein eigener Workspace und wird von cargo test --workspace
nicht erfasst) und einen Abschnitt "Bekannte Lücken" statt der bisher
lückenlosen Erfolgsmeldung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013HC9HLrUU1LNwkzp8nkDLX
2026-09-09 21:37:12 +02:00

maarcadetweet

AT-Protocol-PDS in Rust + AppView + Tauri/Svelte-Desktop-Client. Posts sind auf 160 Zeichen limitiert (oldschool Twitter), erzwungen durch eigenes Lexicon app.twi.post.

Architektur

crates/
├── at-lexicon/    Lexicon-Schemas + 160-Char-Validierung
├── at-crypto/     k256, p256, CID, multibase, JWT, PLC-Ops, Repo-Signing
├── at-identity/   DID, PLC, Handle-Resolution
├── at-mst/        Merkle-Search-Tree
├── at-repo/       Repos, Commits, Blöcke, TID-Revs
├── at-blob/       S3-kompatibler Blob-Store (MinIO) + In-Memory-Store
├── at-firehose/   Jetstream-Consumer (WebSocket)
├── at-shared/     Config, Errors, DID, Cursor
├── pds-server/    axum HTTP PDS (bin)
└── appview/       Jetstream-Indexer + REST-API (bin)

crates/tauri-app/       Tauri 2 + Svelte 5 + Vite + TS Desktop-Client
  ├── src/              Svelte-Components (Terminal, StatusBar, NavRail, PostCard, ComposeBox,
  │                     LoginScreen, ProfileView, NotificationsView)
  ├── src/lib/styles/   tokens.css (1:1 vom maarcade-Design)
  └── src-tauri/        Rust-IPC-Layer

lexicons/app/twi/post.json     Custom Lexicon mit maxLength: 160
migrations/pds/                PDS-DB-Schema (users, repos, blobs, sessions, plc_ops)
migrations/appview/            AppView-DB-Schema (posts, likes, follows, notifications, profiles, jetstream_cursor)
docs/                          Deployment, Architektur, Tauri-Release (siehe unten)

Setup

# 1) Datenbanken + MinIO starten
docker compose up -d

# 2) Umgebungsvariablen — beide Binaries laden .env selbst (dotenvy).
#    PDS_JWT_SECRET muss Hex sein: openssl rand -hex 32
cp .env.example .env

# 3) Workspace kompilieren + Tests
cargo test --workspace
cargo check --workspace

# 4) Tauri-Frontend (Vite dev)
cd crates/tauri-app
npm install
npm run dev
# → http://127.0.0.1:1420

# 5) PDS / AppView (eigene Terminals)
cargo run -p pds-server
cargo run -p appview

Status

Phase Stand
0 Foundation, Workspace, Migrations, Lexicon, Crypto done
1 Identity (PLC-Ops vollständig signieren) done — did:plc: deterministisch aus signed op CID
2 MST + Repo (Spec-konforme CBOR-Encoding) done — encode_key = base64url(sha256(raw_key)) per atproto-Spec, split_around/wrap_with_split threaden den recursive right_sub korrekt als k_tree weiter. 27 MST + 13 Repo + 4 Commit Tests grün.
3 PDS-Server (com.atproto.* XRPC) done — createAccount/Session/Refresh, createRecord/deleteRecord, like/repost, follow
4 AppView-Foundation (Jetstream-Index) done — Jetstream-Indexer + identity-Event-Backfill + PLC-handle-sync-Worker
5 AppView-REST-API done — timeline, profile (by-did + by-handle), search, post-by-uri, thread, notifications, followers/following
6 Tauri-UI-Logik an Backend koppeln done — LoginScreen, NavRail, PostCard, ComposeBox, Profile/Compose/Search/Settings-Views
7 Polish (Tray, Notifications, Auto-Update) done — Tray-Icon custom (tauri::include_image!), Notification-Click navigiert via app://notification-Event + openThread-Helper zu Thread-Detail, Auto-Update in Dev inert (Production-Weg: docs/tauri-release.md)
8 Social-Graph + Benachrichtigungen done — notifications-Tabelle, Schreibpfad im Jetstream-Indexer (idempotent, keine Selbst-Notifications), `/api/notifications[/count

Tests

cargo test --workspace                     # Rust: PDS, AppView, at-* Crates
cd crates/tauri-app && npx vitest run      # Svelte/TS
cd crates/tauri-app/src-tauri && cargo test # Tauri-IPC (eigener Workspace!)

Stand zuletzt gegen den lokalen Dev-Stack (docker compose + laufender PDS + AppView): Rust-Workspace grün (u.a. 27 MST, 24 PDS-Integration, 49 AppView-Lib, 14 AppView-Integration), Frontend grün. Zwei Vorbehalte:

  • Die DB-gestützten Integrationstests sind fail-open — ohne erreichbare Postgres/PDS überspringen sie sich selbst und melden das nur auf stderr. Ein grüner Lauf ohne laufenden Stack sagt also weniger, als er aussieht.
  • Einige Tests hängen am Zustand der Dev-Datenbank; auf einer frischen DB können handle_sync-Tests abweichen. Wer sie ernst nimmt, prüft sie gegen eine definierte DB.

crates/tauri-app/src-tauri hat ein eigenes [workspace] und ist nicht Teil des Root-Workspace; cargo test --workspace von oben erfasst den IPC-Layer nicht.

Dokumentation

Datei Inhalt
docs/architecture.md Crate-Verantwortlichkeiten, Datenfluss PDS → Jetstream → AppView → Client, Tabellenübersicht
docs/deployment.md Betrieb: docker compose, Migrationen, alle Env-Variablen, Release-Build, systemd-Units, Reverse-Proxy, Health-Checks
docs/tauri-release.md Signing-Keys, Updater-Config, latest.json, Build pro Plattform, Artefaktpfade

Bekannte Lücken

  • Die eigene PDS speist keinen Firehose (com.atproto.sync.subscribeRepos fehlt) — eigene Records erreichen die AppView nur über den Best-Effort-Push POST /internal/ingest-commit.
  • Die AppView-Leseschnittstelle hat keine Auth und CORS Any; bei /api/notifications sind das erstmals halbwegs private Daten.
  • Notifications werden nie gelöscht: Unlike/Unfollow lässt die Zeile stehen, und der Dedupe-Key macht sie „einmal pro (Empfänger, Autor, Art, Subject) für immer".
  • Auto-Update ist nur dokumentiert, nicht verdrahtet: niemand ruft check() auf, das Updater-Plugin ist nicht installiert (siehe docs/tauri-release.md).
  • Reply-Notifications gehen verloren, wenn die Antwort vor ihrem Parent indiziert wird (kein Nachlauf) — bei Jetstream möglich.
  • at-blob spricht MinIO ohne Signature V4 — echtes AWS S3 funktioniert damit nicht.
  • Die PDS liefert kein .well-known/did.json; describeServer gibt die DID hart als did:web:pds.maarcadetweet.local zurück.

Design

Orange Akzent, IBM Plex Mono, schwarzer Hintergrund mit 3%-Grid, Terminal-Fenster-Component mit blinkendem Cursor. Tokens sind 1:1 von maarcade-shell/landing/assets/css/tokens.css abgeleitet, plus zwei neue Repos-Tokens (--cid-fg, --rev-fg).

S
Description
AT Protocol PDS + AppView + Tauri Desktop Client (160-char posts). Maarcade design.
Readme
1.9 MiB
Languages
Rust 80.6%
Svelte 11.6%
TypeScript 7.2%
PLpgSQL 0.3%
CSS 0.3%