Skip to content

Add Hot-Reload Google Drive sync without restart#13

Merged
geokoko merged 13 commits intomasterfrom
v0.1.2
Mar 1, 2026
Merged

Add Hot-Reload Google Drive sync without restart#13
geokoko merged 13 commits intomasterfrom
v0.1.2

Conversation

@geokoko
Copy link
Owner

@geokoko geokoko commented Mar 1, 2026

No description provided.

geokoko and others added 8 commits February 3, 2026 01:21
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
- Add time-based guard so processAllDelayedGoals runs at most once per day
- Fix getRecurringSummary orphan separator on malformed patterns
- Add null/future-date validation to getStudyGoalsForFutureDate
- Preserve recurringPattern in addTask null-priority fallback path
- Use empty-string sentinel to allow clearing recurring pattern on edit
- Update README and ARCHITECTURE with recurring tasks, future goal planning,
  schema migration strategy, and delay processing guard
- Add DatabaseReloadService: H2 SHUTDOWN → evict pool → reconnect → re-migrate
- Add GoogleDriveService.downloadAndReload() for in-place DB replacement
- Add SyncStatus enum and checkSyncStatus() comparing local/remote timestamps
- Track local DB dirty flag (markLocalDbDirty) in StudyService, TaskService, ProjectService
- Auto-check Drive sync on startup; show notification if remote is newer
- Replace download+exit flow with hot-reload in ProfileViewPanel
- Show 'local changes not uploaded' warning in Drive sync status
- Register reload listeners to refresh all UI panels after Drive pull
- Add GoogleDriveGateway.getRemoteModifiedTime() for timestamp comparison
@geokoko geokoko self-assigned this Mar 1, 2026
Copilot AI review requested due to automatic review settings March 1, 2026 15:31
Copy link
Contributor

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

This PR extends StudySync’s desktop app to support in-app Google Drive database refresh (hot reload) and also adds new planning features (future-dated study goals and recurring tasks), including the schema/entity/service/UI updates needed to persist and render them.

Changes:

  • Add Google Drive “download + reload” flow with dirty-tracking, startup sync-status check, and UI refresh listeners.
  • Add recurring task support (DB column + entity/service helpers + task management UI).
  • Add future goal planning (DatePicker-based goal creation, calendar/day filtering updates) and reduce repeated delayed-goal processing via a once-per-day guard.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/main/resources/schema.sql Adds recurring_pattern column + idempotent ALTER migration block
src/main/java/com/studysync/presentation/ui/components/TaskManagementPanel.java Adds recurring-task UI controls; passes recurring pattern through create/update
src/main/java/com/studysync/presentation/ui/components/StudyPlannerPanel.java Adds goal date picker + quick-select buttons; saves goals for selected date
src/main/java/com/studysync/presentation/ui/components/ProfileViewPanel.java Replaces “restart to apply” with download-and-reload; shows local-dirty hinting
src/main/java/com/studysync/presentation/ui/components/DailyViewPanel.java Adds future-date branch for goal retrieval
src/main/java/com/studysync/presentation/ui/components/CalendarViewPanel.java Enables future-date navigation, styling, goal planning dialog, and future-date goal filtering
src/main/java/com/studysync/presentation/ui/StudySyncUI.java Wires DatabaseReloadService, adds sync-status check, registers reload listener to refresh panels
src/main/java/com/studysync/integration/drive/GoogleDriveService.java Adds dirty tracking, sync-status computation, reload listeners, and downloadAndReload API
src/main/java/com/studysync/integration/drive/GoogleDriveGateway.java Adds remote modified-time lookup for sync-status checks
src/main/java/com/studysync/domain/service/TaskUpdate.java Adds recurringPattern field + convenience ctor preserving old call sites
src/main/java/com/studysync/domain/service/TaskService.java Wires dirty tracking + adds recurring task operations and update/apply logic
src/main/java/com/studysync/domain/service/StudyService.java Adds future-goal retrieval method, dirty tracking on writes, and once-per-day delayed-goal processing guard
src/main/java/com/studysync/domain/service/ProjectService.java Adds dirty tracking on project writes
src/main/java/com/studysync/domain/entity/Task.java Persists/loads recurring_pattern and adds recurrence helpers + recurring queries
src/main/java/com/studysync/config/DatabaseReloadService.java New service to reload H2/Hikari connections and reapply schema.sql after Drive download
README.md Documents future goal planning, recurring tasks, and migration approach
ARCHITECTURE.md Documents recurrence format, future planning, delayed-goal guard, and migration strategy
Comments suppressed due to low confidence (2)

src/main/java/com/studysync/domain/service/StudyService.java:89

  • getTodayGoals() now calls ensureDelayedGoalsProcessedToday(), which can perform writes (processAllDelayedGoals). Because calculateDailyProgress() is @transactional(readOnly = true) and calls getTodayGoals() via self-invocation, delayed-goal processing may execute inside a read-only transaction, which can fail or be ignored depending on DB/transaction manager. Consider removing readOnly from calculateDailyProgress(), or moving delayed-goal processing into a separate bean/TransactionTemplate so it runs in a write-capable transaction.
    public List<StudyGoal> getTodayGoals() {
        ensureDelayedGoalsProcessedToday();
        return StudyGoal.findByDate(LocalDate.now());
    }

src/main/java/com/studysync/domain/service/StudyService.java:100

  • ensureDelayedGoalsProcessedToday() can trigger processAllDelayedGoals(), which updates/deletes goals. Those DB writes should mark the local DB dirty so Drive sync status remains accurate (similar to other write paths calling markDirty()). Consider capturing the GoalDelayProcessingResult from processAllDelayedGoals() and calling markDirty() when it reports changes.
    private void ensureDelayedGoalsProcessedToday() {
        LocalDate today = LocalDate.now();
        if (!today.equals(lastDelayProcessingDate)) {
            processAllDelayedGoals();
            lastDelayProcessingDate = today;
        }

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

geokoko added 3 commits March 1, 2026 17:39
The manual split-by-semicolon approach skipped SQL statements preceded
by comment headers because the entire chunk started with '--' after
trim(). Spring's ResourceDatabasePopulator handles comment stripping
correctly and is the idiomatic choice for executing SQL scripts.
downloadAndReload() now shuts down H2 and evicts pool connections
before downloading the Drive file, ensuring the .mv.db file lock is
released before the move/replace. Reconnect always runs in a finally
block so the app stays functional even if the download fails.
Copy link
Contributor

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

Copilot reviewed 8 out of 8 changed files in this pull request and generated 10 comments.


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

- Show blocking overlay on main window during DB reload to prevent
  user interaction while H2 is shut down (pre-reload/post-reload listeners)
- Add Objects.requireNonNull for dbShutdown/dbReconnect callbacks;
  catch and log exceptions from both so a failed reconnect returns
  false instead of propagating an unhandled RuntimeException
- Defer markLocalDbDirty() to afterCommit via TransactionSynchronization
  so rolled-back transactions don't falsely flag the DB as dirty
- Adjust runMigrations() log message to note continueOnError=true;
  escalate full failure to logger.error with stack trace
- checkSyncStatus() now returns LOCAL_NEWER based on file timestamps
  (not just the in-memory dirty flag), catching post-restart drift
- markLocalDbDirty() sets the flag unconditionally (regardless of
  sign-in state) so edits made while signed out are tracked
- refreshAllPanels() logs full exception (not just getMessage())
@geokoko geokoko merged commit a5ece5e into master Mar 1, 2026
1 check passed
@geokoko geokoko deleted the v0.1.2 branch March 1, 2026 17:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants