···139139 )
140140 `;
141141142142- // Create indexes
142142+ // ==================== ENHANCED INDEXES FOR PHASE 2 ====================
143143+144144+ // Existing indexes
143145 await sql`CREATE INDEX IF NOT EXISTS idx_source_accounts_to_check ON source_accounts(source_platform, match_found, last_checked)`;
144146 await sql`CREATE INDEX IF NOT EXISTS idx_source_accounts_platform ON source_accounts(source_platform)`;
145147 await sql`CREATE INDEX IF NOT EXISTS idx_user_source_follows_did ON user_source_follows(did)`;
···148150 await sql`CREATE INDEX IF NOT EXISTS idx_atproto_matches_did ON atproto_matches(atproto_did)`;
149151 await sql`CREATE INDEX IF NOT EXISTS idx_user_match_status_did_notified ON user_match_status(did, notified, viewed)`;
150152 await sql`CREATE INDEX IF NOT EXISTS idx_user_match_status_did_followed ON user_match_status(did, followed)`;
151151- await sql`CREATE INDEX IF NOT EXISTS idx_notification_queue_pending ON notification_queue(sent, created_at) WHERE sent = FALSE`;
153153+ await sql`CREATE INDEX IF NOT EXISTS idx_notification_queue_pending ON notification_queue(sent, created_at) WHERE sent = false`;
154154+155155+ // NEW: Enhanced indexes for common query patterns
156156+157157+ // For session lookups (most frequent query)
158158+await sql`CREATE INDEX IF NOT EXISTS idx_user_sessions_did ON user_sessions(did)`;
159159+await sql`CREATE INDEX IF NOT EXISTS idx_user_sessions_expires ON user_sessions(expires_at)`;
160160+161161+ // For OAuth state/session cleanup
162162+ await sql`CREATE INDEX IF NOT EXISTS idx_oauth_states_expires ON oauth_states(expires_at)`;
163163+ await sql`CREATE INDEX IF NOT EXISTS idx_oauth_sessions_expires ON oauth_sessions(expires_at)`;
164164+165165+ // For upload queries by user
166166+ await sql`CREATE INDEX IF NOT EXISTS idx_user_uploads_did_created ON user_uploads(did, created_at DESC)`;
167167+168168+ // For upload details pagination (composite index for ORDER BY + JOIN)
169169+ await sql`CREATE INDEX IF NOT EXISTS idx_user_source_follows_upload_created ON user_source_follows(upload_id, source_account_id)`;
170170+171171+ // For match status queries
172172+ await sql`CREATE INDEX IF NOT EXISTS idx_user_match_status_match_id ON user_match_status(atproto_match_id)`;
173173+174174+ // Composite index for the common join pattern in get-upload-details
175175+ await sql`CREATE INDEX IF NOT EXISTS idx_atproto_matches_source_active ON atproto_matches(source_account_id, is_active) WHERE is_active = true`;
176176+177177+ // For bulk operations - normalized username lookups
178178+ await sql`CREATE INDEX IF NOT EXISTS idx_source_accounts_normalized ON source_accounts(normalized_username, source_platform)`;
179179+180180+ console.log('✅ Database indexes created/verified');
152181}
153182154183export async function cleanupExpiredSessions() {
155184 const sql = getDbClient();
156156- await sql`DELETE FROM oauth_states WHERE expires_at < NOW()`;
157157- await sql`DELETE FROM oauth_sessions WHERE expires_at < NOW()`;
158158- await sql`DELETE FROM user_sessions WHERE expires_at < NOW()`;
185185+186186+ // Use indexes for efficient cleanup
187187+ const statesDeleted = await sql`DELETE FROM oauth_states WHERE expires_at < NOW()`;
188188+ const sessionsDeleted = await sql`DELETE FROM oauth_sessions WHERE expires_at < NOW()`;
189189+ const userSessionsDeleted = await sql`DELETE FROM user_sessions WHERE expires_at < NOW()`;
190190+191191+ console.log('🧹 Cleanup:', {
192192+ states: (statesDeleted as any).length,
193193+ sessions: (sessionsDeleted as any).length,
194194+ userSessions: (userSessionsDeleted as any).length
195195+ });
159196}
160197161198export { getDbClient as sql };