Files
maarcadetweet/README.md
T
tomdeboneandClaude Opus 5 f7b78fd5db docs: Auth-Abschnitt, korrigierte Test-Anleitung, Phase 9
deployment.md bekommt einen eigenen Abschnitt zur Authentifizierung
(Schlüsselweg, geschützte Endpoints, Fehlercodes, der Schalter für
VPN-Instanzen) und eine CORS-Beschreibung, die die Allowlist statt des
alten Wildcards erklärt — inklusive der Tauri-Origins, die sonst am
Preflight scheitern.

Im README steht jetzt der Hinweis, der diese Runde am meisten gekostet
hat: ohne DATABASE_URL_APPVIEW in der Umgebung überspringen sich die
DB-Tests selbst und `cargo test --workspace` meldet grün, ohne sie
ausgeführt zu haben.

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

122 lines
6.6 KiB
Markdown

# 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
```bash
# 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`](docs/tauri-release.md)) |
| 8 Social-Graph + Benachrichtigungen | ✅ done — `notifications`-Tabelle, Schreibpfad im Jetstream-Indexer (idempotent, keine Selbst-Notifications), `/api/notifications[/count|/seen]`, `/api/followers`, `/api/following`, eigene `/api/thread`-Route; im Client Notifications-View mit Unread-Badge und klickbare Follower-/Following-Listen im Profil |
| 9 Auth + Performance | ✅ done — AppView prüft Bearer-Tokens (ES256, Schlüssel aus dem neuen `/.well-known/did.json` der PDS, fail closed); Timeline und Notifications nur noch für die eigene DID; CORS-Allowlist statt `Any`; Indizes für Handle-Lookup und Cold-Start-Feed |
## Tests
```bash
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 Tests sind *fail-open*: **ohne `DATABASE_URL_APPVIEW` in der
Umgebung überspringen sie sich selbst** und melden das nur auf stderr. `cargo test
--workspace` in einer nackten Shell meldet dann grün, ohne sie ausgeführt zu haben —
für einen aussagekräftigen Lauf `set -a; . ./.env; set +a` voranstellen und PDS +
AppView laufen lassen.
* Läuft die Auth (Default), holen sich die Integrationstests echte Tokens von der PDS
bzw. signieren sie aus `PDS_JWT_SECRET`; ohne erreichbare PDS überspringen sie.
`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`](docs/architecture.md) | Crate-Verantwortlichkeiten, Datenfluss PDS → Jetstream → AppView → Client, Tabellenübersicht |
| [`docs/deployment.md`](docs/deployment.md) | Betrieb: docker compose, Migrationen, alle Env-Variablen, Release-Build, systemd-Units, Reverse-Proxy, Health-Checks |
| [`docs/tauri-release.md`](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`.
* `aud` wird beim Token-Check nicht validiert (Signatur, Ablauf, `scope` und
`sub` schon).
* 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.
## 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`).