Summary
The WebUI already records every web-based state change in WebAuditLog (src/models/web-audit-log.ts, src/web/audit.ts). There is currently no equivalent visibility into Discord slash-command usage — operators cannot see who ran /quote, /config, /voicestats, etc., when they ran it, or whether it succeeded.
Adding a Discord-side command audit trail — and surfacing it in the existing admin WebUI — would close this gap with relatively little new infrastructure.
Proposed design
1. New Mongoose model: DiscordCommandAuditLog
// src/models/discord-command-audit-log.ts
{
guildId: String, // required
discordUserId: String, // required
commandName: String, // e.g. "quote", "config", "voicestats"
subcommand: String | null,
channelId: String,
result: "success" | "error" | "denied",
errorMessage: String | null,
durationMs: Number, // wall-clock time from interaction received to reply
createdAt: Date,
}
2. Thin recording helper
Analogous to src/web/audit.ts:
// src/utils/record-command-audit.ts
export async function recordCommandAudit(entry: CommandAuditEntry): Promise<void> { ... }
3. Hook into CommandManager
src/services/command-manager.ts already has a central handleInteraction() dispatch path. Wrap each command execution with a try/catch that records success, error, or permission-denied outcomes.
4. New WebUI read-only page: /admin/audit/commands
- Table of recent command invocations (paginated, newest first)
- Columns: timestamp, user, command, result, duration
- Filters: date range, command name, user ID, result
- Reuse the existing
AdminPageOptions / renderAdminPage layout
5. Retention / cleanup
Honour a new config key core.command_audit.retention_days (default: 90) in the existing VoiceChannelTruncationService cleanup cron, or a new dedicated cleanup job.
Value
- Operator visibility: identify abuse patterns (e.g. a user spamming
/quote add), diagnose mysterious errors, verify that permission changes took effect.
- Security: correlate suspicious WebUI changes with prior slash-command activity.
- Low incremental cost: the model, helper, and WebUI page all follow patterns already established in the codebase (
WebAuditLog, read-only-routes.ts, renderAdminPage). The most complex part is the CommandManager hook, which is a single try/catch wrapper.
Out of scope
- Recording raw command arguments (user privacy / potential secret leakage).
- Exporting audit rows via YAML (too large; use DB tooling for bulk export).
Summary
The WebUI already records every web-based state change in
WebAuditLog(src/models/web-audit-log.ts,src/web/audit.ts). There is currently no equivalent visibility into Discord slash-command usage — operators cannot see who ran/quote,/config,/voicestats, etc., when they ran it, or whether it succeeded.Adding a Discord-side command audit trail — and surfacing it in the existing admin WebUI — would close this gap with relatively little new infrastructure.
Proposed design
1. New Mongoose model:
DiscordCommandAuditLog2. Thin recording helper
Analogous to
src/web/audit.ts:3. Hook into
CommandManagersrc/services/command-manager.tsalready has a centralhandleInteraction()dispatch path. Wrap each command execution with a try/catch that records success, error, or permission-denied outcomes.4. New WebUI read-only page:
/admin/audit/commandsAdminPageOptions/renderAdminPagelayout5. Retention / cleanup
Honour a new config key
core.command_audit.retention_days(default: 90) in the existingVoiceChannelTruncationServicecleanup cron, or a new dedicated cleanup job.Value
/quote add), diagnose mysterious errors, verify that permission changes took effect.WebAuditLog,read-only-routes.ts,renderAdminPage). The most complex part is theCommandManagerhook, which is a single try/catch wrapper.Out of scope