syncova-backup/migrations/000008_metrics.up.sql
Jerrit Fritzsche 610719c316
Some checks failed
CI / Backend (Go) (push) Failing after 3m7s
CI / Frontend (React/TypeScript) (push) Successful in 37s
CI / Sicherheitsprüfungen (push) Successful in 44s
Syncova Backups V1
Enterprise-Backup-, Recovery-, Verification-, Security- und
Monitoring-Plattform fuer Proxmox VE, Windows, Linux und Dateisysteme.

Der Leitsatz, der fast jede Entscheidung erklaert: Ein Backup gilt erst als
vertrauenswuerdig, wenn Integritaet geprueft und Wiederherstellbarkeit
nachgewiesen wurde. Deshalb steigt ein Wiederherstellungspunkt erst nach einem
tatsaechlich durchgefuehrten Restore-Test auf "recoverable", und Unbekanntes
geht in keine Bewertung als "gut" ein.

Umfang (Phasen 0-23):

- Repository Engine: inhaltsadressierte Bloecke, atomares Commit-Protokoll,
  Katalogaufbau allein aus den Manifesten — ohne Datenbank
- Backup Engine: inhaltsabhaengiges Chunking, Deduplizierung trotz
  Verschluesselung, zstd, AES-256-GCM, Streaming mit Gegendruck
- Agenten fuer Windows und Linux mit Auftragsabholung (Pull-Modell)
- Proxmox-Provider mit beiden Zugriffswegen auf die Sicherungsarchive
- Scheduler, Recovery Engine mit Pruefpunkt, Verification, Unveraenderlichkeit
- Weboberflaeche, Kennzahlen, Meldungen, Berichte, Security Center,
  Ransomware-Heuristik (meldet, handelt nie)
- Disaster Recovery, Haertung, Leistungsmessung, Chaos Testing
- Eingefrorene Vertraege fuer API, Migrationen, Backup-Format und Repository
- Auslieferungspaket fuer linux/amd64, linux/arm64 und windows/amd64

Nicht enthalten und als solches gekennzeichnet: Kapazitaetsprognose, Backup
Copy, Changed Block Tracking bei Proxmox, erweiterte Attribute und ACLs.

Gebaut, aber nie auf echter Hardware gefahren: der Windows-Dienst, die
systemd-Einheit und der verpflichtende Proxmox-Meilenstein — ob eine
wiederhergestellte VM startet, ist ungeprueft. Einzelheiten in CHANGELOG.md
und docs/release-candidate.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 09:10:54 +02:00

85 lines
3.8 KiB
SQL

-- Kennzahlen und Verlaufsreihen (Phase 13).
--
-- Der Plan verlangt zwoelf Diagramme. Zehn davon lassen sich aus Tabellen
-- bilden, die es bereits gibt: backup_job_runs traegt Dauer, Durchsatz und
-- Datenmengen jedes Laufs, backups die Groessen fuer Deduplizierung und
-- Kompression, restore_jobs und verification_jobs ihre Ergebnisse.
--
-- Diese Zahlen ein zweites Mal als Zeitreihe abzulegen waere die uebliche
-- Loesung und die schlechtere: Zwei Quellen fuer dieselbe Aussage laufen
-- auseinander, und man merkt es erst, wenn jemand nachrechnet. Aggregiert wird
-- deshalb aus den Ereignistabellen.
--
-- Diese Tabelle nimmt nur auf, was sonst **verloren geht**: Momentaufnahmen, die
-- beim naechsten Schreiben ueberschrieben werden. repositories.used_bytes ist
-- genau das — der heutige Stand, ohne jede Erinnerung an gestern.
CREATE TABLE metric_samples (
-- id ist der fortlaufende Bezeichner.
--
-- Eine Zeitreihe wird ausschliesslich angehaengt und in Zeitfenstern
-- gelesen; eine UUID braeuchte hier mehr Platz und brächte nichts.
id BIGSERIAL PRIMARY KEY,
-- metric_name benennt die Reihe.
metric_name TEXT NOT NULL,
-- subject_type benennt die Art des Gegenstands, etwa 'repository'.
subject_type TEXT NOT NULL,
-- subject_id ist der Gegenstand der Messung.
subject_id UUID NOT NULL,
-- value ist der gemessene Wert.
--
-- DOUBLE PRECISION statt BIGINT: Die Reihe nimmt auch Verhaeltnisse und
-- Prozentwerte auf, und ein zweiter Wertetyp je Reihe waere eine Fallgrube.
value DOUBLE PRECISION NOT NULL,
-- unit ist die Einheit des Werts.
--
-- Sie steht an der Messung und nicht in einer Tabelle daneben: Wer eine
-- Reihe liest, soll nicht raten muessen, ob 400 Bytes, Kilobytes oder
-- Prozent meint.
unit TEXT NOT NULL,
-- measured_at ist der Zeitpunkt der Messung in UTC.
measured_at TIMESTAMPTZ NOT NULL DEFAULT now(),
-- NaN und Unendlich werden abgelehnt.
--
-- Ein einziger solcher Wert verseucht jede Summe und jeden Durchschnitt der
-- Reihe — das Ergebnis ist danach selbst NaN, ohne dass irgendwo ein Fehler
-- auftaucht. Aus einer geteilten Null wird so eine Kurve, die nichts mehr
-- aussagt.
--
-- Die Pruefung ist ausdruecklich `value <> 'NaN'` und **nicht** das uebliche
-- `value = value`: PostgreSQL wertet `NaN = NaN` als wahr, anders als
-- IEEE 754. Der Standardtrick greift hier also nicht — real geprueft.
CONSTRAINT metric_samples_value_finite CHECK (
value <> 'NaN'::float8
AND value <> 'Infinity'::float8
AND value <> '-Infinity'::float8
)
);
-- Der Zugriff erfolgt immer als „diese Reihe, dieser Gegenstand, dieses
-- Zeitfenster". Der Index bildet genau das ab.
CREATE INDEX metric_samples_series_idx
ON metric_samples (metric_name, subject_id, measured_at DESC);
-- Fuer das Aufraeumen alter Messungen.
CREATE INDEX metric_samples_age_idx ON metric_samples (measured_at);
-- Zwei Messungen derselben Reihe zum selben Zeitpunkt sind eine Doppelung. Sie
-- entstuende, wenn zwei Control-Server gleichzeitig sammeln — und verfaelschte
-- jede Summe.
CREATE UNIQUE INDEX metric_samples_unique_idx
ON metric_samples (metric_name, subject_id, measured_at);
-- ---------------------------------------------------------------------------
-- Repositories: Zeitpunkt der letzten Erfassung
-- ---------------------------------------------------------------------------
ALTER TABLE repositories
-- metrics_collected_at ist der Zeitpunkt der letzten Kennzahlenerfassung.
--
-- Getrennt von last_checked_at: Das eine ist eine Zustandspruefung, das
-- andere eine Messung. Ein Repository kann erreichbar sein, ohne dass
-- jemand seinen Fuellstand notiert hat.
ADD COLUMN metrics_collected_at TIMESTAMPTZ;