Fix five code-review findings: token auth, sync rate-limiting, model drift, FK cascade
- 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:
@@ -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),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user