Conversation
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
There was a problem hiding this comment.
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.
src/main/java/com/studysync/integration/drive/GoogleDriveService.java
Outdated
Show resolved
Hide resolved
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.
There was a problem hiding this comment.
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.
src/main/java/com/studysync/integration/drive/GoogleDriveService.java
Outdated
Show resolved
Hide resolved
src/main/java/com/studysync/integration/drive/GoogleDriveService.java
Outdated
Show resolved
Hide resolved
src/main/java/com/studysync/presentation/ui/components/ProfileViewPanel.java
Show resolved
Hide resolved
- 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())
No description provided.