mirror of
https://github.com/sstent/FitTrack_ReportGenerator.git
synced 2026-01-26 00:52:03 +00:00
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:
34
specs/001-create-a-new/checklists/requirements.md
Normal file
34
specs/001-create-a-new/checklists/requirements.md
Normal 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.
|
||||
238
specs/001-create-a-new/contracts/openapi.yaml
Normal file
238
specs/001-create-a-new/contracts/openapi.yaml
Normal 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
|
||||
66
specs/001-create-a-new/data-model.md
Normal file
66
specs/001-create-a-new/data-model.md
Normal 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)`
|
||||
108
specs/001-create-a-new/plan.md
Normal file
108
specs/001-create-a-new/plan.md
Normal 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] |
|
||||
137
specs/001-create-a-new/quickstart.md
Normal file
137
specs/001-create-a-new/quickstart.md
Normal 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"
|
||||
}
|
||||
}
|
||||
```
|
||||
49
specs/001-create-a-new/research.md
Normal file
49
specs/001-create-a-new/research.md
Normal 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).
|
||||
114
specs/001-create-a-new/spec.md
Normal file
114
specs/001-create-a-new/spec.md
Normal 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.
|
||||
129
specs/001-create-a-new/tasks.md
Normal file
129
specs/001-create-a-new/tasks.md
Normal 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.
|
||||
Reference in New Issue
Block a user