mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
Migration 0122 added MoodEntry.externalId plus the NULL-distinct @@unique([userId, source, externalId]) and wired the moodLog webhook and sync importer onto it, but the iOS-facing native routes never used it: POST /api/mood-entries dropped externalId entirely (the schema did not declare it) and POST /api/mood-entries/bulk accepted it in its Zod schema yet parsed-and-ignored it, still upserting on the legacy (userId, date, moodLoggedAt) key. The dedup index existed but nothing on the native write path reached it, so the idempotent re-import the client needs was not functional. Declare externalId on createMoodEntrySchema (bounded to match the bulk schema), persist it, and — when present — upsert the single-entry write on (userId, source, externalId) so a re-post with the same id updates the existing row in place instead of 409-ing or minting a duplicate. When absent, keep the legacy first-write create and its 409-on-conflict behaviour untouched. On the bulk path, branch the per-entry probe and upsert onto the same compound key when an entry carries an externalId, refreshing date and moodLoggedAt in the update so a re-zoned re-import lands the corrected wall-clock on the same row; absent ids keep the legacy wall-clock key. Both paths resolve source once so the dedup key and the row write agree. Echo externalId back on the single response (via the row) and on each bulk per-entry result so the client can map server ids onto its local rows. Cover the present-vs-absent upsert key, cross-user isolation, and the echo with unit tests on both routes plus a real-Postgres integration test proving a re-posted externalId resolves to one row updated in place, a null externalId keeps wall-clock behaviour, and the same id under two users stays isolated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> (cherry picked from commit 6a65de22bc436daeeb73dd2a1cb612336c74a928)