Append-only who/what/when trail for admin actions + scheduler run summaries, generalizing QuotaEvent. Logged at ACTION / run-summary granularity — never per-row (a scheduler run touching thousands of videos is ONE row). Backend: - migration 0054_audit_log + AuditLog model (actor_id FK SET NULL, action, target_type/id, summary, before/after JSON, created_at). - app/audit.py: AuditAction constants (single source of truth, i18n'd on the client) + record() (adds to the caller's txn) + gc(retention_days). - producers wired: role change / suspend / delete / invite approve-deny-add / demo add-remove-reset / discovery purge (admin.py); config set/reset — secret VALUES never logged, key only (config.py); scheduler interval + maintenance tune (scheduler routes); sync pause/resume (sync.py); and the scheduler _job() choke point writes ONE run-summary row per run — manual runs + errors always, automatic runs only when they changed something (no no-op-poll spam). - retention: audit_gc scheduler job prunes rows older than audit_retention_days (sysconfig, default 180; 0 = keep forever). - admin API routes/audit.py (/api/admin/audit): recent-window list (actor emails resolved, System for background) + clear (leaves one tamper-evidence row). Frontend: - new admin-only "Audit log" nav page (ScrollText) using the shared DataTable (first admin page to reuse it) — sort/filter/paginate/persist, action select filter, actor text filter, before→after detail, Clear-all with confirm. - AuditLog.tsx + auditColumns.tsx + api.adminAudit/clearAudit + AuditRow type. - trilingual audit + auditActions namespaces (HU/EN/DE) + nav + config-group + scheduler job labels; Audit config group (retention days).
55 lines
2 KiB
JSON
55 lines
2 KiB
JSON
{
|
|
"feed": "Feed",
|
|
"searchPlaceholder": "Deine Abos durchsuchen…",
|
|
"clearSearch": "Suche löschen",
|
|
"searchYoutube": "Auf YouTube suchen",
|
|
"searchYoutubeTip": "Live auf YouTube nach diesem Begriff suchen (verbraucht gemeinsames API-Kontingent). Du kannst auch Enter drücken.",
|
|
"channelManager": "Kanalverwaltung",
|
|
"usageStats": "Nutzung & Statistik",
|
|
"scheduler": "Planer",
|
|
"configuration": "Konfiguration",
|
|
"users": "Benutzer",
|
|
"scope": {
|
|
"label": "Feed-Quelle",
|
|
"my": "Meine",
|
|
"myTip": "Nur Videos aus deinen eigenen Abos",
|
|
"all": "Bibliothek",
|
|
"allTip": "Alle Videos im gemeinsamen Katalog"
|
|
},
|
|
"account": {
|
|
"admin": "Admin",
|
|
"feed": "Feed",
|
|
"channels": "Kanäle",
|
|
"playlists": "Wiedergabelisten",
|
|
"stats": "Statistik",
|
|
"scheduler": "Planer",
|
|
"config": "Konfiguration",
|
|
"users": "Benutzer",
|
|
"settings": "Einstellungen",
|
|
"about": "Über",
|
|
"signOut": "Abmelden",
|
|
"addAccount": "Weiteres Konto hinzufügen",
|
|
"switchTo": "Zu {{name}} wechseln",
|
|
"audit": "Audit-Protokoll"
|
|
},
|
|
"sync": {
|
|
"yours": "deine",
|
|
"total": "gesamt",
|
|
"countTooltip": "Videos aus deinen Abos im Vergleich zur Gesamtzahl im gemeinsamen Katalog, den die Abos aller Nutzer gefüllt haben.",
|
|
"paused": "pausiert",
|
|
"syncing": "{{count}} werden synchronisiert",
|
|
"backfillingHistory": "Verlauf wird geladen",
|
|
"working": "Synchronisierung…",
|
|
"recentQueued": "{{count}} in Warteschlange",
|
|
"allSynced": "alles synchronisiert",
|
|
"withoutFullHistory": "{{count}} ohne vollständigen Verlauf",
|
|
"fullHistoryTooltip": "Einige deiner Kanäle haben nur ihre neuesten Uploads. Klicke, um die Kanalverwaltung (auf diese gefiltert) zu öffnen und ihren vollständigen Katalog anzufordern.",
|
|
"pause": "Hintergrund-Synchronisierung pausieren",
|
|
"resume": "Hintergrund-Synchronisierung fortsetzen"
|
|
},
|
|
"banner": {
|
|
"updated": "Aktualisiert auf v{{version}} — sieh, was sich geändert hat.",
|
|
"releaseNotes": "Versionshinweise",
|
|
"dismiss": "Schließen"
|
|
}
|
|
}
|