diff --git a/backend/internal/store/migrations/0026_activities_unique_constraint.sql b/backend/internal/store/migrations/0026_activities_unique_constraint.sql new file mode 100644 index 0000000..7379be2 --- /dev/null +++ b/backend/internal/store/migrations/0026_activities_unique_constraint.sql @@ -0,0 +1,46 @@ +-- activities.garmin_activity_id's UNIQUE constraint (migration 0001) must become +-- per-user (UNIQUE(user_id, garmin_activity_id)) now that the per-user-profile +-- design allows multiple users to share the same Garmin activity ID. The old +-- constraint alone was intentionally left in place by migration 0022 as a +-- belts-and-suspenders safeguard (Garmin IDs are globally unique in practice), +-- but it must be removed now to allow Task 6's cross-user test to pass. +PRAGMA foreign_keys = OFF; + +CREATE TABLE activities_new ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER REFERENCES users(id), + garmin_activity_id INTEGER NOT NULL, + event_type_key TEXT NOT NULL, + workout_id INTEGER, + start_time_utc TEXT NOT NULL, + duration_seconds REAL NOT NULL, + distance_meters REAL NOT NULL, + avg_hr REAL, + max_hr REAL, + avg_speed_mps REAL, + elevation_gain_m REAL, + aerobic_training_effect REAL, + anaerobic_training_effect REAL, + vo2max_value REAL, + raw_json TEXT NOT NULL, + details_fetched_at TEXT, + details_raw_json TEXT, + splits_fetched_at TEXT, + workout_raw_json TEXT, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + UNIQUE(user_id, garmin_activity_id) +); + +INSERT INTO activities_new (id, user_id, garmin_activity_id, event_type_key, workout_id, start_time_utc, duration_seconds, distance_meters, avg_hr, max_hr, avg_speed_mps, elevation_gain_m, aerobic_training_effect, anaerobic_training_effect, vo2max_value, raw_json, details_fetched_at, details_raw_json, splits_fetched_at, workout_raw_json, created_at, updated_at) +SELECT id, user_id, garmin_activity_id, event_type_key, workout_id, start_time_utc, duration_seconds, distance_meters, avg_hr, max_hr, avg_speed_mps, elevation_gain_m, aerobic_training_effect, anaerobic_training_effect, vo2max_value, raw_json, details_fetched_at, details_raw_json, splits_fetched_at, workout_raw_json, created_at, updated_at +FROM activities; + +DROP TABLE activities; + +ALTER TABLE activities_new RENAME TO activities; + +CREATE INDEX idx_activities_start_time ON activities(start_time_utc); +CREATE INDEX idx_activities_user_garmin_id ON activities(user_id, garmin_activity_id); + +PRAGMA foreign_keys = ON;