feat(aether): initial commit – self-hosted Cloud, Phasen 1–7

Go-Backend (chi, pgx, golang-migrate) + React/TS-Frontend als PWA.
Enthalten: Auth inkl. OIDC, Dateien mit Versionen und Papierkorb,
Freigaben (Links + intern), WebDAV, Gruppenordner, Admin/Theming,
Volltextsuche mit OCR, eigener PDF-Betrachter und WOPI-Office
(Collabora/OnlyOffice).

Nicht im Repo: deploy/.env (Sitzungsschlüssel, DB- und Admin-Passwort)
sowie alle Daten- und Build-Verzeichnisse – siehe .gitignore.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Opus 5 committed 2026-08-24 09:25:36 +02:00
commit 31a027c93a
225 files changed
+38042

No files matched your search

+165
View File
@@ -0,0 +1,165 @@
# Aether – Projektkonventionen für Claude Code
## Projekt-Überblick
Self-hosted Cloud-Alternative zu Nextcloud. Go-Backend + React-Frontend, modularer Monolith.
Projektplan: `cloud-projekt-plan.md`
## Monorepo-Struktur
```
aether/
├── backend/ # Go – modularer Monolith
│ ├── cmd/aether/ # main.go – Einstiegspunkt
│ ├── internal/ # Domänen-Pakete (nie von außen importieren)
│ │ ├── auth/ # Login, Sessions, CSRF, Argon2id, OIDC-User-Anlage
│ │ ├── storage/ # Storage-Interface + LocalFS (atomar, SHA-256)
│ │ ├── files/ # Datei-/Ordner-CRUD, Trash, Versionen, Favoriten
│ │ ├── sharing/ # Öffentliche Share-Links
│ │ ├── admin/ # Admin-Panel: User, Gruppen(-mitgliedschaft), Settings/Theming
│ │ ├── oidc/ # OIDC-Login (optional, via .env)
│ │ ├── webdav/ # WebDAV-Endpoint /dav/ (Basic Auth – nur App-Passwörter)
│ │ ├── acl/ # Interne Freigaben an User/Gruppen (Rechteauflösung)
│ │ ├── audit/ # Audit-Log (Schreibpfad; Endpunkte liegen in admin/)
│ │ ├── gc/ # Blob-GC: Platte gegen DB abgleichen
│ │ ├── thumbnails/ # Vorschaubild-Generierung
│ │ ├── groups/ # LEERER STUB – Gruppenordner liegen in files/groupfolder.go
│ │ ├── documents/ # Volltext: OCR-Warteschlange + Arbeiter (Phase 6, Teil 1)
│ │ ├── tags/ # Ordnungsmerkmale einer Datei: Etiketten, Belegdatum, Absender
│ │ └── office/ # WOPI-Host: Collabora/OnlyOffice, ein Adapter fuer beide
│ ├── db/migrations/ # SQL-Migrations – Spiegelkopie (siehe Migrations-Regeln!)
│ └── pkg/ # Hilfspakete: config, middleware, response, db (embed migrations)
├── frontend/ # React + TS + Vite + Tailwind
│ └── src/
│ ├── components/
│ ├── pages/
│ ├── api/ # Typed API-Client
│ └── hooks/
├── deploy/ # Docker Compose, Dockerfile, .env.example
└── CLAUDE.md
```
## Backend-Konventionen (Go)
- **Module-Pfad**: `aether`
- **Go-Version**: 1.25 (siehe `go.mod`)
- **Router**: `github.com/go-chi/chi/v5`
- **DB-Treiber**: `github.com/jackc/pgx/v5` (pgxpool für Connection-Pool)
- **Migrations**: `github.com/golang-migrate/migrate/v4`
- **Logging**: `github.com/rs/zerolog` – strukturiert, immer mit Kontext (`log.Ctx(ctx)`)
- **Hashing**: `golang.org/x/crypto/argon2` (Argon2id) – App-Passwörter dagegen SHA-256 (zufälliges Token, jeder WebDAV-Request authentifiziert einzeln)
- **Sessions**: `github.com/gorilla/sessions` mit securecookie
### Paket-Regeln
- Alle Domänen-Pakete unter `internal/` – kein Import von außen
- Keine zirkulären Abhängigkeiten; Dependency-Richtung: `cmd → internal/* → pkg/*`
- Handler in `internal/<domain>/handler.go`, Business-Logic in `internal/<domain>/service.go`, DB in `internal/<domain>/store.go`
- Interfaces für alle externen Abhängigkeiten (Storage, DB) → leicht mockbar
### Code-Stil
- `gofmt` + `goimports` – immer formatiert
- Fehler nie ignorieren (`_`), immer wrappen mit `fmt.Errorf("context: %w", err)`
- Keine Magic-Numbers – Konstanten mit sprechenden Namen
- HTTP-Handler signieren: `func (h *Handler) MethodName(w http.ResponseWriter, r *http.Request)`
- Middleware-Chain: Auth → CSRF → RateLimit → Handler
### Tests
- Testdatei neben der Quelldatei: `auth_test.go` neben `auth.go`
- Integrationstests mit echtem Postgres via `testcontainers-go`
- Pflicht-Tests: Path-Traversal, Upload-Abbruch, Checksum-Verifikation, Soft-Delete-Recovery
- `go test ./...` muss grün sein vor jedem Commit
## Frontend-Konventionen (React + TS)
- **Bundler**: Vite
- **Styling**: Tailwind CSS + CSS-Variablen für Design-Tokens
- **Testing**: Vitest + Testing Library; E2E: Playwright
- **API-Client**: typed fetch-Wrapper unter `src/api/`
### Design-Tokens (CSS-Variablen)
Alle Farben laufen über CSS-Custom-Properties:
```css
:root {
--color-primary: ...;
--color-accent: ...;
--color-background: ...;
--color-surface: ...;
--color-text: ...;
}
```
Admin setzt globale Tokens; User-Override nur für eigene Palette (Scope: `[data-user-theme]`).
### Komponenten-Regeln
- Komponenten in `PascalCase.tsx`
- Kein `dangerouslySetInnerHTML` mit User-Input (XSS)
- API-Calls nur über `src/api/`-Funktionen, nie direkt `fetch` in Komponenten
## Sicherheits-Pflichten
- Path-Traversal: jeden Dateipfad kanonisieren und gegen Storage-Root prüfen
- CSRF: Double-Submit-Cookie oder synchronizer-Token
- Rate-Limiting: Login-Endpunkt + Admin-Login strenger
- Auth-Check: jede Route serverseitig prüfen – nie Frontend vertrauen
- SQL: ausschließlich parametrisierte Queries (pgx unterstützt das nativ)
- Uploads: außerhalb Webroot, keine ausführbaren Rechte, MIME-Prüfung
- WebDAV: **nur App-Passwörter**, nie das Kontopasswort – es ist zugleich der Admin-Zugang
- Kein Zugriff auf fremde IDs → `404`, nicht `403`: sonst verrät die Antwort die Existenz
- Listen und Suche schneiden den erreichbaren Bereich **in der Abfrage** zu, nie nachträglich im Handler
- Hochgeladene Dateien nur für eine Positivliste harmloser Typen `inline` ausliefern (sonst läuft fremdes HTML im eigenen Ursprung)
## Datenintegrität (nicht verhandelbar)
1. **Atomares Schreiben**: Temp-Datei → `fsync` → `rename`. Niemals in-place.
2. **SHA-256**: beim Upload berechnen + in DB; beim Download verifizieren.
3. **Soft-Delete only**: kein hartes Löschen. Bytes erst per GC entfernen.
4. **DB-Commit nach Blob-Write**: Metadaten erst committen, wenn Blob erfolgreich.
## Migrations-Regeln
- Dateien: `000001_init.up.sql` / `000001_init.down.sql`
- **Jede Migration in BEIDE Verzeichnisse legen:** `backend/pkg/db/migrations/` (wird ins Binary embedded und beim Start ausgeführt) UND `backend/db/migrations/` (Spiegelkopie). Beide müssen identisch sein.
- Keine destruktiven Änderungen ohne explizites Down-Migration
- Migration beim App-Start automatisch ausführen (via `migrate.Up()`)
- Aktueller Stand: bis `000018_tag_icons` (Emoji an Etiketten und Absendern)
## Commit-Regeln
Format: `<typ>(<scope>): <kurze Beschreibung>`
Typen: `feat`, `fix`, `test`, `refactor`, `docs`, `chore`, `security`
Beispiele:
- `feat(auth): add argon2id password hashing`
- `test(storage): add checksum verification test`
- `security(admin): enforce server-side admin check on all routes`
Kein Commit ohne grüne Tests.
## Reverse Proxy & Proxy-Awareness
- **Kein Proxy-Container** in docker-compose.yml – TLS und Domain gehören zum Wirt,
nicht ins Projekt. Nichts hier soll einen mitgelieferten Proxy voraussetzen.
- App lauscht auf reinem HTTP (`APP_LISTEN_ADDR`). TLS = externer Proxy.
- `X-Forwarded-For` / `X-Forwarded-Proto` werden **nur** von `TRUSTED_PROXIES` (IPs/CIDRs) akzeptiert.
- Echte Client-IP immer über `middleware.RealIP(r)` abrufen – niemals `r.RemoteAddr` direkt.
- `Secure`-Cookie-Flag: über `middleware.IsHTTPS(r)` setzen (berücksichtigt Forwarded-Proto).
- `PUBLIC_URL` für OIDC-Redirects, WOPI-Callbacks und Share-Links verwenden.
- HSTS gehört auf den Edge-Proxy, **nicht** in die App-Header.
## Docker & Secrets
- **Backend immer via Docker starten/laufen lassen (`docker compose ...` in `deploy/`), nie `go run`.** Der Host hat kein Go-Toolchain installiert; Builds/Compile-Checks laufen über das `golang:1.25-alpine`-Image. Migrations + DB-Verbindung sind auf die Compose-Umgebung ausgelegt.
- Secrets **nur** über `.env` / Compose-Env – nie im Image oder Repo
- Multi-Stage-Build: Builder-Stage (Go-Compiler) → Alpine final
- `.env` ist in `.gitignore`; `.env.example` zeigt alle Keys ohne Werte
## Phasen-Stopp
Nach Phase 1: **STOPP** – Zusammenfassung + Phase-2-Vorschlag, erst nach OK weitermachen.