Fix five code-review findings: token auth, sync rate-limiting, model drift, FK cascade
Build and push images / validate (push) Successful in 2s
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 5s

- garmin_connect_sync: revert to garth.loads() for token auth — login(tokenstore=)
  dispatches on len>512, treating compact tokens as filesystem paths and forcing a
  full re-login on every sync. Explicitly set display_name from the embedded profile.
- garmin_connect_sync: restore incremental sync for both activities and wellness —
  always re-fetching the full lookback window was generating ~270 Garmin API calls
  per wellness sync run, risking rate-limits. Now uses since-1d when since is set.
  Add 0.25s per-day sleep in sync_wellness as an additional rate-limit guard.
- models/user.py: replace the dropped uq_pr_current UniqueConstraint in
  PersonalRecord.__table_args__ with the partial Index the DB actually has,
  so the model and live schema no longer permanently diverge.
- models/user.py: add ondelete="SET NULL" to Activity.named_route_id FK so the
  DB cascade handles unlinks if routes are deleted outside the API endpoint.
- main.py: add startup migration to re-add activities_named_route_id_fkey with
  ON DELETE SET NULL on existing deployments.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 10:30:20 +01:00
parent 211f77a574
commit a9b3da858d
3 changed files with 41 additions and 10 deletions
+8 -4
View File
@@ -1,6 +1,6 @@
from sqlalchemy import (
Column, Integer, String, Float, DateTime, Boolean,
ForeignKey, Text, JSON, Index, UniqueConstraint
ForeignKey, Text, JSON, Index, UniqueConstraint, text
)
from sqlalchemy.orm import relationship
from datetime import datetime, timezone
@@ -102,7 +102,7 @@ class Activity(Base):
calories = Column(Float, nullable=True)
training_stress_score = Column(Float, nullable=True)
vo2max_estimate = Column(Float, nullable=True)
named_route_id = Column(Integer, ForeignKey("named_routes.id"), nullable=True)
named_route_id = Column(Integer, ForeignKey("named_routes.id", ondelete="SET NULL"), nullable=True)
polyline = Column(Text, nullable=True)
bounding_box = Column(JSON, nullable=True)
source_file = Column(String(512), nullable=True)
@@ -199,8 +199,12 @@ class PersonalRecord(Base):
is_current_record = Column(Boolean, default=True)
__table_args__ = (
UniqueConstraint("user_id", "sport_type", "distance_m", "is_current_record",
name="uq_pr_current"),
# Uniqueness is enforced at runtime by the partial index uq_pr_current_active
# (created in init_db), which only covers is_current_record=true rows.
# The old all-columns UniqueConstraint was dropped because it incorrectly
# constrained is_current_record=false rows too, causing multi-worker races.
Index("uq_pr_current_active", "user_id", "sport_type", "distance_m",
postgresql_where=text("is_current_record = true"), unique=True),
)