Skip to content

Work entry audit log (#11)#15

Open
duchacekjan wants to merge 24 commits into
mainfrom
feature/work-entry-audit-log
Open

Work entry audit log (#11)#15
duchacekjan wants to merge 24 commits into
mainfrom
feature/work-entry-audit-log

Conversation

@duchacekjan
Copy link
Copy Markdown
Collaborator

@duchacekjan duchacekjan commented May 19, 2026

Summary

  • Add AuditLog entity + AuditInterceptor (EF Core ISaveChangesInterceptor) capturing all WorkEntry mutations in the same transaction
  • Add GET /api/worksheets/{year}/{month}/days/{date}/audit endpoint returning day-scoped history; admin can pass ?userId
  • Add TS contracts, getWorkEntryAudit API fn, and useWorkEntryAudit TanStack Query hook
  • Add WorkEntryAuditSidebar — right-side Sheet overlay with accordion timeline, colored action dots, entry type badges, skeleton/empty states
  • Wire history icon button into every WorkSheet day row; toggle opens/closes sidebar; active row button highlighted blue

Test plan

  • 32/32 backend integration tests pass (dotnet run --project src/UCK26.Api.Tests)
  • npm run lint zero errors (TypeScript strict)
  • Playwright UI tests — run with API + SPA running: dotnet run --project src/UCK26.Ui.Tests

Closes

Closes #2
Closes #3
Closes #4
Closes #5
Closes #6
Closes #7
Closes #11

No FK to WorkEntry by design — audit survives entry deletion.
AuditLog stores denormalized EntryDate, EntryType, WorksheetId
for post-delete queries.

Closes #2
Interceptor captures all WorkEntry mutations in same transaction;
endpoint returns day-scoped history ordered descending by time.
EntryDate stored as yyyy-MM-dd; action serialized as string.

Closes #3
Closes #4
Right-side Sheet overlay with accordion timeline; colored dot per
action, entry type badge, skeleton loading, empty state.

Closes #6
History button on every day row; toggle opens/closes right-side
sidebar; active button highlighted blue; summary row column aligned.

Closes #7
Sheet already renders a close button; removed manual X button.
Delete audit now captures all original field values so sidebar
shows what the removed entry contained.
…cting line

Dots sit in dedicated column left of cards, connected by vertical line.
SheetContent gets p-6. Last event has no trailing line segment.
@duchacekjan duchacekjan changed the title feat: work entry audit log (#11) Work entry audit log (#11) May 19, 2026
@duchacekjan duchacekjan marked this pull request as ready for review May 19, 2026 09:46
Copy link
Copy Markdown
Collaborator Author

@duchacekjan duchacekjan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 findings total. One bug (EntityId=0 on Create), one risk (nondeterministic batch ordering), one unused variable, one state-reset miss, one weak test assertion.

Comment thread src/UCK26.Api/Persistence/AuditInterceptor.cs
Comment thread src/UCK26.Api/Endpoints/WorksheetEndpoints.cs Outdated
Comment thread src/uck26-frontend/src/features/work/WorkEntryAuditSidebar.tsx
Comment thread src/UCK26.Api.Tests/Integration/WorksheetEndpointTests.cs
Comment thread src/UCK26.Api/Persistence/AuditInterceptor.cs Outdated
duchacekjan and others added 12 commits May 19, 2026 11:54
Includes favicon support, Home route with icon, and dynamic company logo rendering in the AppShell component.
- Back-fill EntityId for Create audit logs via SavedChangesAsync override;
  SavingChangesAsync fires before EF assigns the auto-increment id
- Use DateTime.UtcNow per entry instead of shared timestamp to avoid
  nondeterministic ordering within a batch
- Drop unused callerName variable in audit endpoint handler
- Reset expandedIndex when date prop changes in WorkEntryAuditSidebar
- Strengthen Audit_PutEntry test to assert changed field names and values

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds end-to-end auditing for WorkEntry mutations (create/update/delete) and surfaces per-day audit history in the worksheet UI via a right-side sidebar, backed by an EF Core SaveChangesInterceptor and a new audit endpoint.

Changes:

  • Backend: introduce AuditLog storage + AuditInterceptor, and add GET /api/worksheets/{year}/{month}/days/{date}/audit.
  • Frontend: add TS DTOs, API function + TanStack Query hook, implement WorkEntryAuditSidebar, and wire a per-day history button into WorkSheet.
  • Tests/docs: add integration coverage for interceptor/endpoint, Playwright coverage for sidebar, and update README/CLAUDE.

Reviewed changes

Copilot reviewed 19 out of 21 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
src/UCK26.Ui.Tests/WorkPageTests.cs Adds Playwright coverage for opening/closing the audit sidebar and empty/non-empty states.
src/UCK26.Api/Program.cs Registers AuditInterceptor and wires it into EF Core via AddInterceptors.
src/UCK26.Api/Persistence/Migrations/AppDbContextModelSnapshot.cs Updates EF snapshot to include AuditLogs.
src/UCK26.Api/Persistence/Migrations/20260519060944_AddAuditLog.Designer.cs Adds migration designer for AuditLogs table.
src/UCK26.Api/Persistence/Migrations/20260519060944_AddAuditLog.cs Creates AuditLogs table (no FK to WorkEntry).
src/UCK26.Api/Persistence/AuditLog.cs Introduces AuditLog, AuditAction, and AuditChangedField.
src/UCK26.Api/Persistence/AuditInterceptor.cs Captures WorkEntry mutations and writes audit rows.
src/UCK26.Api/Persistence/AppDbContext.cs Adds AuditLogs DbSet and a pending-backfill list.
src/UCK26.Api/Endpoints/WorksheetEndpoints.cs Adds the day-scoped audit endpoint and deserializes ChangedFields.
src/UCK26.Api.Tests/Integration/WorksheetEndpointTests.cs Adds integration tests for interceptor behavior and audit endpoint authorization.
src/UCK26.Api.Tests/Infrastructure/TestWebApplicationFactory.cs Ensures the interceptor is applied in the test DbContext configuration.
src/uck26-frontend/src/shared/ui/AppShell.tsx Adds “Home” route and updates sidebar route entries.
src/uck26-frontend/src/shared/lib/api/worksheets.contracts.api.ts Adds audit DTO contracts for frontend consumption.
src/uck26-frontend/src/shared/lib/api/worksheets.api.ts Adds getWorkEntryAudit API call.
src/uck26-frontend/src/features/work/worksheets.queries.ts Adds useWorkEntryAudit query hook.
src/uck26-frontend/src/features/work/WorkSheet.tsx Adds history icon column + mounts WorkEntryAuditSidebar.
src/uck26-frontend/src/features/work/WorkEntryAuditSidebar.tsx Implements the audit history sidebar UI.
src/uck26-frontend/package.json Bumps @itixo/component-library dependency.
src/uck26-frontend/package-lock.json Updates lockfile for the component library bump.
README.md Documents audit logging and the new audit endpoint + entities list.
CLAUDE.md Updates solution map and testing data-test-id conventions for audit UI.
Files not reviewed (2)
  • src/UCK26.Api/Persistence/Migrations/20260519060944_AddAuditLog.Designer.cs: Language not supported
  • src/uck26-frontend/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/UCK26.Ui.Tests/WorkPageTests.cs Outdated
Comment thread src/UCK26.Ui.Tests/WorkPageTests.cs Outdated
Comment thread src/UCK26.Ui.Tests/WorkPageTests.cs
Comment thread src/uck26-frontend/src/features/work/WorkSheet.tsx Outdated
Comment thread src/uck26-frontend/src/features/work/WorkSheet.tsx Outdated
Comment thread src/UCK26.Api/Persistence/AuditInterceptor.cs
Comment thread src/UCK26.Api/Persistence/AuditInterceptor.cs
Comment thread src/UCK26.Api/Endpoints/WorksheetEndpoints.cs
Comment thread src/UCK26.Api.Tests/Integration/WorksheetEndpointTests.cs
Comment thread src/UCK26.Api/Endpoints/WorksheetEndpoints.cs
@duchacekjan
Copy link
Copy Markdown
Collaborator Author

Addressed all unresolved review threads in e2761a5 and 2f88c20:

  • WorkPageTests: added data-test-id="work-history-empty" and changed the empty-state assertion to use the test id.
  • WorkPageTests: CreateEntryForDateAsync now captures the POST response and calls EnsureSuccessStatusCode().
  • WorkEntryAuditSidebar: delete events now render a tombstone message (Entry removed) instead of reading changedFields.
  • AuditInterceptor: delete audit rows now keep ChangedFields = null; test assertion updated.
  • WorksheetEndpoints: audit endpoint now parses ChangedFields via guarded JSON handling and returns null for invalid payloads.
  • WorksheetEndpoints: audit ordering now uses PerformedAt DESC, Id DESC for stable same-timestamp ordering.

Verification:

  • dotnet run --project src/UCK26.Api.Tests -> 33/33 passed
  • npm run lint -> passed
  • UCK26_FRONTEND_URL=http://localhost:3001 UCK26_API_URL=http://localhost:5081 dotnet run --project src/UCK26.Ui.Tests -> 13/13 passed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants