# 004-single-sync-job: Simplify Sync Job Management with Progress Tracking ## Goal To simplify the synchronization job management by allowing only one sync job to run at a time, and to provide progress tracking for this single active sync job via a polling API. This aligns with the system's single-user nature while offering better user feedback. ## Motivation The current system is designed for a single user. While the previous iteration aimed to remove all job management complexity, the need for user feedback on ongoing sync operations necessitates a simplified progress tracking mechanism. This approach avoids a full-fledged job queue and ID system but still provides visibility into the single active sync. ## Proposed Changes ### 1. Reintroduction of a Simplified Sync Job Model * **Define `SyncJob` Model**: Reintroduce a `Pydantic` model for `SyncJob` (e.g., in a new `backend/src/sync_status.py` file or similar). This model will represent the state of the *single active* sync job and will include fields such as: * `status: str` (e.g., "idle", "in_progress", "completed", "failed") * `progress: float` (0.0 to 1.0) * `start_time: datetime` * `end_time: Optional[datetime]` * `error_message: Optional[str]` * `job_type: Optional[str]` (e.g., "activities", "health", "workouts") ### 2. Introduce `CurrentSyncJobManager` * **Create `CurrentSyncJobManager`**: Implement a singleton class or a global object (e.g., in `backend/src/sync_manager.py`) to manage the state of the `SyncJob`. This manager will hold the single `SyncJob` instance and provide methods for its lifecycle. * `start_sync(job_type: str) -> SyncJob`: Initializes a new `SyncJob` with "in_progress" status and the given type. Sets the `start_time`. Returns the `SyncJob` instance. * `update_progress(progress: float, details: Optional[str] = None)`: Updates the `progress` and optionally `details` of the current `SyncJob`. * `complete_sync()`: Sets the `status` to "completed" and `end_time` for the current `SyncJob`. * `fail_sync(error_message: str)`: Sets the `status` to "failed", `error_message`, and `end_time` for the current `SyncJob`. * `get_current_sync_status() -> SyncJob`: Returns the current `SyncJob` instance. * `is_sync_active() -> bool`: Returns `True` if a sync is currently "in_progress", `False` otherwise. ### 3. Modification of Sync Service Functions * The `_in_background` functions in `backend/src/services/garmin_health_service.py`, `backend/src/services/garmin_activity_service.py`, and `backend/src/services/garmin_workout_service.py` will be modified: * They will no longer accept a `job_id` parameter. * Instead, they will receive the `SyncJob` instance (or a reference to the `CurrentSyncJobManager`) for the current operation. * They will use the `CurrentSyncJobManager`'s `update_progress`, `complete_sync`, and `fail_sync` methods to report their status. ### 4. Modification of API Endpoints (`backend/src/api/garmin_sync.py`) * **Remove `job_store` and `SyncJob` imports from the old system.** * **Import `CurrentSyncJobManager` and `SyncJob` from the new system.** * **Remove `/status/{job_id}` endpoint**: This endpoint is no longer needed as there are no individual job IDs to query. * **Modify sync initiation endpoints (`/garmin/activities`, `/garmin/workouts`, `/garmin/health`)**: * Before initiating a sync, check `CurrentSyncJobManager.is_sync_active()`. If `True`, return an error response (e.g., `409 Conflict`) indicating that a sync is already in progress. * Call `CurrentSyncJobManager.start_sync(job_type="...")` to initialize the sync job. * Pass the `SyncJob` instance (or a reference to the `CurrentSyncJobManager`) to the background task. * Change the `response_model` to return the initial `SyncJob` status or a simple success message. * **Add New API Endpoint for Status Polling**: * `GET /garmin/sync/status`: * **Response Model**: `SyncJob` * **Description**: Returns the current status of the single active sync job. If no sync is active, it returns an "idle" status `SyncJob`. ### 5. Update Dependencies and Main Application * **`backend/src/dependencies.py`**: Remove any references to the old `job_store` and `SyncStatusService`. * **`backend/src/main.py`**: Ensure the `CurrentSyncJobManager` is properly initialized and accessible (e.g., as a global or via dependency injection if preferred). ## Impact * **Progress Tracking**: Users can now poll a dedicated API endpoint to get real-time progress updates for the single active sync job. * **Clearer State**: The system's state regarding sync operations is more transparent. * **Controlled Concurrency**: Only one sync operation can run at a time, preventing resource contention in a single-user environment. * **Simplified API**: No need to manage multiple job IDs. The status endpoint always refers to the current operation. * **Minimal Overhead**: Avoids the complexity of a full-blown job queue and distributed job management system, suitable for a single-user application.