feat(admin): Abgleich zwischen Platte und Datenbank

Aether fuehrt zwei Buecher: die Bytes auf der Platte und die Eintraege in
der Datenbank. Wer Dateien von aussen hineinlegt -- per SFTP oder aus
einer Sicherung zurueckgeholt --, erzeugt nur das eine. Die Datei liegt
da, Aether weiss nichts von ihr, und der GC haelt sie nach 24 Stunden
fuer einen Rest und loescht sie.

Neu deshalb internal/rescan, die Gegenrichtung zum GC, und ein Knopf
unter Admin -> Audit. Drei Faelle:

  Datei da, kein Eintrag    Eintrag anlegen, samt Ordnerkette,
                            Pruefsumme und Dateityp
  Eintrag da, Datei fort    Eintrag entfernen, dazu Vorschaubild und
                            fruehere Fassungen
  von aussen ersetzt        Groesse und Pruefsumme uebernehmen

Zwei Schritte, nie einer: Check liest nur, Apply aendert. Ein Knopf, der
beides in einem taete, gaebe niemandem die Gelegenheit, vorher
hinzusehen -- und was hier geloescht wird, ist nicht der Papierkorb.

Nicht angefasst werden .trash/ und .versions/. Beide liegen im selben
Baum, gehoeren aber dem System: Wuerden sie uebernommen, tauchten
geloeschte Dateien wieder auf und jede fruehere Fassung wuerde zu einer
eigenen Datei.

Zwei Fallen, die erst der Praxistest zeigte:

  - Der Dateityp muss aus Endung *oder Inhalt* kommen. Beim Hochladen
    schickt der Browser ihn mit; eine per SFTP abgelegte Datei bringt
    niemanden mit, der ihn kennt. Dazu hat das Alpine-Abbild keine
    /etc/mime.types, und Gos eingebaute Liste kennt nicht einmal .txt --
    jede Textdatei waere als application/octet-stream gelandet.
  - COALESCE($1, $2) ohne Cast: Postgres haelt die Parameter dann fuer
    Text und bricht mit "operator does not exist: uuid = text" ab. Die
    Ordnerkette wurde nie angelegt.

Die Pruefsumme wird trotz des vollstaendigen Lesevorgangs berechnet. Ein
Eintrag ohne sie waere ein Eintrag, dessen Beschaedigung beim
Herunterladen niemand bemerkt -- genau die Zusage, die Aether sonst
ueberall einhaelt.

scripts/rescan-selbsttest.py mit 20 Pruefungen in fuenf Gruppen, darunter
"Pruefen aendert nichts" und "Papierkorb bleibt unangetastet". Nebenbei
raeumt der Freigabe-Selbsttest jetzt auch seinen Papierkorb und nimmt
einen eindeutigen Kontonamen je Lauf -- ein abgebrochener Lauf blockierte
sonst jeden weiteren mit 409.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-09-07 01:10:25 +02:00
1 parent fce8053d09
commit 55dcf517f2
12 files changed
+1029 -4

No files matched your search

+40
View File
@@ -507,6 +507,46 @@ hunderte pro Minute.
---
## Dateien von außen: Abgleich mit der Datenbank
Aether führt zwei Bücher: die Bytes auf der Platte und die Einträge in der
Datenbank. Normalerweise entstehen beide zusammen. Wer Dateien **von außen**
hineinlegt – per SFTP oder aus einer Sicherung zurückgeholt –, erzeugt nur
das eine: Die Datei liegt da, aber Aether weiß nichts von ihr, zeigt sie
nicht an, und die Speicherbereinigung hält sie nach 24 Stunden für einen Rest
und löscht sie.
Dagegen gibt es unter **Admin → Audit** den Knopf **Rescan storage**:
| Fall | Was der Abgleich tut |
|---|---|
| Datei da, kein Eintrag | legt den Eintrag an – samt Ordnerkette, Prüfsumme und Dateityp |
| Eintrag da, Datei fort | entfernt den Eintrag, dazu Vorschaubild und frühere Fassungen |
| Datei von außen ersetzt | übernimmt neue Größe und Prüfsumme |
**Zwei Schritte, nie einer.** *Check* liest nur und zeigt, was passieren
würde; erst *Apply* ändert etwas. Was hier gelöscht wird, ist nicht der
Papierkorb – es ist endgültig.
Was der Abgleich **nicht** anfasst: `.trash/` und `.versions/`. Beide liegen
im selben Verzeichnisbaum, gehören aber dem System. Würden sie übernommen,
tauchten gelöschte Dateien wieder auf und jede frühere Fassung würde zu einer
eigenen Datei.
### Für Sicherungen heißt das
Die Dateien liegen im Klartext unter `users/<konto>/home/<ordner>/<datei>` –
eine Wiederherstellung einzelner Dateien aus einem Datei-Backup (etwa dem
File-Restore des Proxmox Backup Servers) ist damit möglich, ohne die Datenbank
mit zurückzuspielen. Der Weg ist: **Datei zurücklegen → Rescan → Check →
Apply.** Ohne den Abgleich bliebe sie unsichtbar.
Für den umgekehrten Fall – ein Eintrag, dessen Datei aus der Sicherung
*nicht* zurückkam – zeigt derselbe Lauf die verwaisten Einträge und räumt sie
auf Wunsch weg.
---
## Kalender (CalDAV)
Adresse: `https://<deine-domain>/caldav/` – oder gar nichts eintippen und die