Initial commit: smartrun MVP

Garmin run classification and progression tracker. Go backend (MCP
client to mcp-garmin, SQLite store, deterministic rule engine, REST
API) and React/TS frontend (Dashboard, Review Queue, Workout Kinds).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 18:33:06 +02:00
commit f689f74ae0
69 changed files with 10666 additions and 0 deletions

116
frontend/src/types/api.ts Normal file
View File

@@ -0,0 +1,116 @@
// Hand-written types mirroring backend/internal/api's JSON DTOs. Kept in
// sync manually while the API surface is small; revisit codegen once it
// stabilizes post-MVP.
export interface Activity {
ID: number;
GarminActivityID: number;
ActivityName: string;
ActivityType: string;
StartTimeUTC: string;
BeginTimestampMs: number;
DurationSeconds: number;
DistanceMeters: number;
AvgHR: number | null;
MaxHR: number | null;
AvgSpeedMps: number | null;
MaxSpeedMps: number | null;
ElevationGainM: number | null;
ElevationLossM: number | null;
Calories: number | null;
LapCount: number;
AerobicTrainingEffect: number | null;
AnaerobicTrainingEffect: number | null;
TrainingEffectLabel: string;
VO2MaxValue: number | null;
DetailsFetchedAt: string | null;
SplitsFetchedAt: string | null;
CreatedAt: string;
UpdatedAt: string;
}
export interface Lap {
ID: number;
ActivityID: number;
LapIndex: number;
StartTimeUTC: string;
DurationSeconds: number;
DistanceMeters: number;
AvgHR: number | null;
MaxHR: number | null;
AvgSpeedMps: number | null;
MaxSpeedMps: number | null;
ElevationGainM: number | null;
ElevationLossM: number | null;
IntensityType: string;
HRDriftBpmPerMin: number | null;
HRRecoveryBpmPerMin: number | null;
}
export interface WorkoutKind {
ID: number;
Name: string;
Description: string;
Color: string;
RuleJSON: string;
Priority: number;
IsActive: boolean;
CreatedAt: string;
UpdatedAt: string;
}
export interface ScoredKind {
workout_kind_id: number;
name: string;
score: number;
}
export interface KindAssignment {
ID: number;
ActivityID: number;
WorkoutKindID: number | null;
AssignmentSource: "rule_engine" | "manual";
Status: "assigned" | "needs_review";
Confidence: number | null;
CandidateKindsJSON: string;
CreatedAt: string;
}
export interface ReviewQueueItem extends KindAssignment {
activity: Activity;
}
export interface ProgressionPoint {
date: string;
activity_id: number;
value: number;
}
export interface SyncRun {
ID: number;
Kind: "backfill" | "incremental";
StartedAt: string;
FinishedAt: string | null;
ActivitiesFetched: number;
Status: "running" | "success" | "error";
ErrorMessage: string | null;
}
export interface AuthResponse {
status: "authenticated" | "mfa_required" | "failed" | "unknown";
message: string;
}
export interface DetailFillProgress {
Done: number;
Total: number;
}
export interface SyncStatus {
in_progress: boolean;
detail_fill_progress: DetailFillProgress;
activities_pending_details: number;
last_run?: SyncRun;
}
export type ProgressionMetric = "pace" | "hr" | "vo2max" | "aerobic_te" | "anaerobic_te";