Detailed admin audit log
GET /api/admin/audit and the Socket.IO event audit_new_entry return the same entry format. The server records successful changes; there is no API for clients to append arbitrary entries. Access and retention rules are unchanged.
API format
{
id: 123,
adminId: '…', adminLogin: 'editor',
operationType: 'edit_song_lyrics',
createdAt: 1790000000000, // Unix milliseconds
data: {
title: 'Song', artist: 'Artist',
action: 'update', // lyrics: update | clear | offset
details: { // optional, version 1
version: 1,
changes: [
{ field: 'lyrics', before: 'Old lyrics', after: 'New lyrics' },
{ field: 'lyricsStatus', before: 'plain', after: 'synced' },
{ field: 'offset', before: 0, after: -1.5 }
],
info: { source: 'bulk', force: false }
}
}
}changes contains changed fields only; info contains operation context. Values may be strings, numbers, booleans, arrays, or null for absent values. failureReason may contain a localized message object. Field identifiers and enum values are independent of language; clients translate their presentation.
The UI offers ▼/▲ only when details exist, preserves lyrics line breaks and timecodes, and gives long blocks their own scrollbar. Old entries without details remain readable. Clients should fall back to the operation identifier for unknown operation types.
Operations and details
edit_song_lyrics:lyrics,lyricsStatus(none,plain,synced),offsetin seconds. Clearing lyrics and offset-only edits have distinct labels. Also coversPUT /api/admin/lyrics/cacheandDELETE /api/admin/lyrics/cache.edit_song_meta: changedtitle,artist,album,year. Moving a song includesmovedFromandmovedTo(day/night) indata.settings_save: one entry per save, with changed sections indata.sections. Paths includebranding.byLang.uk.dayRadioName,branding.telegram_url,generation.MAX_DAY_DURATION,generation.GROUP_DEFS.A,radioHosts.backgroundMusicMode, andartistArts.dayEnabled. Object key ordering is ignored. Artist arrays show previous/new membership and added/removed members. Jingles and phrases have their own display groups. Broadcast duration is stored in seconds, guest session durations in minutes. Selected phrases include their filenames when available.- Donation settings use
settings_savewithsections: ['donations']:currency,pricingMode,fixedPrice,pricePerSecond,tiersEnabled,tierCeiling,blockDonationsWhileChatting.info.clampedrecords automatic adjustment to the payment provider's tier ceiling limit. group_create: name, mode and songs ininfo.group_edit: changes to name, mode, membership and song order.group_delete: group name.group_insert: name, actual count and actual insertion order. Song labels contain title, artist and ID to distinguish otherwise identical records.admin_create: initial privileges.admin_privileges:privilegesAddedandprivilegesRemovedininfo.admin_login_change: previous/newlogin.admin_password_resetidentifies password resets; changing one's own password, activation and deletion remain short events.artist_art_upload:data.replaceddistinguishes replacement from addition. ReplacementinfocontainspreviousFile,file, and the new file'sbytes,width,height. Image copies are not stored in audit entries.jingle_edit,background_music_edit,phrase_edit: changes toused(on-air selection) ormode. Batch operations log each successfully changed file.queue_addandqueue_remove: song identity and position. Skips, accepting/ rejecting suggestions, and media uploads/deletions remain short events.mode_switch:fromMode,targetMode,scheduledAt(Unix ms ornull),timeZoneand optionalscheduledTime. This records an accepted request for a scheduled time or as soon as possible after the current track, rather than confirmation that switching has completed.participant_mute: participant and changedmutedstate; includes moderator actions and a host muting a guest.host_queue_pause,host_queue_resume: successful main queue state changes.host_background_music: previous/newbackgroundTrack.guest_code_generate,guest_code_regenerate: lifetime andexpiresAt. Deactivation, kicks, bans, unbans and session starts/ends remain short events.donation_insert_failed: amount, currency, order ID and localized failure reason ininfo; clients show a general explanation if the reason is unknown.
Saving metadata and lyrics together creates two entries. Unchanged saves do not produce edit entries. Previous values are captured before changes; new values come from server persistence after normalization.
Request contract additions
POST /api/admin/song-editor/save accepts optional auditContext: { source: 'bulk', force: boolean }. This is an audit origin hint only: it does not change authorization, search for lyrics, or force an update on the server. The batch lyrics client includes it when saving.
POST /api/admin/song-groups/:groupId/insert additionally returns insertedSongIds: string[] in actual insertion order alongside insertedCount. The admin_insert_song_group event also writes the same audit entry; its input payload remains unchanged.
Details use the existing operation data JSON field for both JSON and SQL providers, so no table migration is required. Passwords, hashes, tokens, access codes and payment secrets are excluded. Personal microphone toggles and gain adjustments are not audited.