syncova-backup/packages/reports/format.go
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

83 lines
2.3 KiB
Go

package reports
import (
"fmt"
"strconv"
"strings"
"time"
)
// FormatBytes stellt eine Datenmenge lesbar dar.
//
// Binaerpraefixe, weil Speicher so verkauft und angezeigt wird und ein Bericht
// nicht gegen die Anzeige des Betriebssystems arbeiten soll.
func FormatBytes(byteCount float64) string {
const unitStep = 1024.0
if byteCount < unitStep {
return fmt.Sprintf("%.0f B", byteCount)
}
unitNames := []string{"KiB", "MiB", "GiB", "TiB", "PiB"}
scaledValue := byteCount / unitStep
for _, unitName := range unitNames {
if scaledValue < unitStep {
return fmt.Sprintf("%.1f %s", scaledValue, unitName)
}
scaledValue /= unitStep
}
return fmt.Sprintf("%.1f EiB", scaledValue)
}
// FormatDuration stellt eine Dauer in Sekunden lesbar dar.
func FormatDuration(seconds float64) string {
if seconds < 1 {
return fmt.Sprintf("%.0f ms", seconds*1000)
}
wholeDuration := time.Duration(seconds * float64(time.Second))
switch {
case wholeDuration < time.Minute:
return fmt.Sprintf("%.1f s", seconds)
case wholeDuration < time.Hour:
return fmt.Sprintf("%d min %d s", int(wholeDuration.Minutes()),
int(wholeDuration.Seconds())%60)
case wholeDuration < 24*time.Hour:
return fmt.Sprintf("%d h %d min", int(wholeDuration.Hours()),
int(wholeDuration.Minutes())%60)
default:
return fmt.Sprintf("%d Tage %d h", int(wholeDuration.Hours())/24,
int(wholeDuration.Hours())%24)
}
}
// FormatPercent stellt einen Anteil dar.
//
// Ein kleiner Wert wird als „< 0,1 %" ausgewiesen, nicht als „0,0 %": Null
// Prozent liest sich wie „nichts vorhanden" — dieselbe Regel wie in der
// Uebersicht (Phase 12).
func FormatPercent(percentValue float64) string {
if percentValue > 0 && percentValue < 0.1 {
return "< 0,1 %"
}
return strings.Replace(fmt.Sprintf("%.1f %%", percentValue), ".", ",", 1)
}
// FormatTimestamp stellt einen Zeitpunkt in UTC dar.
//
// Immer mit ausgeschriebener Zeitzone: Ein Bericht wandert zwischen Standorten,
// und „14:00" ohne Zone hat je nach Leser drei Bedeutungen.
func FormatTimestamp(pointInTime time.Time) string {
return pointInTime.UTC().Format("2006-01-02 15:04:05 UTC")
}
// trimNumber stellt eine Zahl ohne ueberfluessige Nachkommastellen dar.
func trimNumber(numericValue float64) string {
return strconv.FormatFloat(numericValue, 'f', -1, 64)
}