feat: Initial implementation of FitTrack Report Generator

This commit introduces the initial version of the FitTrack Report Generator, a FastAPI application for analyzing workout files.

Key features include:
- Parsing of FIT, TCX, and GPX workout files.
- Analysis of power, heart rate, speed, and elevation data.
- Generation of summary reports and charts.
- REST API for single and batch workout analysis.

The project structure has been set up with a `src` directory for core logic, an `api` directory for the FastAPI application, and a `tests` directory for unit, integration, and contract tests.

The development workflow is configured to use Docker and modern Python tooling.
This commit is contained in:
2025-10-11 09:54:13 -07:00
parent 6643a64ff0
commit 9e0bd322d3
152 changed files with 25695 additions and 49 deletions

View File

@@ -0,0 +1,34 @@
# Specification Quality Checklist: Initial Spec
**Purpose**: Validate specification completeness and quality before proceeding to planning
**Created**: 2025-10-09
**Feature**: [spec.md](./../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
All checks have passed. The specification is ready for the next phase.

View File

@@ -0,0 +1,238 @@
openapi: 3.0.0
info:
title: FitTrack Report Generator API
version: 1.0.0
description: API for analyzing workout files and generating reports.
servers:
- url: /api
description: Base API path
paths:
/analyze/workout:
post:
summary: Analyze a single workout file
description: Uploads a single workout file (FIT, TCX, or GPX) for comprehensive analysis.
operationId: analyzeSingleWorkout
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
properties:
file:
type: string
format: binary
description: The workout file (FIT, TCX, or GPX) to analyze.
user_id:
type: string
format: uuid
description: Optional user ID to associate the analysis with.
ftp_value:
type: number
format: float
description: Optional Functional Threshold Power (FTP) value for calculations. Overrides user's default if provided.
required:
- file
responses:
'200':
description: Analysis successful. Returns a summary of the analysis.
content:
application/json:
schema:
$ref: '#/components/schemas/WorkoutAnalysisSummary'
'400':
description: Invalid input or file format.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/analyze/batch:
post:
summary: Analyze multiple workout files in a batch
description: Uploads a directory (as a zip file) of workout files for batch analysis and generates a summary report.
operationId: analyzeBatchWorkouts
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
properties:
zip_file:
type: string
format: binary
description: A zip file containing multiple workout files (FIT, TCX, or GPX).
user_id:
type: string
format: uuid
description: Optional user ID to associate the analysis with.
ftp_value:
type: number
format: float
description: Optional Functional Threshold Power (FTP) value for calculations. Overrides user's default if provided.
required:
- zip_file
responses:
'200':
description: Batch analysis initiated. Returns a summary of the batch process.
content:
application/json:
schema:
type: object
properties:
batch_id:
type: string
format: uuid
description: Unique ID for the batch analysis.
status:
type: string
description: Status of the batch analysis (e.g., 'processing', 'completed').
total_files:
type: integer
description: Total number of files submitted in the batch.
'400':
description: Invalid input or file format.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/analysis/{analysis_id}/charts:
get:
summary: Retrieve generated charts for a specific analysis
description: Returns a PNG image of the requested chart for a previously analyzed workout.
operationId: getAnalysisCharts
parameters:
- name: analysis_id
in: path
required: true
schema:
type: string
format: uuid
description: The ID of the workout analysis.
- name: chart_type
in: query
required: true
schema:
type: string
enum: [power_curve, elevation_profile, zone_distribution_power, zone_distribution_hr, zone_distribution_speed]
description: The type of chart to retrieve.
responses:
'200':
description: Chart image successfully retrieved.
content:
image/png:
schema:
type: string
format: binary
'404':
description: Analysis or chart not found.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/analysis/{analysis_id}/summary:
get:
summary: Retrieve a summary of a specific analysis
description: Returns a detailed summary of a previously analyzed workout.
operationId: getAnalysisSummary
parameters:
- name: analysis_id
in: path
required: true
schema:
type: string
format: uuid
description: The ID of the workout analysis.
responses:
'200':
description: Analysis summary successfully retrieved.
content:
application/json:
schema:
$ref: '#/components/schemas/WorkoutAnalysisSummary'
'404':
description: Analysis not found.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
components:
schemas:
WorkoutAnalysisSummary:
type: object
properties:
analysis_id:
type: string
format: uuid
description: Unique ID of the analysis.
user_id:
type: string
format: uuid
description: User ID associated with the analysis.
file_name:
type: string
description: Original name of the analyzed file.
analysis_date:
type: string
format: date-time
description: Timestamp of the analysis.
status:
type: string
description: Status of the analysis (e.g., 'completed', 'failed').
metrics:
type: object
description: Key metrics from the workout analysis (e.g., duration, distance, NP, IF, TSS).
additionalProperties: true
report_url:
type: string
format: url
description: URL to the generated report.
chart_urls:
type: object
description: URLs to generated charts.
additionalProperties:
type: string
format: url
ErrorResponse:
type: object
properties:
code:
type: string
description: A unique error code.
message:
type: string
description: A human-readable error message.
details:
type: object
description: Optional additional error details.
additionalProperties: true

View File

@@ -0,0 +1,66 @@
# Data Model
## Entities
### User
- **Description**: Represents a user of the system, primarily for storing personalized settings.
- **Fields**:
- `id`: Unique identifier (e.g., UUID)
- `ftp_value`: Configured Functional Threshold Power (float, nullable, default value if null)
- **Relationships**: One-to-many with `WorkoutAnalysis` (a user can have multiple analyses).
- **Validation Rules**: `ftp_value` must be a positive number if set.
### WorkoutAnalysis
- **Description**: Represents the result of analyzing a single workout file. This entity links a user to their analyzed workout data.
- **Fields**:
- `id`: Unique identifier (e.g., UUID)
- `user_id`: Foreign key to `User.id`
- `file_name`: Original name of the workout file (string)
- `analysis_date`: Timestamp of when the analysis was performed (datetime)
- `status`: Status of the analysis (e.g., 'completed', 'failed', 'processing')
- `summary_metrics`: JSONB field for storing overall workout summary metrics (e.g., total distance, duration, average speed, etc.)
- `report_path`: Path to the generated report (string)
- `chart_paths`: JSONB field for storing paths to generated charts (e.g., `{'power_curve': '/path/to/chart.png'}`)
- **Relationships**: Many-to-one with `User`.
### WorkoutData (Conceptual/In-Memory Structure)
- **Description**: Represents the complete raw and processed data for a single workout session. This is primarily an in-memory object during analysis and its key components are persisted in `WorkoutAnalysis`.
- **Fields**:
- `metadata`: `WorkoutMetadata` object
- `time_series_data`: Pandas DataFrame containing raw time-series data (e.g., timestamp, power, heart rate, speed, elevation)
- `power_data`: `PowerData` object
- `heart_rate_data`: `HeartRateData` object
- `speed_data`: `SpeedData` object (derived from time-series)
- `elevation_data`: `ElevationData` object (derived from time-series)
### WorkoutMetadata
- **Description**: Metadata extracted from the workout file.
- **Fields**:
- `start_time`: Datetime of workout start
- `duration`: Total duration (timedelta or seconds)
- `device`: Device used for recording (string)
- `file_type`: Original file type (e.g., 'FIT', 'TCX', 'GPX')
### PowerData
- **Description**: Contains all power-related analysis results.
- **Fields**:
- `raw_power_stream`: List of power values
- `average_power`: Float
- `normalized_power`: Float
- `intensity_factor`: Float
- `training_stress_score`: Float
- `zone_distribution`: Dictionary/JSONB of time spent in each power zone
### HeartRateData
- **Description**: Contains all heart-rate-related analysis results.
- **Fields**:
- `raw_hr_stream`: List of heart rate values
- `average_hr`: Float
- `max_hr`: Integer
- `zone_distribution`: Dictionary/JSONB of time spent in each heart rate zone
### ZoneCalculator (Utility)
- **Description**: A utility class/module for defining and calculating training zones based on user-specific thresholds (like FTP) or default values.
- **Fields**: (Methods for calculation, not data fields)
- `calculate_power_zones(ftp, max_power)`
- `calculate_heart_rate_zones(max_hr)`

View File

@@ -0,0 +1,108 @@
# 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.11
**Primary Dependencies**: FastAPI, pandas, numpy, scipy, matplotlib, fitparse, tcxparser, gpxpy
**Storage**: PostgreSQL (for user data and analysis results)
**Testing**: pytest
**Target Platform**: Linux server
**Project Type**: web
**Performance Goals**: Analysis of a typical 2-hour workout file MUST complete in under 30 seconds; processing a batch of 100 workout files concurrently without generating errors or significant performance degradation.
**Constraints**: Public API (no authentication); errors reported as JSON objects; best effort service availability.
**Scale/Scope**: Batch analysis of up to 100 workout files concurrently; configurable FTP per user account.
## Constitution Check
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
| Principle | Status | Justification (if violation) |
|---|---|---|
| I. Library-First | Aligned | Core analysis logic will be implemented as a reusable library. |
| II. CLI Interface | VIOLATION | The primary interface is an API, not a CLI. Justification: The feature is designed as a web service with API endpoints for integration. A CLI could be added later if needed for specific use cases, but it's not the primary requirement for this feature. |
| III. Test-First (NON-NEGOTIABLE) | Aligned | User scenarios and acceptance criteria are defined, supporting a test-first approach. |
| IV. Integration Testing | Aligned | API endpoints and batch processing necessitate integration tests. |
| V. Observability | Aligned | Error reporting and service availability imply the need for observability. |
| VI. Versioning & Breaking Changes | Aligned | Will consider API versioning as part of the design. |
| VII. Simplicity | Aligned | Focus on core analysis functionality. |
## 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)
```
src/
├── core/
│ ├── batch_processor.py
│ ├── chart_generator.py
│ ├── file_parser.py
│ ├── logger.py
│ ├── report_generator.py
│ ├── workout_analyzer.py
│ └── workout_data.py
├── db/
│ ├── models.py
│ └── session.py
└── utils/
└── zone_calculator.py
api/
├── routers/
│ └── analysis.py
├── main.py
└── schemas.py
tests/
├── unit/
│ ├── test_batch_processor.py
│ ├── test_chart_generator.py
│ ├── test_fit_parser.py
│ ├── test_gpx_parser.py
│ ├── test_tcx_parser.py
│ └── test_workout_data.py
├── integration/
└── contract/
├── test_analyze_workout_api.py
├── test_batch_analysis_api.py
└── test_charts_api.py
├── performance/
│ └── test_performance.py
```
**Structure Decision**: The project will use a `src/` directory for core logic, `api/` for the FastAPI application, and `tests/` for all testing types. This aligns with a modular web application structure.
## 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] |

View File

@@ -0,0 +1,137 @@
# Quickstart Guide: FitTrack Report Generator API
This guide provides a quick overview of how to interact with the FitTrack Report Generator API.
## Base URL
The base URL for all API endpoints is `/api`.
## 1. Analyze a Single Workout File
To analyze a single workout file, send a `POST` request to the `/analyze/workout` endpoint with the workout file and optional user/FTP information.
### Endpoint
`POST /api/analyze/workout`
### Request Example (using `curl`)
```bash
curl -X POST \
-H "Content-Type: multipart/form-data" \
-F "file=@/path/to/your/workout.fit" \
-F "user_id=a1b2c3d4-e5f6-7890-1234-567890abcdef" \
-F "ftp_value=250" \
http://localhost:8000/api/analyze/workout
```
### Response Example (200 OK)
```json
{
"analysis_id": "f1e2d3c4-b5a6-9876-5432-10fedcba9876",
"user_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
"file_name": "workout.fit",
"analysis_date": "2025-10-09T10:30:00Z",
"status": "completed",
"metrics": {
"duration": "01:00:00",
"distance_km": 25.5,
"normalized_power_watts": 220,
"intensity_factor": 0.88,
"tss": 75
},
"report_url": "/api/analysis/f1e2d3c4-b5a6-9876-5432-10fedcba9876/report",
"chart_urls": {
"power_curve": "/api/analysis/f1e2d3c4-b5a6-9876-5432-10fedcba9876/charts?chart_type=power_curve"
}
}
```
## 2. Analyze Multiple Workout Files (Batch)
To analyze multiple workout files, compress them into a `.zip` file and send a `POST` request to the `/analyze/batch` endpoint.
### Endpoint
`POST /api/analyze/batch`
### Request Example (using `curl`)
```bash
curl -X POST \
-H "Content-Type: multipart/form-data" \
-F "zip_file=@/path/to/your/workouts.zip" \
-F "user_id=a1b2c3d4-e5f6-7890-1234-567890abcdef" \
http://localhost:8000/api/analyze/batch
```
### Response Example (200 OK)
```json
{
"batch_id": "g1h2i3j4-k5l6-7890-1234-567890abcdef",
"status": "processing",
"total_files": 10
}
```
## 3. Retrieve Charts for an Analysis
To get a specific chart for a previously analyzed workout, send a `GET` request to the `/analysis/{analysis_id}/charts` endpoint.
### Endpoint
`GET /api/analysis/{analysis_id}/charts`
### Path Parameters
- `analysis_id`: The unique ID of the workout analysis.
### Query Parameters
- `chart_type`: The type of chart to retrieve (e.g., `power_curve`, `elevation_profile`, `zone_distribution_power`).
### Request Example
```bash
curl -X GET http://localhost:8000/api/analysis/f1e2d3c4-b5a6-9876-5432-10fedcba9876/charts?chart_type=power_curve
```
### Response
Returns a PNG image of the requested chart.
## 4. Retrieve Analysis Summary
To get a detailed summary of a previously analyzed workout, send a `GET` request to the `/analysis/{analysis_id}/summary` endpoint.
### Endpoint
`GET /api/analysis/{analysis_id}/summary`
### Path Parameters
- `analysis_id`: The unique ID of the workout analysis.
### Request Example
```bash
curl -X GET http://localhost:8000/api/analysis/f1e2d3c4-b5a6-9876-5432-10fedcba9876/summary
```
### Response Example (200 OK)
```json
{
"analysis_id": "f1e2d3c4-b5a6-9876-5432-10fedcba9876",
"user_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
"file_name": "workout.fit",
"analysis_date": "2025-10-09T10:30:00Z",
"status": "completed",
"metrics": {
"duration": "01:00:00",
"distance_km": 25.5,
"normalized_power_watts": 220,
"intensity_factor": 0.88,
"tss": 75
},
"report_url": "/api/analysis/f1e2d3c4-b5a6-9876-5432-10fedcba9876/report",
"chart_urls": {
"power_curve": "/api/analysis/f1e2d3c4-b5a6-9876-5432-10fedcba9876/charts?chart_type=power_curve"
}
}
```

View File

@@ -0,0 +1,49 @@
# Research Findings
## Decision: Python 3.11
**Rationale**: Modern Python version offering performance improvements and new features.
**Alternatives considered**: Python 3.9, 3.10 (older, less performant).
## Decision: FastAPI for API Development
**Rationale**: High performance, easy to use, automatic OpenAPI documentation, and strong typing with Pydantic. Well-suited for building robust APIs quickly.
**Alternatives considered**: Flask (less batteries-included, requires more setup for features like validation and documentation), Django (more heavyweight, better for full-stack web applications with ORM and admin panel).
## Decision: Pandas, NumPy, SciPy for Data Analysis
**Rationale**: Industry-standard libraries for numerical operations, data manipulation, and scientific computing in Python. Essential for processing workout data efficiently.
**Alternatives considered**: Custom implementations (time-consuming, error-prone), R (different ecosystem).
## Decision: fitparse, tcxparser, gpxpy for File Parsing
**Rationale**: Dedicated and well-maintained libraries for parsing common workout file formats (FIT, TCX, GPX).
**Alternatives considered**: Manual parsing (complex, error-prone), other less mature libraries.
## Decision: Matplotlib for Chart Generation
**Rationale**: Powerful and flexible library for creating static, interactive, and animated visualizations in Python. Can generate various chart types required by the specification.
**Alternatives considered**: Plotly (more interactive, but potentially more complex for basic static charts), Seaborn (built on Matplotlib, good for statistical plots).
## Decision: PostgreSQL for Data Storage
**Rationale**: Robust, open-source relational database with strong support for complex queries, data integrity, and scalability. Suitable for storing user configurations (FTP) and analysis results.
**Alternatives considered**: SQLite (simpler, file-based, less suitable for concurrent access or larger deployments), MySQL (similar to PostgreSQL, but PostgreSQL often preferred for its advanced features and open-source nature).
## Decision: Pytest for Testing
**Rationale**: Popular, easy-to-use, and powerful testing framework for Python. Supports various testing styles (unit, integration, functional) and has a rich plugin ecosystem.
**Alternatives considered**: unittest (built-in, but often considered less ergonomic than pytest).
## Decision: Linux Server as Target Platform
**Rationale**: Standard and cost-effective platform for deploying Python web applications.
**Alternatives considered**: Windows Server (less common for Python web apps), cloud-specific platforms (can be used on top of Linux).

View File

@@ -0,0 +1,114 @@
# Feature Specification: Initial Spec
**Feature Branch**: `001-create-a-new`
**Created**: 2025-10-09
**Status**: Draft
**Input**: User description: "create a new feature called "Initial Spec" based on the content of @initialspec.md"
## Clarifications
### Session 2025-10-09
- Q: How should the API endpoints be secured? → A: No authentication required (public API).
- Q: When the system encounters a corrupted or invalid workout file, how should it report the error? → A: A JSON object in the API response.
- Q: The original spec mentioned `_calculate_hr_recovery` was not implemented. Should heart rate recovery analysis be included in the scope for this feature? → A: No, defer it to a future feature.
- Q: The underlying analysis functions use a default FTP (Functional Threshold Power). Should the FTP value be configurable for TSS/IF calculations? → A: Yes, make it configurable per user account.
- Q: What is the target service availability for the analysis API? → A: Best effort (development/internal tool).
## User Scenarios & Testing *(mandatory)*
### User Story 1 - Analyze a single workout file (Priority: P1)
As a data analyst, I want to upload a single workout file (FIT, TCX, or GPX) and receive a comprehensive analysis report so that I can understand the performance characteristics of that workout.
**Why this priority**: This is the core functionality of the application and provides the primary value to the user.
**Independent Test**: Can be fully tested by providing a single workout file and verifying that a complete report is generated with all expected metrics and charts.
**Acceptance Scenarios**:
1. **Given** a valid FIT file containing power data, **When** the user submits it for analysis, **Then** the system generates a report including NP, IF, TSS, and power zone distribution.
2. **Given** a valid GPX file without power data, **When** the user submits it for analysis, **Then** the system estimates power and generates a report with the estimated power metrics.
---
### User Story 2 - Generate specific charts for a workout (Priority: P2)
As a developer, I want to request specific visualizations (e.g., power curve, elevation profile) for an analyzed workout via an API so that I can integrate these charts into a custom dashboard.
**Why this priority**: Enables integration with other systems and provides flexibility for developers.
**Independent Test**: Can be tested by calling an API endpoint with a workout ID and chart type, and verifying that the correct chart image is returned.
**Acceptance Scenarios**:
1. **Given** a workout has been successfully analyzed, **When** a developer requests the `power_curve` chart via the API, **Then** the system returns a PNG image of the power curve.
2. **Given** an invalid workout ID, **When** a developer requests a chart, **Then** the system returns a 404 Not Found error.
---
### User Story 3 - Batch analyze multiple workout files (Priority: P3)
As a coach, I want to upload a directory of workout files and receive a summary report comparing the key metrics across all workouts so that I can track my athletes' progress over time.
**Why this priority**: Provides a powerful feature for users who need to analyze large amounts of data.
**Independent Test**: Can be tested by providing a directory of workout files and verifying that a batch analysis is performed and a summary report is generated.
**Acceptance Scenarios**:
1. **Given** a directory containing 10 valid workout files, **When** the user submits the directory for batch analysis, **Then** the system processes all 10 files and generates a summary CSV file with key metrics for each workout.
---
### Edge Cases
- **Corrupted Files**: How does the system handle a workout file that is corrupted or malformed? It should fail gracefully and report the error for the specific file as a JSON object in the API response.
- **Missing Data**: What happens if a workout file is missing a critical data stream (e.g., timestamp, distance)? The system should report the missing data and calculate metrics that are possible with the available data.
- **Data Spikes**: How does the system handle data with significant spikes or anomalies (e.g., a power reading of 5000W)? The system should detect and flag these spikes in the analysis.
## Requirements *(mandatory)*
### Functional Requirements
- **FR-001**: System MUST parse FIT, TCX, and GPX workout files.
- **FR-002**: System MUST calculate summary metrics including duration, distance, speed, power, and heart rate.
- **FR-003**: System MUST perform detailed power analysis, including Normalized Power (NP), Intensity Factor (IF), Training Stress Score (TSS), power zones, and power distribution.
- **FR-004**: System MUST perform detailed heart rate analysis, including time in zones and distribution.
- **FR-005**: System MUST perform detailed speed analysis, including time in speed zones and distribution.
- **FR-006**: System MUST perform elevation analysis, including total ascent/descent and gradient.
- **FR-007**: System MUST detect high-intensity intervals based on power output.
- **FR-008**: System MUST calculate efficiency metrics, such as the power-to-heart-rate ratio.
- **FR-009**: System MUST estimate power data when it is not present in the source file.
- **FR-010**: System MUST be able to analyze gear usage for single-speed bicycles.
- **FR-011**: System MUST generate analysis reports in HTML, PDF, and Markdown formats.
- **FR-012**: System MUST generate charts, including power curves, elevation profiles, and zone distribution charts.
- **FR-013**: System MUST provide a `POST /api/analyze/workout` endpoint to analyze a single workout file.
- **FR-014**: System MUST provide a `POST /api/analyze/batch` endpoint to analyze a directory of workout files.
- **FR-015**: System MUST provide a `GET /api/analysis/{id}/charts` endpoint to retrieve generated charts for a specific analysis.
- **FR-016**: System MUST provide a `GET /api/analysis/{id}/summary` endpoint to retrieve a summary of a specific analysis.
- **FR-017**: System MUST expose the API endpoints publicly with no authentication mechanism.
- **FR-018**: System MUST allow users to configure their FTP value.
- **FR-019**: The system MUST use the user's configured FTP for all relevant calculations (TSS, IF). If not configured, a default value will be used.
### Key Entities
- **User**: Represents a user of the system. Key attributes include a unique identifier and their configured FTP value.
- **WorkoutData**: Represents a complete workout session, containing all raw and processed data. Key attributes include metadata, a dataframe of the raw time-series data, and dedicated objects for power, heart rate, speed, and elevation data.
- **WorkoutMetadata**: Contains metadata about the workout, such as start time, duration, and the device used.
- **PowerData**: Holds all power-related information, including the raw power stream, average power, normalized power, and zone distribution.
- **HeartRateData**: Holds all heart-rate-related information, including the raw HR stream, average HR, max HR, and zone distribution.
- **ZoneCalculator**: A utility entity used to define and calculate training zones for different metrics like power and heart rate.
### Out of Scope
- **Heart Rate Recovery Analysis**: The calculation and analysis of heart rate recovery is explicitly out of scope for this feature and will be considered for a future release.
## Success Criteria *(mandatory)*
### Measurable Outcomes
- **SC-001**: The system MUST successfully parse over 99% of valid FIT, TCX, and GPX files from major device manufacturers (Garmin, Wahoo).
- **SC-002**: The analysis of a typical 2-hour workout file MUST complete in under 30 seconds on standard hardware.
- **SC-003**: The variance between key calculated metrics (NP, IF, TSS) and the values produced by industry-standard software like GoldenCheetah or TrainingPeaks MUST be less than 5%.
- **SC-004**: The system MUST be capable of processing a batch of 100 workout files concurrently without generating errors or significant performance degradation.
- **SC-005**: The service will be provided on a "best effort" basis, suitable for development and internal use, with no strict uptime guarantee.

View File

@@ -0,0 +1,129 @@
# Tasks: Initial Spec
**Feature Branch**: `001-create-a-new`
**Date**: 2025-10-09
**Spec**: /home/sstent/Projects/FitTrack_ReportGenerator/specs/001-create-a-new/spec.md
## Summary
This document outlines the tasks required to implement the "Initial Spec" feature, which involves analyzing workout files, generating reports and charts, and exposing this functionality via a REST API.
## Phase 1: Setup and Project Initialization
**Goal**: Establish the basic project structure, environment, and initial configurations.
- [X] T001: Initialize Python project with `pyproject.toml` and create a virtual environment. (src/)
- [X] T002: Create `src/core`, `src/db`, `src/utils`, `api/`, `api/routers`, `tests/unit`, `tests/integration`, `tests/contract` directories. (src/, api/, tests/)
- [X] T003: Configure `pytest` for testing. (pyproject.toml)
- [X] T004: Add initial `requirements.txt` with `FastAPI`, `pandas`, `numpy`, `scipy`, `matplotlib`, `fitparse`, `tcxparser`, `gpxpy`, `psycopg2-binary` (for PostgreSQL). (requirements.txt)
- [X] T005: Implement basic FastAPI application in `api/main.py` with a root endpoint. (api/main.py)
- [X] T006: Set up Dockerfile for the application. (Dockerfile)
## Phase 2: Foundational Components
**Goal**: Implement core, reusable components that are prerequisites for all user stories.
- [X] T007: Implement `src/db/models.py` for `User` and `WorkoutAnalysis` entities based on `data-model.md`. (src/db/models.py)
- [X] T008: Implement database connection and session management in `src/db/session.py`. (src/db/session.py)
- [X] T009: Implement `src/utils/zone_calculator.py` for calculating power and heart rate zones. (src/utils/zone_calculator.py)
- [X] T010: Implement base classes/interfaces for file parsing in `src/core/file_parser.py` (e.g., `FitParser`, `TcxParser`, `GpxParser`). (src/core/file_parser.py)
- [X] T011: Implement `src/core/workout_data.py` for `WorkoutData`, `WorkoutMetadata`, `PowerData`, `HeartRateData` objects. (src/core/workout_data.py)
## Phase 3: User Story 1 - Analyze a single workout file (P1)
**Goal**: Enable users to upload a single workout file and receive a comprehensive analysis report.
**Independent Test Criteria**: Provide a single workout file and verify that a complete report is generated with all expected metrics and charts.
- [X] T012 [US1]: Write unit tests for `FitParser` to ensure correct parsing of FIT files. (tests/unit/test_fit_parser.py)
- [X] T013 [US1]: Implement `FitParser` in `src/core/file_parser.py` to parse FIT files (FR-001). (src/core/file_parser.py)
- [X] T014 [US1]: Write unit tests for `TcxParser` to ensure correct parsing of TCX files. (tests/unit/test_tcx_parser.py)
- [X] T015 [US1]: Implement `TcxParser` in `src/core/file_parser.py` to parse TCX files (FR-001). (src/core/file_parser.py)
- [X] T016 [US1]: Write unit tests for `GpxParser` to ensure correct parsing of GPX files. (tests/unit/test_gpx_parser.py)
- [X] T017 [US1]: Implement `GpxParser` in `src/core/file_parser.py` to parse GPX files (FR-001). (src/core/file_parser.py)
- [X] T018 [US1]: Write unit tests for `WorkoutData` and related data objects (`PowerData`, `HeartRateData`). (tests/unit/test_workout_data.py)
- [X] T019 [US1]: Implement `src/core/workout_analyzer.py` to calculate summary metrics (FR-002). (src/core/workout_analyzer.py)
- [X] T020 [US1]: Implement detailed power analysis (NP, IF, TSS, zones) in `src/core/workout_analyzer.py` (FR-003). (src/core/workout_analyzer.py)
- [X] T021 [US1]: Implement detailed heart rate analysis (zones) in `src/core/workout_analyzer.py` (FR-004). (src/core/workout_analyzer.py)
- [X] T022 [US1]: Implement detailed speed analysis (zones) in `src/core/workout_analyzer.py` (FR-005). (src/core/workout_analyzer.py)
- [X] T023 [US1]: Implement elevation analysis in `src/core/workout_analyzer.py` (FR-006). (src/core/workout_analyzer.py)
- [X] T024 [US1]: Implement high-intensity interval detection in `src/core/workout_analyzer.py` (FR-007). (src/core/workout_analyzer.py)
- [X] T025 [US1]: Implement efficiency metrics calculation in `src/core/workout_analyzer.py` (FR-008). (src/core/workout_analyzer.py)
- [X] T026 [US1]: Implement power estimation when not present in source file in `src/core/workout_analyzer.py` (FR-009). (src/core/workout_analyzer.py)
- [X] T027 [US1]: Implement gear usage analysis for single-speed bicycles in `src/core/workout_analyzer.py` (FR-010). (src/core/workout_analyzer.py)
- [X] T028 [US1]: Implement report generation (HTML, PDF, Markdown) in `src/core/report_generator.py` (FR-011). (src/core/report_generator.py)
- [X] T029 [US1]: Write contract tests for `POST /api/analyze/workout` endpoint. (tests/contract/test_analyze_workout_api.py)
- [X] T030 [US1]: Implement `POST /api/analyze/workout` endpoint in `api/routers/analysis.py` (FR-013). (api/routers/analysis.py)
- [X] T031 [US1]: Implement error handling for corrupted/malformed files (Edge Case). (api/routers/analysis.py, src/core/file_parser.py)
- [X] T032 [US1]: Implement handling for missing data streams (Edge Case). (src/core/workout_analyzer.py)
- [X] T033 [US1]: Implement detection and flagging of data spikes (Edge Case). (src/core/workout_analyzer.py)
- [X] T034 [US1]: Implement `GET /api/analysis/{id}/summary` endpoint in `api/routers/analysis.py` (FR-016). (api/routers/analysis.py)
- [X] T035 [US1]: Ensure FTP configuration is used for calculations (FR-018, FR-019). (src/core/workout_analyzer.py, api/routers/analysis.py)
**Checkpoint**: Single workout analysis and summary retrieval are functional and tested.
## Phase 4: User Story 2 - Generate specific charts for a workout (P2)
**Goal**: Allow developers to request specific visualizations for an analyzed workout via an API.
**Independent Test Criteria**: Call an API endpoint with a workout ID and chart type, and verify that the correct chart image is returned.
- [X] T036 [US2]: Write unit tests for chart generation logic. (tests/unit/test_chart_generator.py)
- [X] T037 [US2]: Implement chart generation (power curves, elevation profiles, zone distribution) in `src/core/chart_generator.py` (FR-012). (src/core/chart_generator.py)
- [X] T038 [US2]: Write contract tests for `GET /api/analysis/{id}/charts` endpoint. (tests/contract/test_charts_api.py)
- [X] T039 [US2]: Implement `GET /api/analysis/{id}/charts` endpoint in `api/routers/analysis.py` (FR-015). (api/routers/analysis.py)
**Checkpoint**: Chart generation and retrieval are functional and tested.
## Phase 5: User Story 3 - Batch analyze multiple workout files (P3)
**Goal**: Enable coaches to upload a directory of workout files for batch analysis and receive a summary report.
**Independent Test Criteria**: Provide a directory of workout files and verify that a batch analysis is performed and a summary CSV file is generated.
- [X] T040 [US3]: Write unit tests for batch processing logic. (tests/unit/test_batch_processor.py)
- [X] T041 [US3]: Implement batch processing logic in `src/core/batch_processor.py` to handle zip files and process multiple workouts. (src/core/batch_processor.py)
- [X] T042 [US3]: Implement summary report generation for batch analysis (e.g., CSV) in `src/core/report_generator.py`. (src/core/report_generator.py)
- [X] T043 [US3]: Write contract tests for `POST /api/analyze/batch` endpoint. (tests/contract/test_batch_analysis_api.py)
- [X] T044 [US3]: Implement `POST /api/analyze/batch` endpoint in `api/routers/analysis.py` (FR-014). (api/routers/analysis.py)
**Checkpoint**: Batch analysis is functional and tested.
## Phase 6: Polish & Cross-Cutting Concerns
**Goal**: Address remaining cross-cutting concerns and ensure overall quality.
- [X] T045: Implement structured logging across the application. (src/, api/)
- [X] T046: Review and refine error handling mechanisms for all API endpoints. (api/routers/analysis.py)
- [X] T047: Ensure all API endpoints are publicly accessible (FR-017). (api/main.py, deployment config)
- [X] T048: Conduct performance testing to meet SC-002 and SC-004. (tests/performance/)
- [X] T049: Review and optimize database interactions. (src/db/)
- [X] T050: Update `plan.md` with the final project structure. (specs/001-create-a-new/plan.md)
## Dependencies
- Phase 1 must be completed before Phase 2.
- Phase 2 must be completed before Phase 3, Phase 4, and Phase 5.
- Phase 3, Phase 4, and Phase 5 can be developed in parallel after Phase 2, but are ordered by priority.
- Phase 6 can begin once all other phases are functionally complete.
## Parallel Execution Examples
### User Story 1 (P1)
- T012 [P]: Write unit tests for FitParser
- T014 [P]: Write unit tests for TcxParser
- T016 [P]: Write unit tests for GpxParser
- T018 [P]: Write unit tests for WorkoutData
- T029 [P]: Write contract tests for POST /api/analyze/workout
### User Story 2 (P2)
- T036 [P]: Write unit tests for chart generation logic
- T038 [P]: Write contract tests for GET /api/analysis/{id}/charts
### User Story 3 (P3)
- T040 [P]: Write unit tests for batch processing logic
- T043 [P]: Write contract tests for POST /api/analyze/batch
## Implementation Strategy
We will adopt an incremental delivery approach, prioritizing User Story 1 (single workout analysis) as the Minimum Viable Product (MVP). Subsequent user stories will be developed and integrated in priority order. Each user story will be developed using a test-driven development (TDD) approach, ensuring that tests are written before implementation. Foundational components will be established first to provide a stable base for feature development.