feat: Verlauf -- wer hat wann was abgelegt, ersetzt oder geloescht
Neuer Reiter, und dahinter eine eigene Tabelle. WARUM NICHT EINFACH
media.created_at -- drei Gruende, jeder allein wuerde reichen:
1. media kennt nur den JETZIGEN Stand. Was geloescht wurde, ist weg, samt
der Frage, wer es geloescht hat.
2. Ein Ueberschreiben hebt updated_at an und ueberschreibt damit die
Auskunft, wann die Datei urspruenglich kam.
3. media.token_id ist beim Upload aus dem Dashboard NULL -- dort hat niemand
einen Token, sondern eine Sitzung. Das "von wem" stand also nirgends.
Das ist NICHT das Logging, das die ROADMAP ablehnt: dort geht es um
Anfrage-Protokolle samt ClickHouse. Hier sind es ein paar Zeilen je Upload in
derselben SQLite-Datei, und nach einem halben Jahr raeumt pruneEvents auf.
DER VERLAUF STARTET NICHT LEER. Beim ersten Start wird er aus dem Bestand
nachgetragen (68 Eintraege) -- ein Tab, der am ersten Tag leer ist, obwohl 68
Bilder in der Ablage liegen, sieht aus wie ein kaputter Tab. Die nachgetragenen
Eintraege sind als solche gekennzeichnet: Zeitpunkt stimmt, Urheber steht als
"vor der Aufzeichnung", weil ihn niemand mehr kennt. Die Oberflaeche sagt das
unter der Tabelle, statt es zu verschweigen.
logEvent wirft nie: ein Verlauf, der einen Upload scheitern laesst, waere die
Buchhaltung, die das Geschaeft verhindert.
Nachgemessen: Upload, Ersetzen und Loeschen aus dem Dashboard erscheinen als
user:admin, die Uploads des Fotostudios als token:d4rk_photostudio; beim
Loeschen wird die Groesse VOR dem Loeschen geholt, sonst stuende dort nichts.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -147,6 +147,28 @@ export type Folders = {
|
||||
wurzel: { files: number; bytes: number }
|
||||
}
|
||||
|
||||
export type EventKind = 'upload' | 'replace' | 'delete'
|
||||
|
||||
export type MediaEvent = {
|
||||
id: number
|
||||
at: number
|
||||
kind: EventKind
|
||||
path: string
|
||||
size: number | null
|
||||
actor_kind: 'token' | 'user' | 'unbekannt'
|
||||
actor: string
|
||||
}
|
||||
|
||||
export type EventsSeite = {
|
||||
total: number
|
||||
limit: number
|
||||
offset: number
|
||||
items: MediaEvent[]
|
||||
akteure: { actor: string; actor_kind: string; n: number; zuletzt: number }[]
|
||||
/** Ab wann aufgezeichnet wird — null, solange nichts drinsteht. */
|
||||
seit: number | null
|
||||
}
|
||||
|
||||
export type UploadErgebnis = {
|
||||
name: string
|
||||
ok: boolean
|
||||
@@ -190,6 +212,12 @@ export const api = {
|
||||
deleteMediaBulk: (ids: number[]) =>
|
||||
post<{ deleted: string[]; count: number }>('/api/dash/media/delete', { ids }),
|
||||
|
||||
events: (kind: string, actor: string, limit: number, offset: number) =>
|
||||
get<EventsSeite>(
|
||||
`/api/dash/events?kind=${encodeURIComponent(kind)}` +
|
||||
`&actor=${encodeURIComponent(actor)}&limit=${limit}&offset=${offset}`,
|
||||
),
|
||||
|
||||
stats: () => get<Stats>('/api/dash/stats'),
|
||||
thumbsNachziehen: () => post<ThumbLauf>('/api/dash/maintenance/thumbs'),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user