10 KiB
Auto Refresh Implementation Report
1. Executive Summary
Implemented a shared TanStack Query invalidation layer for CRUD and workflow mutations that affect multiple dashboard modules. The change keeps existing URL search params, filters, sorting, pagination, dialogs, and route-handler architecture intact while making related client-side caches stale after successful actions.
2. Modules Audited
- Users
- Employees
- Employee Directory
- Courses
- Training Records
- Training Record Reviews
- Training Record Certificates
- Training Matrix
- Online Lessons
- Announcements
- Training Policies
- Permission Management
- Employee Import and Master Review
- Organizers
- Notifications
- Products legacy feature
3. Problems Found
- Several mutations invalidated only their own feature list even when the action changed data used by other pages.
- Certificate upload/delete refreshed the certificate list but not the training record detail/list cache that can show certificate preview data.
- Course mutations refreshed Course Master but not course option consumers used by training records and matrix screens.
- People mutations refreshed users or employees separately, but related directory, permission, and training-record option caches could remain stale.
- Content workflow actions could create notifications while only refreshing the content module.
4. Root Causes
- Cache invalidation lived inside each feature mutation file with no shared dependency map.
- Query keys were consistent, but related keys were not grouped by domain.
- The app uses server-prefetch plus hydrated TanStack Query; after a client mutation, stale hydrated data needs explicit query invalidation.
5. Files Changed
-
src/lib/query-invalidation.ts- Added shared invalidation helpers grouped by domain: people, courses, training records, training matrix, content workflow, permissions, organizers, imports, and policies.
- Reason: centralizes related cache dependencies without introducing a new library or changing page architecture.
- Impact: mutations can refresh all affected query groups consistently.
- Test: lint and TypeScript compile.
-
src/features/users/api/mutations.ts- Switched create/update/delete to
invalidatePeopleData(). - Reason: user changes affect users, employee-facing selectors, directory consumers, and permission assignment screens.
- Impact: user-related pages update after CRUD.
- Test: lint and TypeScript compile.
- Switched create/update/delete to
-
src/features/employees/api/mutations.ts- Switched create/update/delete to
invalidatePeopleData(). - Reason: employee changes affect Employee Directory and training-record participant options.
- Impact: employee data consumers refresh after employee CRUD.
- Test: lint and TypeScript compile.
- Switched create/update/delete to
-
src/features/courses/api/mutations.ts- Switched create/update/delete to
invalidateCourseData(). - Reason: course changes affect Course Master, training-record course options, and matrix option/compliance consumers.
- Impact: course selectors and matrix-dependent data are refreshed after course CRUD.
- Test: lint and TypeScript compile.
- Switched create/update/delete to
-
src/features/training-records/api/mutations.ts- Switched create/update/delete/import to
invalidateTrainingRecordData(). - Reason: training records affect record lists, employee directory summaries, and training matrix compliance.
- Impact: list and related summaries refresh after record actions.
- Test: lint and TypeScript compile.
- Switched create/update/delete/import to
-
src/features/training-records/api/review-mutations.ts- Added related training record invalidation plus detail invalidation for the reviewed record.
- Reason: review actions affect pending/approved lists and the detail page.
- Impact: pending review and training record views refresh after review actions.
- Test: lint and TypeScript compile.
-
src/features/training-records/api/certificate-mutations.ts- Added record list/detail invalidation alongside certificate list invalidation.
- Reason: certificate changes can affect preview data shown on record views.
- Impact: attachment and record UI update together.
- Test: lint and TypeScript compile.
-
src/features/training-matrix/api/mutations.ts- Switched create/update/delete to
invalidateTrainingMatrixData(). - Reason: matrix target changes affect matrix pages, employee target summaries, and training-record compliance consumers.
- Impact: matrix-related screens update after matrix CRUD.
- Test: lint and TypeScript compile.
- Switched create/update/delete to
-
src/features/employee-directory/api/mutations.ts- Added matrix/record related invalidation after target upsert while keeping target detail invalidation.
- Reason: employee target edits affect matrix compliance and employee-directory views.
- Impact: target detail and related summaries refresh after save.
- Test: lint and TypeScript compile.
-
src/features/online-lessons/api/mutations.ts- Added content workflow invalidation for lesson CRUD/workflow actions.
- Reason: lesson submit/publish/delete can affect lesson lists/details and notifications.
- Impact: content and notification data refresh after lesson actions.
- Test: lint and TypeScript compile.
-
src/features/announcements/api/mutations.ts- Added content workflow invalidation for announcement CRUD, workflow, pin, and unpin actions.
- Reason: announcement actions can affect lists/details and notifications.
- Impact: announcement and notification data refresh after content actions.
- Test: lint and TypeScript compile.
-
src/features/training-policy/api/mutations.ts- Switched policy actions to
invalidateTrainingPolicyData(). - Reason: policy changes may affect matrix-related policy views.
- Impact: policy and related matrix data refresh after policy actions.
- Test: lint and TypeScript compile.
- Switched policy actions to
-
src/features/import-employees/api/mutations.ts- Switched import/review actions to
invalidateEmployeeImportData(). - Reason: imports and master review can change employees, directory data, and participant options.
- Impact: employee-facing data refreshes after import and review actions.
- Test: lint and TypeScript compile.
- Switched import/review actions to
-
src/features/organizers/api/mutations.ts- Switched organizer CRUD to
invalidateOrganizerData(). - Reason: organizer changes can affect user/employee organization context data.
- Impact: organizer and related people data refresh after organizer actions.
- Test: lint and TypeScript compile.
- Switched organizer CRUD to
-
src/features/permission-management/api/mutations.ts- Switched template and user-permission mutations to
invalidatePermissionData()plus user detail invalidation where needed. - Reason: permission mutations affect template/catalog/user/audit views and user lists.
- Impact: permission screens update more consistently after save/clone/activate/deactivate/delete.
- Test: lint and TypeScript compile.
- Switched template and user-permission mutations to
-
src/features/products/api/mutations.ts- Added product detail invalidation after update.
- Reason: legacy detail view can otherwise show stale data after update.
- Impact: product detail cache refreshes after update.
- Test: lint and TypeScript compile.
6. Refresh Strategy by Module
- People data: invalidate users, employees, employee directory, training-record user options, and permission-management users.
- Course data: invalidate courses, training-record course options, training matrix options, and training matrix lists.
- Training record data: invalidate training records, employee directory, and training matrix compliance.
- Training matrix data: invalidate matrix, employee directory, and training record data.
- Content workflow data: invalidate announcements, online lessons, and notifications.
- Permission data: invalidate permission-management root keys and users.
- Import data: invalidate master review, employees, employee directory, and training-record user options.
- Organizer data: invalidate organizers, users, employees, and employee directory.
- Training policy data: invalidate training policies and training matrix.
7. Cache Keys Updated
['users']['employees']['employee-directory']['courses']['training-records']['training-records', 'course-options']['training-records', 'user-options']['training-matrix']['announcements']['online-lessons']['notifications']['permission-management']['master-review']['organizers']['training-policies']['products']
8. Pagination Handling
Existing pagination, search, filter, and sort state remains URL-driven through current table components and nuqs. The implementation invalidates query prefixes instead of rewriting search params, so existing table state is preserved.
9. Related Data Revalidation
Related data is now grouped by domain in src/lib/query-invalidation.ts. Mutations call the relevant domain helper rather than refreshing only the immediate feature.
10. Full Page Reloads Removed
No window.location.reload() usage was found in the audited app code. Existing router.refresh() calls remain only where the surrounding component/page still uses server component refresh behavior after a mutation.
11. Test Results
npm run lint -- src/lib/query-invalidation.ts ...: passed.npx tsc --noEmit --pretty false: passed.
12. Remaining Risks
- Some server-rendered dashboard summary/report widgets may use direct server data without a client query key; those still depend on navigation or
router.refresh()unless migrated to TanStack Query. - The current working tree already had unrelated edits in
src/app/dashboard/courses/page.tsxandsrc/features/courses/components/course-tables/columns.tsx; this implementation did not revert or normalize those changes. - Manual browser testing was not completed in this pass.
13. Recommendations
- Add query keys for dashboard/report summary widgets if they need live client refresh after related mutations.
- Keep future mutation files thin by using the shared domain invalidation helpers instead of adding one-off invalidate lists.
- Add a small integration test for high-risk flows: training record review, certificate upload/delete, course create/update, and employee import review.