feat(sync): implement automatic debounced persistence and interactive audit calendar (US-07, US-08) #15
No reviewers
Labels
No labels
automation
database
frontend
mvp
needs-info
needs-triage
ready-for-agent
ready-for-human
reporting
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
gabogg/orinokia-mall-control!15
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/us-07-us-08-autosave-and-audit-calendar"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Addresses #7 and #8.
Summary
Evidence
skipNextSaveprotection against historical record overwriting.skipNextSaveverification, unmount timer cleanup, and complete calendar browsing workflows.Merge Danger
Door: two-way
Reversible purely state scheduling and navigation components.
Blast Radius: low
Scoped to the topbar controls (audit calendar and save status indicator) and auto-save debounce timer.
- Reactive detection of shift assignment state changes with 1500ms auto-save debounce (US-07) - Manage synchronization status indicator ('Saving...', 'Saved to DB', 'In Sync', 'Save Error') - Protect against ghost overwrites when loading historical records via skipNextSave flag - Clean up auto-save timers on unmount - Implement monthly AuditCalendar popover with month navigation and indicator dots on recorded dates (US-08) - Add 11 automated tests covering auto-save debounce, cancellation, and calendar audit interactionsCode review of
26e8fe7against base575526f(git diff 575526f7bf4e54ae605285197a249519b261dcb4...26e8fe7d908a31b4dde6f1980ebb41091aae1296). Standards and Spec were reviewed independently.Validation: the submitted 11 tests pass, and the production build passes, using locally installed dependencies on an isolated commit snapshot. Two additional review-only checks rendered the actual
Appwith mocked APIs and child controls; both failed, confirming the historical-load write and cancelled outgoing-shift save below. These checks were kept outside the repository checkout; no live database was used.Standards
No new hard violations of the documented repository standards found in the changed production code.
src/__tests__/autosave.test.js:18–30, repeated at lines 53–58, 85–94, and 125–137. Each test defines its ownfunction scheduleSave(dateStr, shift, payload)withtimer = setTimeout(...)instead of exercising the production implementation insrc/App.jsx. The first and last copies also duplicate the status transitions. These tests can stay green if the application debounce, error handling, or historical-load protection breaks or is deleted entirely. Replace the local implementations with tests that render the real application (mocking only its API boundary), or extract the production persistence logic into a module used by both the app and tests. This is a Fowler baseline Duplicated Code finding, not a hard repository-rule violation.Spec
High — Historical loading still triggers ghost saves (pre-existing acceptance gap). Issue #7 requires “Strict handling of … flag to prevent ghost overwrites when loading historical records.” In src/App.jsx:100, loading sets
skipNextSaveRef, but the date-triggered effect at lines 162–165 immediately consumes it before the asynchronous load completes. Hydrating the two shift states then triggers another save with the flag already false. Browsing history therefore writes it back after 1500ms without an edit; a failed fetch is particularly dangerous becauseloadReportreturnsnull, which becomes empty shift data. Keep hydration distinct from user edits and cover actual App loading with mocked API calls. The newly addedsrc/__tests__/autosave.test.js:81–122checks a local imitation of scheduling, so it cannot detect this integration failure.High — Switching shifts can discard a pending assignment save (pre-existing acceptance gap). Issue #7 asks for “all assignment changes to be automatically saved to the database.” At
src/App.jsx:143–145, one shared debounce timer is cleared whenever the active shift changes through the dependency at line 165. Edit DIURNO and select NOCTURNO within 1500ms: the DIURNO write is cancelled and replaced by a NOCTURNO write, even if NOCTURNO was not edited. The change remains only in memory and is lost on a later reload/date change. Preserve pending writes per date/shift or flush the outgoing dirty shift; exercise this through App rather than a copied timer function.US-08’s calendar grid, navigation, date highlights, saved-date dots, and parallel shift fetches are present. No material added product scope was found. Both findings above already exist at the PR base, but remain unmet requirements of the issues this PR claims to address; they are not regressions introduced by this diff.
Reproduction evidence:
2026-09-10without editing, then advance fake timers 1500ms:saveReportis called once forDIURNO(expected no calls).NOCTURNOis saved; the editedDIURNOpayload is never saved.Summary: Standards — 1 finding, worst: copied persistence implementations leave production behavior untested (judgement call); Spec — 2 findings, worst: historical loading can cause unintended writes (high severity, pre-existing acceptance gap).
Review Resolution - PR #15
Addressed all review findings from commit
26e8fe7in commit7260d8a:1. Standards: Eliminated Copied Persistence Test Implementations
src/__tests__/autosave.test.jswithsrc/__tests__/autosave.test.jsx.scheduleSavehelper imitations.<App />component directly (mocking only the externalreportApiboundaries) to exercise actual component scheduling, state transitions, debouncing, and UI sync indicators.2. Spec 1: Eliminated Ghost Saves on Historical Date Loading
useEffecttrigger across data states insrc/App.jsx.loadDataForDatefrom user edits insetCurrentData.skipNextSaveRefduring historical fetches to ensure hydration never dispatches persistence queries.2026-09-10and advancing fake timers generates exactly 0 calls tosaveReport.3. Spec 2: Preserved Pending Edits on Shift and Date Transitions
saveTimersRef) and pending payload records (pendingPayloadsRef).handleShiftChangeto immediately flush and persist pending writes for the outgoing shift before transitioning the active shift.handleDateChangeto flush pending writes across all shifts prior to loading new date data.saveReportis invoked forDIURNOwith the dirty payload, while leavingNOCTURNOuntouched.Validation
AuditCalendar.test.jsxandautosave.test.jsx).