ATlast — you'll never need to find your favorites on another platform again. Find your favs in the ATmosphere.
atproto

fix: use TIMESTAMPTZ for all timestamp columns

Changed all TIMESTAMP columns to TIMESTAMPTZ (timestamp with timezone) to
properly handle timezone-aware timestamps across all tables:
- oauth_states (created_at, expires_at)
- oauth_sessions (created_at, expires_at)
- user_sessions (created_at, expires_at)
- user_uploads (created_at, last_checked)
- source_accounts (last_checked, match_found_at, created_at)
- user_source_follows (created_at)
- atproto_matches (found_at, last_verified, last_follow_check)
- user_match_status (notified_at, viewed_at, followed_at, dismissed_at)
- notification_queue (created_at, sent_at)

This fixes the 5-hour timezone offset issue where timestamps were stored
without timezone info, causing display errors across different timezones.

byarielm.fyi aacbbaa2 c5adc150

verified
Changed files
+21 -21
packages
functions
src
infrastructure
+21 -21
packages/functions/src/infrastructure/database/DatabaseService.ts
··· 34 34 CREATE TABLE IF NOT EXISTS oauth_states ( 35 35 key TEXT PRIMARY KEY, 36 36 data JSONB NOT NULL, 37 - created_at TIMESTAMP DEFAULT NOW(), 38 - expires_at TIMESTAMP NOT NULL 37 + created_at TIMESTAMPTZ DEFAULT NOW(), 38 + expires_at TIMESTAMPTZ NOT NULL 39 39 ) 40 40 `; 41 41 ··· 43 43 CREATE TABLE IF NOT EXISTS oauth_sessions ( 44 44 key TEXT PRIMARY KEY, 45 45 data JSONB NOT NULL, 46 - created_at TIMESTAMP DEFAULT NOW(), 47 - expires_at TIMESTAMP NOT NULL 46 + created_at TIMESTAMPTZ DEFAULT NOW(), 47 + expires_at TIMESTAMPTZ NOT NULL 48 48 ) 49 49 `; 50 50 ··· 53 53 session_id TEXT PRIMARY KEY, 54 54 did TEXT NOT NULL, 55 55 fingerprint JSONB, 56 - created_at TIMESTAMP DEFAULT NOW(), 57 - expires_at TIMESTAMP NOT NULL 56 + created_at TIMESTAMPTZ DEFAULT NOW(), 57 + expires_at TIMESTAMPTZ NOT NULL 58 58 ) 59 59 `; 60 60 ··· 63 63 upload_id TEXT PRIMARY KEY, 64 64 did TEXT NOT NULL, 65 65 source_platform TEXT NOT NULL, 66 - created_at TIMESTAMP DEFAULT NOW(), 67 - last_checked TIMESTAMP, 66 + created_at TIMESTAMPTZ DEFAULT NOW(), 67 + last_checked TIMESTAMPTZ, 68 68 total_users INTEGER NOT NULL, 69 69 matched_users INTEGER DEFAULT 0, 70 70 unmatched_users INTEGER DEFAULT 0 ··· 77 77 source_platform TEXT NOT NULL, 78 78 source_username TEXT NOT NULL, 79 79 normalized_username TEXT NOT NULL, 80 - last_checked TIMESTAMP, 80 + last_checked TIMESTAMPTZ, 81 81 match_found BOOLEAN DEFAULT FALSE, 82 - match_found_at TIMESTAMP, 83 - created_at TIMESTAMP DEFAULT NOW(), 82 + match_found_at TIMESTAMPTZ, 83 + created_at TIMESTAMPTZ DEFAULT NOW(), 84 84 UNIQUE(source_platform, normalized_username) 85 85 ) 86 86 `; ··· 92 92 did TEXT NOT NULL, 93 93 source_account_id INTEGER NOT NULL REFERENCES source_accounts(id) ON DELETE CASCADE, 94 94 source_date TEXT, 95 - created_at TIMESTAMP DEFAULT NOW(), 95 + created_at TIMESTAMPTZ DEFAULT NOW(), 96 96 UNIQUE(upload_id, source_account_id) 97 97 ) 98 98 `; ··· 109 109 post_count INTEGER, 110 110 follower_count INTEGER, 111 111 match_score INTEGER NOT NULL, 112 - found_at TIMESTAMP DEFAULT NOW(), 113 - last_verified TIMESTAMP, 112 + found_at TIMESTAMPTZ DEFAULT NOW(), 113 + last_verified TIMESTAMPTZ, 114 114 is_active BOOLEAN DEFAULT TRUE, 115 115 follow_status JSONB DEFAULT '{}', 116 - last_follow_check TIMESTAMP, 116 + last_follow_check TIMESTAMPTZ, 117 117 UNIQUE(source_account_id, atproto_did) 118 118 ) 119 119 `; ··· 125 125 atproto_match_id INTEGER NOT NULL REFERENCES atproto_matches(id) ON DELETE CASCADE, 126 126 source_account_id INTEGER NOT NULL REFERENCES source_accounts(id) ON DELETE CASCADE, 127 127 notified BOOLEAN DEFAULT FALSE, 128 - notified_at TIMESTAMP, 128 + notified_at TIMESTAMPTZ, 129 129 viewed BOOLEAN DEFAULT FALSE, 130 - viewed_at TIMESTAMP, 130 + viewed_at TIMESTAMPTZ, 131 131 followed BOOLEAN DEFAULT FALSE, 132 - followed_at TIMESTAMP, 132 + followed_at TIMESTAMPTZ, 133 133 dismissed BOOLEAN DEFAULT FALSE, 134 - dismissed_at TIMESTAMP, 134 + dismissed_at TIMESTAMPTZ, 135 135 UNIQUE(did, atproto_match_id) 136 136 ) 137 137 `; ··· 141 141 id SERIAL PRIMARY KEY, 142 142 did TEXT NOT NULL, 143 143 new_matches_count INTEGER NOT NULL, 144 - created_at TIMESTAMP DEFAULT NOW(), 144 + created_at TIMESTAMPTZ DEFAULT NOW(), 145 145 sent BOOLEAN DEFAULT FALSE, 146 - sent_at TIMESTAMP, 146 + sent_at TIMESTAMPTZ, 147 147 retry_count INTEGER DEFAULT 0, 148 148 last_error TEXT 149 149 )