mirror of
https://github.com/sstent/FitTrack_GarminSync.git
synced 2026-01-25 08:35:23 +00:00
feat: Implement Garmin sync, login improvements, and utility scripts
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
# Specification Quality Checklist: Garmin Login Improvements
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
||||
**Created**: Friday, October 10, 2025
|
||||
**Feature**: [Link to spec.md]
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [X] No implementation details (languages, frameworks, APIs)
|
||||
- [X] Focused on user value and business needs
|
||||
- [X] Written for non-technical stakeholders
|
||||
- [X] All mandatory sections completed
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [X] No [NEEDS CLARIFICATION] markers remain
|
||||
- [X] Requirements are testable and unambiguous
|
||||
- [X] Success criteria are measurable
|
||||
- [X] Success criteria are technology-agnostic (no implementation details)
|
||||
- [X] All acceptance scenarios are defined
|
||||
- [X] Edge cases are identified
|
||||
- [X] Scope is clearly bounded
|
||||
- [X] Dependencies and assumptions identified
|
||||
|
||||
## Feature Readiness
|
||||
|
||||
- [X] All functional requirements have clear acceptance criteria
|
||||
- [X] User scenarios cover primary flows
|
||||
- [X] Feature meets measurable outcomes defined in Success Criteria
|
||||
- [X] No implementation details leak into specification
|
||||
|
||||
## Notes
|
||||
|
||||
- Items marked incomplete require spec updates before `/speckit.clarify` or `/speckit.plan`
|
||||
@@ -0,0 +1,93 @@
|
||||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "Garmin Authentication API",
|
||||
"version": "1.0.0",
|
||||
"description": "API for authenticating with Garmin Connect and managing credentials."
|
||||
},
|
||||
"paths": {
|
||||
"/login": {
|
||||
"post": {
|
||||
"summary": "Authenticate with Garmin Connect",
|
||||
"description": "Allows a user to provide Garmin Connect credentials to authenticate and store tokens for the FitTrack Garmin Sync service. This endpoint is publicly accessible.",
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": ["username", "password"],
|
||||
"properties": {
|
||||
"username": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Garmin Connect username (email address)"
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"format": "password",
|
||||
"description": "Garmin Connect password"
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"username": "user@example.com",
|
||||
"password": "myGarminPassword"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Garmin account linked successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string",
|
||||
"example": "Garmin account linked successfully."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Authentication failed",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detail": {
|
||||
"type": "string",
|
||||
"example": "Invalid Garmin credentials provided."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal server error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detail": {
|
||||
"type": "string",
|
||||
"example": "An unexpected error occurred during Garmin authentication."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
specs/003-loginimprovements-use-the/data-model.md
Normal file
19
specs/003-loginimprovements-use-the/data-model.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Data Model: Garmin Login Improvements
|
||||
|
||||
## Entity: GarminCredentials
|
||||
|
||||
Represents the stored Garmin authentication information.
|
||||
|
||||
### Attributes:
|
||||
- `garmin_username` (string): The Garmin Connect account username (email).
|
||||
- `garmin_password_plaintext` (string): The plaintext password for the Garmin Connect account.
|
||||
- `access_token` (string): The Garmin Connect access token.
|
||||
- `access_token_secret` (string): The Garmin Connect access token secret.
|
||||
- `token_expiration_date` (datetime): The expiration date and time of the access token.
|
||||
|
||||
### Relationships:
|
||||
- Stored in `centralDB`.
|
||||
|
||||
### Validation Rules:
|
||||
- `garmin_username` and `garmin_password_plaintext` are required for initial login.
|
||||
- `access_token`, `access_token_secret`, and `token_expiration_date` are generated upon successful Garmin authentication and are required for subsequent token refreshes and sync operations.
|
||||
113
specs/003-loginimprovements-use-the/plan.md
Normal file
113
specs/003-loginimprovements-use-the/plan.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# Implementation Plan: [FEATURE]
|
||||
|
||||
**Branch**: `[###-feature-name]` | **Date**: [DATE] | **Spec**: [link]
|
||||
**Input**: Feature specification from `/specs/[###-feature-name]/spec.md`
|
||||
|
||||
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/commands/plan.md` for the execution workflow.
|
||||
|
||||
## Summary
|
||||
|
||||
[Extract from feature spec: primary requirement + technical approach from research]
|
||||
|
||||
## Technical Context
|
||||
|
||||
<!--
|
||||
ACTION REQUIRED: Replace the content in this section with the technical details
|
||||
for the project. The structure here is presented in advisory capacity to guide
|
||||
the iteration process.
|
||||
-->
|
||||
|
||||
**Language/Version**: Python 3.13
|
||||
**Primary Dependencies**: FastAPI, garth, garminconnect, httpx, pydantic
|
||||
**Storage**: centralDB (PostgreSQL/SQLite with SQLAlchemy)
|
||||
**Testing**: pytest
|
||||
**Target Platform**: Linux server
|
||||
**Project Type**: Web (backend service)
|
||||
**Performance Goals**: SC-001: Login within 10s; SC-003: Error response within 2s.
|
||||
**Constraints**: Stateless API caller (no cookies); Single-user system; Automatic token refresh.
|
||||
**Scale/Scope**: Single user, managing Garmin Connect data.
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
- **Python Modernization**: Compliant (Python 3.13, type hints, dataclasses for schemas).
|
||||
- **Virtual Environment Isolation**: Compliant (project uses .venv, dependencies pinned).
|
||||
- **Test-Driven Development**: Compliant (spec includes tests, pytest is used).
|
||||
- **Containerization Standards**: Compliant (project uses Docker Compose).
|
||||
- **Project Structure Standards**: Compliant (modifies existing src/api and src/services).
|
||||
- **Service-Specific Standards (garmin_sync_service)**: Compliant (implements Garmin Connect OAuth flow).
|
||||
- **API Standards**: Compliant (FastAPI, OpenAPI, structured errors).
|
||||
- **Code Quality Standards**: Compliant (Black, Flake8, Mypy, Isort).
|
||||
|
||||
No violations detected.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```
|
||||
specs/[###-feature]/
|
||||
├── plan.md # This file (/speckit.plan command output)
|
||||
├── research.md # Phase 0 output (/speckit.plan command)
|
||||
├── data-model.md # Phase 1 output (/speckit.plan command)
|
||||
├── quickstart.md # Phase 1 output (/speckit.plan command)
|
||||
├── contracts/ # Phase 1 output (/speckit.plan command)
|
||||
└── tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan)
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
<!--
|
||||
ACTION REQUIRED: Replace the placeholder tree below with the concrete layout
|
||||
for this feature. Delete unused options and expand the chosen structure with
|
||||
real paths (e.g., apps/admin, packages/something). The delivered plan must
|
||||
not include Option labels.
|
||||
-->
|
||||
|
||||
```
|
||||
# [REMOVE IF UNUSED] Option 1: Single project (DEFAULT)
|
||||
src/
|
||||
├── models/
|
||||
├── services/
|
||||
├── cli/
|
||||
└── lib/
|
||||
|
||||
tests/
|
||||
├── contract/
|
||||
├── integration/
|
||||
└── unit/
|
||||
|
||||
# [REMOVE IF UNUSED] Option 2: Web application (when "frontend" + "backend" detected)
|
||||
backend/
|
||||
├── src/
|
||||
│ ├── models/
|
||||
│ ├── services/
|
||||
│ └── api/
|
||||
└── tests/
|
||||
|
||||
frontend/
|
||||
├── src/
|
||||
│ ├── components/
|
||||
│ ├── pages/
|
||||
│ └── services/
|
||||
└── tests/
|
||||
|
||||
# [REMOVE IF UNUSED] Option 3: Mobile + API (when "iOS/Android" detected)
|
||||
api/
|
||||
└── [same as backend above]
|
||||
|
||||
ios/ or android/
|
||||
└── [platform-specific structure: feature modules, UI flows, platform tests]
|
||||
```
|
||||
|
||||
**Structure Decision**: [Document the selected structure and reference the real
|
||||
directories captured above]
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
*Fill ONLY if Constitution Check has violations that must be justified*
|
||||
|
||||
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
||||
|-----------|------------|-------------------------------------|
|
||||
| [e.g., 4th project] | [current need] | [why 3 projects insufficient] |
|
||||
| [e.g., Repository pattern] | [specific problem] | [why direct DB access insufficient] |
|
||||
97
specs/003-loginimprovements-use-the/quickstart.md
Normal file
97
specs/003-loginimprovements-use-the/quickstart.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Quickstart: Garmin Login Improvements
|
||||
|
||||
This guide provides a quick way to test the Garmin login and initial synchronization feature.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* A running instance of the FitTrack Garmin Sync backend.
|
||||
* `curl` installed on your system.
|
||||
|
||||
## 1. Link your Garmin Account
|
||||
|
||||
Send a `POST` request to the `/api/garmin/login` endpoint with your Garmin Connect username (email) and password. This will link your Garmin account with the service and store your credentials for automatic token management.
|
||||
|
||||
**Endpoint**: `POST /api/garmin/login`
|
||||
|
||||
**Example using `curl`**:
|
||||
|
||||
```bash
|
||||
API_BASE_URL="http://localhost:8000" # Adjust if your API is running on a different host/port
|
||||
GARMIN_USERNAME="your_garmin_email@example.com" # Replace with your Garmin email
|
||||
GARMIN_PASSWORD="your_garmin_password" # Replace with your Garmin password
|
||||
|
||||
curl -s -X POST "${API_BASE_URL}/api/garmin/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"username\": \"${GARMIN_USERNAME}\",
|
||||
\"password\": \"${GARMIN_PASSWORD}\"
|
||||
}"
|
||||
```
|
||||
|
||||
**Expected Success Response (200 OK)**:
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Garmin account linked successfully."
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Initiate Garmin Activity Synchronization
|
||||
|
||||
Once your Garmin account is linked, you can trigger an activity synchronization. The backend will implicitly use the stored Garmin credentials. No additional authentication headers are required from the client for this operation.
|
||||
|
||||
**Endpoint**: `POST /api/sync/garmin/activities`
|
||||
|
||||
**Example using `curl`**:
|
||||
|
||||
```bash
|
||||
API_BASE_URL="http://localhost:8000" # Adjust if your API is running on a different host/port
|
||||
|
||||
curl -s -X POST "${API_BASE_URL}/api/sync/garmin/activities" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{}"
|
||||
```
|
||||
|
||||
**Expected Success Response (202 Accepted)**:
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Garmin activity synchronization initiated.",
|
||||
"sync_job_id": "a-uuid-representing-the-sync-job"
|
||||
}
|
||||
```
|
||||
|
||||
## 3. Check Synchronization Status
|
||||
|
||||
After initiating a synchronization job, you can check its status using the `/api/sync/status` endpoint. You will need the `job_id` returned from the synchronization initiation step.
|
||||
|
||||
**Endpoint**: `GET /api/sync/status`
|
||||
|
||||
**Example using `curl`**:
|
||||
|
||||
```bash
|
||||
API_BASE_URL="http://localhost:8000" # Adjust if your API is running on a different host/port
|
||||
JOB_ID="<PASTE_YOUR_JOB_ID_HERE>" # Replace with the job_id from Step 2
|
||||
|
||||
curl -s -X GET "${API_BASE_URL}/api/sync/status?job_id=${JOB_ID}"
|
||||
```
|
||||
|
||||
**Expected Response (200 OK)**:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "a-uuid-representing-the-sync-job",
|
||||
"status": "completed", // or "pending", "in_progress", "failed"
|
||||
"start_time": "2025-10-11T00:00:00.000000",
|
||||
"end_time": "2025-10-11T00:01:00.000000",
|
||||
"progress": 1.0,
|
||||
"error_message": null,
|
||||
"details": {
|
||||
"synced_activities_count": 5,
|
||||
"total_activities_found": 5
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
```
|
||||
11
specs/003-loginimprovements-use-the/research.md
Normal file
11
specs/003-loginimprovements-use-the/research.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Research Findings for Garmin Login Improvements
|
||||
|
||||
## Phase 0: Outline & Research
|
||||
|
||||
### Client Authentication for Sync Operations
|
||||
|
||||
- **Decision**: The API client will not send an `Authorization` header for subsequent sync operations (e.g., `/api/sync/garmin/activities`).
|
||||
- **Rationale**: The feature specification (`spec.md`) explicitly states that "the api caller should not need a cookie - all state should be global for the Garmin Sync service" and that the service operates as a single-user system, implicitly using the stored Garmin credentials after a successful `/api/garmin/login`. This clarifies the discrepancy with the `sync_garmin_activities.json` contract, which showed an `Authorization: Bearer <token>` header.
|
||||
- **Alternatives considered**:
|
||||
- Client sending an `APP_BEARER_TOKEN` (rejected as it contradicts the stateless client requirement).
|
||||
- Client sending a session cookie (rejected as it contradicts the stateless client requirement).
|
||||
86
specs/003-loginimprovements-use-the/spec.md
Normal file
86
specs/003-loginimprovements-use-the/spec.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# Feature Specification: Garmin Login Improvements
|
||||
|
||||
**Feature Branch**: `003-loginimprovements-use-the`
|
||||
**Created**: Friday, October 10, 2025
|
||||
**Status**: Draft
|
||||
**Input**: User description: "Rework the garmin authentication for this app. I want the app to: allow providing a user/pass via the /login endpoint; the app should store the resulting auth tokens and user/pass in the centralDB; the api caller should not need a cookie - all state should be global for the Garmin Sync service"
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Initial Garmin Account Setup (Priority: P1)
|
||||
|
||||
A user wants to link their Garmin account to the FitTrack Garmin Sync service for the first time. They provide their Garmin credentials via the `/login` endpoint. The system successfully authenticates with Garmin, stores the credentials and tokens, and confirms the link.
|
||||
|
||||
**Why this priority**: This is the core functionality enabling users to connect their Garmin accounts, which is fundamental to the service.
|
||||
|
||||
**Independent Test**: Can be fully tested by calling the `/login` endpoint with valid Garmin credentials and verifying that the credentials and tokens are stored in the `centralDB` and subsequent Garmin Sync operations can proceed.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the FitTrack Garmin Sync service is running, **When** a user sends a POST request to `/login` with valid Garmin username and password, **Then** the system successfully authenticates with Garmin, stores the Garmin username, plaintext password, and authentication tokens in the `centralDB`, and returns a success response.
|
||||
2. **Given** the FitTrack Garmin Sync service is running, **When** a user sends a POST request to `/login` with invalid Garmin username or password, **Then** the system returns an error response indicating authentication failure and does not store any credentials or tokens.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Automatic Garmin Token Refresh (Priority: P1)
|
||||
|
||||
After initial setup, the system automatically manages the Garmin authentication tokens, refreshing them as needed without user intervention, to ensure continuous synchronization with Garmin.
|
||||
|
||||
**Why this priority**: Ensures the service remains operational and data synchronization is uninterrupted, providing a seamless user experience.
|
||||
|
||||
**Independent Test**: Can be tested by simulating an expired token scenario and verifying that the system successfully refreshes the token during a subsequent Garmin API call.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** valid Garmin credentials and tokens are stored in the `centralDB`, and the current Garmin authentication token is nearing expiration or has expired, **When** the Garmin Sync service attempts to perform an operation requiring Garmin authentication, **Then** the system automatically refreshes the Garmin authentication token using the stored credentials, updates the `centralDB` with the new tokens, and successfully completes the Garmin operation.
|
||||
2. **Given** valid Garmin credentials and tokens are stored in the `centralDB`, and the current Garmin authentication token is valid, **When** the Garmin Sync service attempts to perform an operation requiring Garmin authentication, **Then** the system uses the existing valid token without attempting a refresh.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Stateless Garmin Sync Operations (Priority: P1)
|
||||
|
||||
The Garmin Sync service operates without relying on session cookies. For every operation requiring Garmin access, it retrieves the necessary authentication tokens from the `centralDB` based on the single-user context.
|
||||
|
||||
**Why this priority**: This is a core architectural requirement for the service to be stateless and not rely on client-side cookies.
|
||||
|
||||
**Independent Test**: Can be tested by performing multiple Garmin Sync operations (e.g., activity download, health metric sync) and verifying that each operation successfully retrieves credentials from the `centralDB` and completes without requiring a prior session.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** valid Garmin credentials and tokens are stored in the `centralDB`, **When** any Garmin Sync operation is initiated, **Then** the service retrieves the necessary Garmin authentication tokens from the `centralDB` for the single user and uses them to authenticate with Garmin.
|
||||
2. **Given** no valid Garmin credentials or tokens are stored in the `centralDB`, **When** any Garmin Sync operation is initiated, **Then** the service returns an error indicating that Garmin authentication is required.
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: The system MUST expose a `/login` endpoint that accepts a Garmin username and password.
|
||||
- **FR-002**: The system MUST authenticate with Garmin using the provided username and password.
|
||||
- **FR-003**: Upon successful Garmin authentication, the system MUST store the Garmin username, plaintext password, and authentication tokens in the `centralDB`.
|
||||
- **FR-004**: The system MUST automatically refresh Garmin authentication tokens when they are expired or nearing expiration.
|
||||
- **FR-005**: The system MUST update the `centralDB` with newly refreshed Garmin authentication tokens.
|
||||
- **FR-006**: The system MUST retrieve Garmin authentication tokens from the `centralDB` for all Garmin Sync operations. **The client is not required to send any authentication header for these operations.**
|
||||
- **FR-007**: The system MUST return an error response to the API caller if Garmin authentication fails (initial login or token refresh).
|
||||
- **FR-008**: The system MUST operate as a single-user system, using the single set of stored Garmin credentials for all operations.
|
||||
- **FR-009**: The `/login` endpoint MUST be publicly accessible without prior authentication.
|
||||
|
||||
## Clarifications
|
||||
|
||||
### Session 2025-10-10
|
||||
|
||||
- Q: How should the client authenticate for subsequent sync operations (e.g., `/api/sync/garmin/activities`) given that the spec states "the api caller should not need a cookie" and "all state should be global for the Garmin Sync service", but the contract for `sync_garmin_activities` shows an `Authorization: Bearer <token>` header? → A: No authentication header is required; the backend implicitly uses the single stored Garmin credentials.
|
||||
|
||||
### Key Entities *(include if feature involves data)*
|
||||
|
||||
- **GarminCredentials**: Represents the stored Garmin authentication information.
|
||||
* Attributes: `garmin_username` (string), `garmin_password_plaintext` (string), `access_token` (string), `access_token_secret` (string), `token_expiration_date` (datetime).
|
||||
* Relationship: Stored in `centralDB`.
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: Users can successfully link their Garmin account via the `/login` endpoint within 10 seconds.
|
||||
- **SC-002**: Garmin data synchronization operations (e.g., activity download) complete without interruption due to expired tokens for 99.9% of attempts.
|
||||
- **SC-003**: The `/login` endpoint correctly handles invalid Garmin credentials, returning an error response within 2 seconds.
|
||||
- **SC-004**: The system maintains continuous Garmin connectivity for 99% of the time without requiring manual re-authentication.
|
||||
76
specs/003-loginimprovements-use-the/tasks.md
Normal file
76
specs/003-loginimprovements-use-the/tasks.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Tasks: Garmin Login Improvements
|
||||
|
||||
**Branch**: `003-loginimprovements-use-the` | **Date**: 2025-10-10 | **Spec**: /home/sstent/Projects/FitTrack_GarminSync/specs/003-loginimprovements-use-the/spec.md
|
||||
|
||||
## Summary
|
||||
|
||||
This plan outlines the implementation of Garmin login improvements, enabling users to link their Garmin accounts via a `/login` endpoint. The system will store credentials, automatically refresh tokens, and operate statelessly for API callers, implicitly using stored Garmin credentials for sync operations.
|
||||
|
||||
## Phase 1: Setup Tasks (Project Initialization)
|
||||
|
||||
- **T001**: Ensure Python 3.13 virtual environment is set up and activated.
|
||||
- **T002**: Install core dependencies: FastAPI, garth, garminconnect, httpx, pydantic.
|
||||
- **T003**: Verify `centralDB` connection and schema for `GarminCredentials` entity.
|
||||
|
||||
## Phase 2: Foundational Tasks (Blocking Prerequisites)
|
||||
|
||||
- **T004**: Implement `GarminCredentials` Pydantic model in `backend/src/schemas.py` based on `data-model.md`.
|
||||
- **T005**: Implement `GarminLoginRequest` and `GarminLoginResponse` Pydantic models in `backend/src/schemas.py` based on `garmin_auth_login.json`.
|
||||
- **T006**: Implement `ActivitySyncRequest` Pydantic model in `backend/src/schemas.py` based on `sync_garmin_activities.json`.
|
||||
- **T007**: Update `CentralDBService` in `backend/src/services/central_db_service.py` to include methods for `create_garmin_credentials`, `get_garmin_credentials`, and `update_garmin_credentials`.
|
||||
- **T008**: Implement `GarminAuthService` in `backend/src/services/garmin_auth_service.py` with `initial_login` method to authenticate with Garmin and return `GarminCredentials`.
|
||||
|
||||
## Phase 3: User Story 1 - Initial Garmin Account Setup (P1)
|
||||
|
||||
**Goal**: User can link their Garmin account via `/api/garmin/login`.
|
||||
**Independent Test Criteria**: Call `/api/garmin/login` with valid/invalid credentials and verify `centralDB` state and response.
|
||||
|
||||
- **T009** [US1]: Implement `/api/garmin/login` endpoint in `backend/src/api/garmin_auth.py` to accept `GarminLoginRequest`.
|
||||
- **T010** [US1]: Integrate `GarminAuthService.initial_login` and `CentralDBService` methods into `/api/garmin/login` endpoint.
|
||||
- **T011** [US1]: Ensure `/api/garmin/login` returns `GarminLoginResponse` on success and appropriate error on failure.
|
||||
- **T012** [US1]: Write unit tests for `/api/garmin/login` endpoint in `backend/tests/api/test_garmin_auth_api.py` covering success and failure scenarios.
|
||||
|
||||
## Phase 4: User Story 3 - Stateless Garmin Sync Operations (P1)
|
||||
|
||||
**Goal**: Garmin Sync operations retrieve tokens from `centralDB` without client-side authentication.
|
||||
**Independent Test Criteria**: Call `/api/sync/garmin/activities` after successful login and verify sync initiation.
|
||||
|
||||
- **T013** [US3]: Modify `get_current_user` dependency in `backend/src/dependencies.py` to retrieve `user_id` implicitly (e.g., from a fixed value for single-user system) and then fetch `GarminCredentials` from `CentralDBService`.
|
||||
- **T014** [US3]: Implement `GarminActivityService` in `backend/src/services/garmin_activity_service.py` to use `GarminCredentials` from `CentralDBService` for Garmin API calls.
|
||||
- **T015** [US3]: Implement `/api/sync/garmin/activities` endpoint in `backend/src/api/garmin_sync.py` to accept `ActivitySyncRequest`.
|
||||
- **T016** [US3]: Integrate `GarminActivityService` into `/api/sync/garmin/activities` endpoint.
|
||||
- **T017** [US3]: Write unit tests for `/api/sync/garmin/activities` endpoint in `backend/tests/api/test_garmin_sync_api.py` covering successful sync initiation.
|
||||
|
||||
## Phase 5: User Story 2 - Automatic Garmin Token Refresh (P1)
|
||||
|
||||
**Goal**: System automatically refreshes Garmin authentication tokens.
|
||||
**Independent Test Criteria**: Simulate expired token and verify refresh during a sync operation.
|
||||
|
||||
- **T018** [US2]: Enhance `GarminAuthService` to include a method for checking token expiration and refreshing tokens.
|
||||
- **T019** [US2]: Integrate token refresh logic into `GarminActivityService` (and other Garmin services) before making Garmin API calls.
|
||||
- **T020** [US2]: Ensure `CentralDBService` is updated with new tokens after refresh.
|
||||
- **T021** [US2]: Write integration tests for automatic token refresh in `backend/tests/integration/test_garmin_token_refresh.py`.
|
||||
|
||||
## Final Phase: Polish & Cross-Cutting Concerns
|
||||
|
||||
- **T022**: Review and update `README.md` with instructions for setting up and running the service.
|
||||
- **T023**: Ensure all new code adheres to project's code quality standards (Black, Flake8, Mypy, Isort).
|
||||
- **T024**: Update `GEMINI.md` with any new technologies or commands.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Phase 1 -> Phase 2
|
||||
- Phase 2 -> Phase 3
|
||||
- Phase 3 -> Phase 4
|
||||
- Phase 4 -> Phase 5
|
||||
- Phase 5 -> Final Phase
|
||||
|
||||
## Parallel Execution Examples
|
||||
|
||||
- **Phase 2**: T004, T005, T006 can be executed in parallel.
|
||||
- **Phase 3 (US1)**: T009, T010, T011 can be executed in parallel after T008.
|
||||
- **Phase 4 (US3)**: T014, T015, T016 can be executed in parallel after T013.
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
We will follow an MVP-first approach, delivering User Story 1, then User Story 3, and finally User Story 2. This ensures core login and stateless sync functionality is established before implementing automatic token refresh.
|
||||
Reference in New Issue
Block a user