fix: cleanup StravaConfig on user delete (FK violation); equalize login timing (user enum); scope upload task-status to owner; SQL-side data-point downsampling; drop unused clsx/react-leaflet deps
Build and push images / validate (push) Successful in 3s
Build and push images / build-backend (push) Successful in 6s
Build and push images / build-worker (push) Successful in 5s
Build and push images / build-frontend (push) Successful in 19s

This commit is contained in:
2026-06-25 12:21:25 +01:00
parent 84eb1c46bd
commit 64caaad4e7
7 changed files with 79 additions and 42 deletions
+20 -10
View File
@@ -1,7 +1,7 @@
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, desc, delete
from sqlalchemy.orm import selectinload
from sqlalchemy.orm import selectinload, aliased
from pydantic import BaseModel
from typing import Optional, List
from datetime import datetime
@@ -267,17 +267,27 @@ async def get_data_points(
if not act.scalar_one_or_none():
raise HTTPException(status_code=404, detail="Activity not found")
q = select(ActivityDataPoint).where(
ActivityDataPoint.activity_id == activity_id
).order_by(ActivityDataPoint.timestamp)
if downsample > 1:
# Stride in SQL (keep every Nth row by ordered row number) so the DB
# never ships the rows we'd immediately discard — a long per-second
# activity is tens of thousands of points and the UI only charts ~1/N.
rn = func.row_number().over(order_by=ActivityDataPoint.timestamp).label("rn")
sub = (
select(ActivityDataPoint, rn)
.where(ActivityDataPoint.activity_id == activity_id)
.subquery()
)
adp = aliased(ActivityDataPoint, sub)
q = select(adp).where(sub.c.rn % downsample == 1).order_by(sub.c.timestamp)
else:
q = (
select(ActivityDataPoint)
.where(ActivityDataPoint.activity_id == activity_id)
.order_by(ActivityDataPoint.timestamp)
)
result = await db.execute(q)
points = result.scalars().all()
if downsample > 1:
points = points[::downsample]
return points
return result.scalars().all()
@router.get("/{activity_id}/laps", response_model=List[LapOut])