feat(audit-log): dashboard audit log system with slideover UI#144
feat(audit-log): dashboard audit log system with slideover UI#144Copilot wants to merge 46 commits into
Conversation
✅ Deploy Preview for wolfstar-rocks-et34281 ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
❌ 7 Tests Failed:
View the top 3 failed test(s) by shortest run time
|
Contribution Guidelines ReviewThanks for this detailed PR — the audit log feature is well-described and the title follows Conventional Commits format correctly. ✅ There's one item from the contribution guidelines that needs attention before this can be marked ready: 📸 Missing screenshots for frontend changesThe guidelines state:
This PR introduces
✅ Everything else looks good
Once screenshots are added and the PR is marked ready for review, this should be good to go!
|
There was a problem hiding this comment.
Code Review — Audit Log System (draft)
This is a solid feature addition with a clean architecture. CI shows lint ✅ · unit tests ✅ · component tests ✅ — but 🧹 Unused code check ❌ is failing (needs investigation before merge). Browser tests, accessibility audits and benchmarks were still running at review time.
Since this is a draft I'm not blocking merge, but there are two runtime-breaking bugs that must be addressed before this is ready.
🐛 Must fix (runtime errors)
| # | File | Issue |
|---|---|---|
| 1 | server/database/schema.prisma |
Model named AuditLog generates prisma.auditLog, but all code calls prisma.dashboardAuditLog. Also @@Map("audit_log") disagrees with the migration's dashboard_audit_log table. Fix: rename model to DashboardAuditLog and change @@map`` to "dashboard_audit_log". |
| 2 | shared/schemas/audit-log.ts |
number() rejects string query params — every request to GET /audit-logs?limit=50 will return 400. Use coerce(number(), Number) (see inline comment). |
⚠️ Should address
| # | File | Issue |
|---|---|---|
| 3 | server/api/guilds/[guild]/settings.patch.ts |
deriveSection classifies the whole batch by keys[0] only — mixed-section saves are mislabelled. |
| 4 | app/composables/useAuditLog.ts |
Cache key is a static string evaluated once at setup — pass a getter () => \guild:...`` so Nuxt can react to guild navigation. |
| 5 | app/components/guild/AuditLogSlideover.vue |
Entries list lacks aria-live="polite" — screen reader users won't know when content refreshes. |
💡 Nice-to-have
| # | File | Suggestion |
|---|---|---|
| 6 | AuditLogSlideover.vue |
Replace hand-rolled formatRelativeTime with useTimeAgo from VueUse — it's already in the project and stays reactive as time passes. |
🧹 CI failure
The unused code check is failing — likely caused by the new AuditLogQuery type export or another export not yet consumed. Run pnpm knip locally and add any genuinely unused exports to the knip ignore list, or wire them up properly.
Generated by WolfStar Code Quality Reviewer for issue #144 · ● 778.1K
Contribution Guidelines Review 🔍Hi ✅ What looks good
🔧 A couple of things to address1. Missing before/after screenshotsThe guidelines require:
This PR adds a new 2. PR is still in draftThe PR is currently marked as a draft, which typically means it isn't ready for review or merge yet. When the implementation is complete and the checklist below is done, mark it as "Ready for review". 📋 Pre-submission checklistBefore marking ready for review, please confirm:
Once those are addressed, this will be in great shape! Feel free to ping when it's ready. 🚀
|
Contribution Guidelines Review 👋Thanks for this detailed PR! The implementation looks well-structured and the description clearly explains the changes across the database, server, shared, and frontend layers. A few contribution process items to address before this is ready for review: ❌ Missing screenshots for frontend changesThe contribution guidelines require:
This PR introduces a new
i️ PR is still in draftThe PR is currently marked as a draft. Once the implementation is complete and CI checks pass (build, lint, typecheck, tests), please mark it as ready for review. ✅ What looks good
Once screenshots are added and the draft status is removed, this will be much closer to ready. Let us know if you have any questions!
|
|
@copilot apply changes based on the comments in this thread |
Contribution Guidelines Review ✅This PR has been reviewed against the contribution guidelines and meets all requirements:
The
|
There was a problem hiding this comment.
Pull request overview
Introduces a dashboard-facing audit log system for guild settings changes, including persistence in the database, server endpoints to query activity, and UI surfaces (recent activity panel + slideover) to view entries.
Changes:
- Added Prisma
AuditLogmodel + migrations, and server-sideAuditLogManagerfor recording/fetching entries. - Updated guild settings PATCH flow to write audit entries on settings updates, and added
GET /api/guilds/:guild/audit-logs(plus moderation list endpoint and supporting schemas/composables). - Added frontend UI for recent activity and an “Activity Log” slideover, wired into the guild manage navbar.
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| shared/utils/moderationConstants.ts | Adds moderation labels/icons/severity helpers for new “Recent Activity” UI. |
| shared/types/prisma.ts | Extends PrismaJson typings to include audit log change arrays. |
| shared/schemas/moderation.ts | Adds query schema for moderation list endpoint. |
| shared/schemas/index.ts | Re-exports new schemas. |
| shared/schemas/audit-log.ts | Adds query schema for audit log endpoint pagination. |
| server/database/settings/types.ts | Introduces audit-log-related types for settings/database layer. |
| server/database/settings/structures/AuditLogManager.ts | Implements audit log write + fetch logic, including member hydration. |
| server/database/settings/functions.ts | Exposes readSettingsAuditLog() from settings context. |
| server/database/settings/context/SettingsContext.ts | Wires AuditLogManager into per-guild settings context lifecycle. |
| server/database/schema.prisma | Adds AuditLog model and relation to Guild. |
| server/database/migrations/20260412130548_audit_log_remove_username_add_guild_fk/migration.sql | Drops prior table and creates audit_log with FK + index. |
| server/database/migrations/20260411190000_add_dashboard_audit_log/migration.sql | Initial migration adding dashboard_audit_log (later superseded by next migration). |
| server/api/guilds/[guild]/settings.patch.ts | Adds fire-and-forget audit log write when settings are patched. |
| server/api/guilds/[guild]/moderation.get.ts | Adds moderation cases list endpoint. |
| server/api/guilds/[guild]/audit-logs.get.ts | Adds audit log list endpoint. |
| app/pages/(app)/guilds/[...id]/manage.vue | Integrates Activity Log trigger + slideover into the dashboard navbar. |
| app/composables/useModerationCases.ts | Adds composable to fetch moderation cases + total. |
| app/composables/useAuditLog.ts | Adds composable to fetch audit log entries + total. |
| app/components/guild/settings/General.vue | Adds “Recent Activity” panel showing audit changes and moderation cases. |
| app/components/guild/card.vue | Small template formatting/layout tweak. |
| app/components/AuditLogSlideover.vue | Adds Activity Log slideover UI. |
There was a problem hiding this comment.
Review — feat(audit-log): dashboard audit log system
Draft PR — no merge decision, but flagging issues that need attention before this is ready.
CI status
| Check | Result |
|---|---|
| 🔠 Lint | ✅ Passed |
| 🧪 Unit tests | ✅ Passed |
| 🧪 Component tests | ✅ Passed |
| 🧹 Unused code (knip) | ❌ Failed |
| 🖥️ Browser tests | 🔄 In progress |
| ♿ Accessibility audits | 🔄 In progress |
| ⚡ Benchmarks | 🔄 In progress |
Must fix before merge
-
❌ Unused code check failing (
shared/utils/moderationConstants.ts+shared/schemas/moderation.ts) — 9 exported symbols are never consumed. Removeexportfrom internal helpers and types that aren't used outside the file, and dropModerationQueryfrom the schema if it isn't referenced elsewhere. See inline comment onmoderationConstants.ts. -
🐛 Audit log diff always shows
oldValue === newValue—AuditLogManager.update()is called after the settings write, butSettingsContext.update()→onPatch()runs during the write and overwritesthis.#settingswith the new state first. The fix is to snapshot old values synchronously before thetrx.write().submit()call. See inline comment onsettings.patch.ts:69. -
🔴 TypeScript error:
AuditLogChangesnot in scope —AuditLogChangesis aPrismaJsonnamespace type and cannot be used as a bare identifier inAuditLogManager.ts. Replace with the already-importedAuditLogChange[]. See inline comment onAuditLogManager.ts:56.
Suggestions
MaybeRefOrGetternot reactive inuseAuditLog/useModerationCases—toValue(guildId)resolves once at init; if the ref ever changes the composable won't re-fetch. Narrow the type tostringto match actual usage.sectionIconsmap is duplicated — defined identically inAuditLogSlideover.vueandGeneral.vue; consider a shared constant.- Prisma
changesdefault —@default("{}")creates a JSON object, but the type isAuditLogChange[](an array). Use@default("[]")and update both migration SQL files accordingly. member.useroptional access ingetMemberDisplay—APIGuildMember.useris typed as optional; add a null guard.
The overall design is solid — layered well from schema → server → composable → UI, the deriveSection logic is clear, and the slideover pattern matches existing conventions. The audit diff timing bug is the most important correctness issue to get right before promoting this out of draft.
Generated by WolfStar Code Quality Reviewer for issue #144 · ● 1.5M
All review feedback addressed in ad7bcd0:
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
Hey I ran a quick check against the contribution guidelines. Here's where things stand: ✅ Looks good
⏳ Before marking ready This PR is currently in draft state, so I'm holding off on the
Once those are green and you mark the PR as ready, feel free to ping for another look and the label can be added then. 🚀
|
|
Thanks for this contribution! The implementation looks substantial and well thought-out. Before this PR can move forward, there are a few contribution process items to address. 👇 PR TemplateThe description doesn't follow the PR template. Please update it to include the required sections:
The technical detail in the current description is great — it just needs to be restructured into the template format. Own words, pleaseFrom CONTRIBUTING.md § Using AI:
The current description reads as AI-generated. Please rewrite it in your own voice — even a few plain sentences explaining what this does and why you built it is far more valuable than a detailed AI summary. Draft statusThis PR is currently marked as a draft. When it's ready for review, please mark it as ready and ensure CI checks pass (lint, typecheck, build, tests). Once those are addressed, re-request review and a maintainer will take a look. Thanks again for contributing! 🙌
|
* Introduced new columns in the Guild model for: - Command execution logs - Settings change logs * Updated migration file to reflect these changes.
* Add status label to log filters * Improve empty state messages for log tables * Format timestamps using `formatTimeAgo` for better readability
- Update UTable to show loading state for both 'pending' and 'idle'. - Add action type filter to ModerationLogTable for better log management. - Refactor audit logging to simplify change tracking.
- Update async data retrieval for audit, command, and moderation logs - Include resolved limit and offset in the data key for better pagination - Simplify cache invalidation logic for manual and hook refreshes
* Refactor log response handlers to use cached response handling. * Add maxAge and swr options for improved caching. * Implement getKey function for unique cache keys based on guild and request URL.
* Updated search input to use debounced query for better performance. * Improved pagination handling with dynamic total entries display. * Refactored user display in the activity log for better UI consistency.
* Integrate auditDiff to capture changes in settings. * Improve clarity of audit logs by including before and after states.
* Refactored patchToChanges to utilize getNestedValue for accessing nested properties. * Enhanced diff processing to limit the number of operations processed. * Updated changes structure to directly pass before and after settings for audit logging.
|
@copilot fix ci failed |
…access, fix any type" Agent-Logs-Url: https://github.com/wolfstar-project/wolfstar.rocks/sessions/2e965151-4a59-4dfa-80e9-7d5578c07275 Co-authored-by: RedStar071 <76824516+RedStar071@users.noreply.github.com>
* Updated swr option to false in commands, index, and moderation log handlers. * This change improves response caching behavior.
* Introduced new utility functions for handling audit changes. * Added metadata management for audit fields. * Created tests for audit log functionalities. * Removed deprecated schemas and functions to streamline codebase. * Enhanced logging descriptions for better clarity and usability.
* Include @tanstack/table-core in the ignoreDependencies list * Ensures proper handling of dependencies in guild/logs components
- Updated function name for clarity and consistency. - Removed alias for resolveGuildMembers to streamline code.
- Move mock entries for command, audit, and moderation logs.
* Replace CommandLogEntry with CommandLogData for better clarity. * Introduce commandType and commandId fields in CommandLog model. * Remove deprecated command log type definitions.
* Add commandType and commandId to command log entries * Move metadata field to the end of the entry structure
* Change CommandLogEntry to CommandLogData for consistency * Update mock command entry to reflect new data structure * Adjust variable names for clarity in log table component
- Changed type from CommandLogEntry to CommandLogData - Updated fetch calls in tests to reflect new type
|
@copilot resolve the merge conflicts in this pull request |
…stem-for-changes # Conflicts: # .github/workflows/semantic-pull-requests.yml
Merge conflicts resolved in There was one conflict in HEAD (PR branch) added: The merged result includes all scopes from both branches. All other changes from |

Linked issue
Context
The dashboard had no way to see what changed in guild settings, who ran commands, or review past moderation actions. This adds a
/guilds/:id/logspage with tabs for each log type, and wires up theevloghash-chain audit pipeline so settings changes are persisted and verifiable.The evlog infrastructure was folded in here since both features write to the same
AuditEventtable.Description
Database
AuditEventmodel with SHA-256 hash chain (AuditChainHeadstores the chain tip)CommandLogmodel (non-chained; written directly by the bot via shared Postgres)Moderation.createdAt(nullable column — cannot use Prisma@@index)Server
server/api/guilds/[guild]/logs/index.get.ts— dashboard activity feed (readsAuditEventfiltered to dashboard actions for the guild)server/api/guilds/[guild]/logs/moderation.get.ts— moderation cases with pagination and type filteringserver/api/guilds/[guild]/logs/commands.get.ts— command execution historyserver/api/guilds/[guild]/settings.patch.ts— updated to calllog.audit()on settings saves, capturing a before/after diffserver/plugins/evlog-drain.ts+server/utils/audit/postgres-drain.ts— Postgres sink with serializable transaction, 5x retry on write conflicts, swallows duplicate-key errorsserver/plugins/evlog-enrich.ts— enriches every event with request UA andtenantId(guild id)Shared
shared/audit/actions.ts— typed action creators (guildSettingsUpdate,userLogin, etc.)shared/audit/envelope.ts— canonical envelope shape +hashEnvelope()used by both the drain and the verify scriptshared/types/audit-log.ts,command-log.ts,moderation-log.ts,moderation-types.ts— DTO typesshared/schemas— valibot schemas withtransform(Number)coercion for query string paramsFrontend
app/pages/(app)/guilds/[...id]/logs.vue— new logs page, tab-based (moderation, commands, activity)app/components/guild/logs/ModerationLogTable.vue,CommandLogTable.vue,DashboardActivityTable.vue— table components with search, pagination, and loading statesapp/utils/audit-log.ts— formatting helpers for change diffs (roles, channels, durations, arrays)app/components/ActivitySection.vue— quick-preview widget in the manage navbar (deep-links to the activity tab)Scripts
scripts/audit-verify.ts— offline hash-chain replay tool (pnpm audit:verify) to detect tampering