Skip to content

Conversation

@idoshamun
Copy link
Member

Summary

Adds comprehensive backend tests for the socialLinksInputSchema validation, complementing the Phase 1 backend implementation that was merged in #3404.

Changes

  • Added tests for socialLinksInputSchema validation including:
    • Basic array validation with auto-detection
    • Platform override capability
    • Fallback to 'other' for unknown platforms
    • Invalid URL rejection
    • Empty array handling
    • Order preservation

Related Issues

  • ENG-258: Write backend tests for socialLinks feature

Test plan

  • All 26 tests pass (pnpm test __tests__/common/socials.ts)

Adds unit tests for the socialLinksInputSchema Zod schema:
- Validates array of social links with platform auto-detection
- Tests explicit platform override
- Tests fallback to "other" for unknown domains
- Tests rejection of invalid URLs
- Tests empty array handling
- Tests order preservation

Also adds missing platform detection tests for codepen, reddit, and stackoverflow.

Closes ENG-258
@pulumi
Copy link

pulumi bot commented Jan 8, 2026

🍹 The Update (preview) for dailydotdev/api/prod (at c296577) was successful.

Resource Changes

    Name                                                   Type                           Operation
~   vpc-native-update-trending-cron                        kubernetes:batch/v1:CronJob    update
~   vpc-native-generate-search-invites-cron                kubernetes:batch/v1:CronJob    update
~   vpc-native-deployment                                  kubernetes:apps/v1:Deployment  update
~   vpc-native-update-views-cron                           kubernetes:batch/v1:CronJob    update
~   vpc-native-personalized-digest-deployment              kubernetes:apps/v1:Deployment  update
~   vpc-native-clean-stale-user-transactions-cron          kubernetes:batch/v1:CronJob    update
~   vpc-native-private-deployment                          kubernetes:apps/v1:Deployment  update
~   vpc-native-post-analytics-clickhouse-cron              kubernetes:batch/v1:CronJob    update
~   vpc-native-update-tag-recommendations-cron             kubernetes:batch/v1:CronJob    update
~   vpc-native-user-profile-updated-sync-cron              kubernetes:batch/v1:CronJob    update
~   vpc-native-ws-deployment                               kubernetes:apps/v1:Deployment  update
~   vpc-native-temporal-deployment                         kubernetes:apps/v1:Deployment  update
-   vpc-native-api-clickhouse-migration-e68fea1e           kubernetes:batch/v1:Job        delete
+   vpc-native-api-clickhouse-migration-3b9f2c73           kubernetes:batch/v1:Job        create
~   vpc-native-personalized-digest-cron                    kubernetes:batch/v1:CronJob    update
~   vpc-native-clean-zombie-opportunities-cron             kubernetes:batch/v1:CronJob    update
~   vpc-native-sync-subscription-with-cio-cron             kubernetes:batch/v1:CronJob    update
~   vpc-native-update-current-streak-cron                  kubernetes:batch/v1:CronJob    update
~   vpc-native-clean-zombie-images-cron                    kubernetes:batch/v1:CronJob    update
+   vpc-native-api-db-migration-3b9f2c73                   kubernetes:batch/v1:Job        create
~   vpc-native-clean-zombie-user-companies-cron            kubernetes:batch/v1:CronJob    update
~   vpc-native-clean-gifted-plus-cron                      kubernetes:batch/v1:CronJob    update
~   vpc-native-daily-digest-cron                           kubernetes:batch/v1:CronJob    update
~   vpc-native-hourly-notification-cron                    kubernetes:batch/v1:CronJob    update
-   vpc-native-api-db-migration-e68fea1e                   kubernetes:batch/v1:Job        delete
~   vpc-native-clean-zombie-users-cron                     kubernetes:batch/v1:CronJob    update
~   vpc-native-validate-active-users-cron                  kubernetes:batch/v1:CronJob    update
~   vpc-native-update-tags-str-cron                        kubernetes:batch/v1:CronJob    update
~   vpc-native-bg-deployment                               kubernetes:apps/v1:Deployment  update
~   vpc-native-update-source-public-threshold-cron         kubernetes:batch/v1:CronJob    update
~   vpc-native-update-highlighted-views-cron               kubernetes:batch/v1:CronJob    update
~   vpc-native-update-source-tag-view-cron                 kubernetes:batch/v1:CronJob    update
~   vpc-native-calculate-top-readers-cron                  kubernetes:batch/v1:CronJob    update
~   vpc-native-generic-referral-reminder-cron              kubernetes:batch/v1:CronJob    update
~   vpc-native-check-analytics-report-cron                 kubernetes:batch/v1:CronJob    update
~   vpc-native-post-analytics-history-day-clickhouse-cron  kubernetes:batch/v1:CronJob    update

@idoshamun idoshamun marked this pull request as draft January 8, 2026 09:06
@idoshamun
Copy link
Member Author

Backfill Migration (ENG-255)

Note: The backfill migration needs to be created manually due to file protection hooks. The migration should be run in batches to minimize lock time on the large user table.

Recommended Approach: Batch Processing

-- Run in batches of 10,000 to minimize table locks
DO $$
DECLARE
  batch_size INT := 10000;
  affected_rows INT;
BEGIN
  LOOP
    UPDATE "user"
    SET "socialLinks" = (
      SELECT COALESCE(jsonb_agg(link ORDER BY priority), '[]'::jsonb)
      FROM (
        SELECT jsonb_build_object('platform', platform, 'url', url) as link, priority
        FROM (VALUES
          (1, 'github', CASE WHEN github IS NOT NULL THEN 'https://github.com/' || github END),
          (2, 'linkedin', CASE WHEN linkedin IS NOT NULL THEN 'https://linkedin.com/in/' || linkedin END),
          (3, 'twitter', CASE WHEN twitter IS NOT NULL THEN 'https://x.com/' || twitter END),
          (4, 'youtube', CASE WHEN youtube IS NOT NULL THEN 'https://youtube.com/@' || youtube END),
          (5, 'stackoverflow', CASE WHEN stackoverflow IS NOT NULL THEN 'https://stackoverflow.com/users/' || stackoverflow END),
          (6, 'threads', CASE WHEN threads IS NOT NULL THEN 'https://threads.net/@' || threads END),
          (7, 'bluesky', CASE WHEN bluesky IS NOT NULL THEN 'https://bsky.app/profile/' || bluesky END),
          (8, 'mastodon', mastodon),
          (9, 'roadmap', CASE WHEN roadmap IS NOT NULL THEN 'https://roadmap.sh/u/' || roadmap END),
          (10, 'codepen', CASE WHEN codepen IS NOT NULL THEN 'https://codepen.io/' || codepen END),
          (11, 'reddit', CASE WHEN reddit IS NOT NULL THEN 'https://reddit.com/user/' || reddit END),
          (12, 'hashnode', hashnode),
          (13, 'portfolio', portfolio)
        ) AS t(priority, platform, url)
        WHERE url IS NOT NULL
      ) AS links
    )
    WHERE id IN (
      SELECT id FROM "user"
      WHERE ("socialLinks" = '[]' OR "socialLinks" IS NULL)
        AND (github IS NOT NULL OR linkedin IS NOT NULL OR twitter IS NOT NULL 
             OR youtube IS NOT NULL OR stackoverflow IS NOT NULL OR threads IS NOT NULL
             OR bluesky IS NOT NULL OR mastodon IS NOT NULL OR roadmap IS NOT NULL
             OR codepen IS NOT NULL OR reddit IS NOT NULL OR hashnode IS NOT NULL
             OR portfolio IS NOT NULL)
      LIMIT batch_size
      FOR UPDATE SKIP LOCKED
    );
    
    GET DIAGNOSTICS affected_rows = ROW_COUNT;
    RAISE NOTICE 'Updated % rows', affected_rows;
    
    EXIT WHEN affected_rows = 0;
    
    -- Small pause between batches to reduce load
    PERFORM pg_sleep(0.1);
  END LOOP;
END $$;

Key Optimizations

  1. Only updates users with social links - Skips users with no legacy social data
  2. Batch processing - Updates 10,000 rows at a time to minimize lock duration
  3. SKIP LOCKED - Avoids blocking on rows being modified by other transactions
  4. Conditional check - Only processes rows where socialLinks is empty/null AND at least one legacy field exists

Pre-migration Count Query

-- Check how many rows will be affected
SELECT COUNT(*) FROM "user"
WHERE ("socialLinks" = '[]' OR "socialLinks" IS NULL)
  AND (github IS NOT NULL OR linkedin IS NOT NULL OR twitter IS NOT NULL 
       OR youtube IS NOT NULL OR stackoverflow IS NOT NULL OR threads IS NOT NULL
       OR bluesky IS NOT NULL OR mastodon IS NOT NULL OR roadmap IS NOT NULL
       OR codepen IS NOT NULL OR reddit IS NOT NULL OR hashnode IS NOT NULL
       OR portfolio IS NOT NULL);

Comment on lines +102 to +106
it('should detect reddit.com', () => {
expect(detectPlatformFromUrl('https://reddit.com/user/username')).toBe(
'reddit',
);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think reddit is one with multiple urls iirc

});

it('should auto-detect platform from URL', () => {
const input = [{ url: 'https://x.com/johndoe' }];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same couyld still be twitter.com iirc

@idoshamun idoshamun closed this Jan 8, 2026
@idoshamun idoshamun deleted the flexible-links-phase-2 branch January 8, 2026 15:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants