Skip to content

fix: sync company email verification to work experiences#3976

Merged
rebelchris merged 1 commit into
mainfrom
fix/company-email-verification-experience-sync
Jul 3, 2026
Merged

fix: sync company email verification to work experiences#3976
rebelchris merged 1 commit into
mainfrom
fix/company-email-verification-experience-sync

Conversation

@rebelchris

Copy link
Copy Markdown
Contributor

Problem

User feedback (ENG-1825): a user tried to verify their company email and got This email has already been verified, even though the profile UI still showed the work experience as unverified — trapping them in a dead-end loop.

Root cause

There are two separate verified flags:

  • UserCompany.verified — the email record (what the GraphQL error checks)
  • UserExperienceWork.verified — what the profile UI shows

They're only linked through the onUserCompanyCompanyChange CDC worker, which reacts to companyId changes (creation-with-company or a companyId change) — not to a plain verified flip.

So:

  • verifyUserCompanyCode flips verified false → true without changing companyId, so the matching work experience is never marked verified.
  • The profile keeps showing the experience as unverified, the user re-submits addUserCompany, and hits This email has already been verified.

The prior fix (#3891, shouldEnrichUserCompany) only covered the companyId IS NULL path (enrich → set companyId → CDC fires). The case where the company already exists (companyId set at creation, then a verified-flip with no companyId change) was left uncovered — which is exactly what the reported user hit.

Fix

  • Add syncVerifiedUserWorkExperiences(con, userId, companyId) helper that marks matching UserExperienceWork rows verified.
  • Call it from verifyUserCompanyCode after the verified flip, so confirming the code propagates to the work experience.
  • Make addUserCompany idempotent: when the email is already verified for the same user, re-assert the experience verification and return success instead of throwing — killing the dead-end loop.

Tests

  • Updated the old "already verified → error" test to assert idempotent success.
  • Added a test that re-submitting an already-verified email marks the matching work experience verified.
  • Added a test that verifyUserCompanyCode marks the matching work experience verified.

When a user verifies their company email, the verified state lives on
UserCompany, while the profile UI reads UserExperienceWork.verified. The
two are only linked via the onUserCompanyCompanyChange CDC worker, which
reacts to companyId changes (creation-with-company or companyId change) —
not to a plain verified flip.

As a result:
- verifyUserCompanyCode flips verified false->true without changing
  companyId, so the matching work experience is never marked verified.
- The profile still shows the experience as unverified, so the user
  re-submits addUserCompany and hits 'This email has already been
  verified', trapping them in a dead-end loop.

Fixes:
- Add syncVerifiedUserWorkExperiences helper that marks matching Work
  experiences verified for a (userId, companyId).
- Call it from verifyUserCompanyCode after the verified flip.
- Make addUserCompany idempotent: when the email is already verified for
  the same user, re-assert experience verification and return success
  instead of throwing.

Adds tests for both resolvers.
@pulumi

pulumi Bot commented Jul 3, 2026

Copy link
Copy Markdown

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

Resource Changes

    Name                                                    Type                           Operation
~   vpc-native-update-highlighted-views-cron                kubernetes:batch/v1:CronJob    update
~   vpc-native-post-analytics-clickhouse-cron               kubernetes:batch/v1:CronJob    update
~   vpc-native-update-source-public-threshold-cron          kubernetes:batch/v1:CronJob    update
~   vpc-native-post-analytics-history-day-clickhouse-cron   kubernetes:batch/v1:CronJob    update
~   vpc-native-user-profile-updated-sync-cron               kubernetes:batch/v1:CronJob    update
~   vpc-native-validate-active-users-cron                   kubernetes:batch/v1:CronJob    update
-   vpc-native-api-clickhouse-migration-fcab9478            kubernetes:batch/v1:Job        delete
-   vpc-native-api-db-migration-fcab9478                    kubernetes:batch/v1:Job        delete
~   vpc-native-personalized-digest-deployment               kubernetes:apps/v1:Deployment  update
~   vpc-native-clean-zombie-opportunities-cron              kubernetes:batch/v1:CronJob    update
~   vpc-native-clean-expired-better-auth-sessions-cron      kubernetes:batch/v1:CronJob    update
~   vpc-native-rotate-weekly-quests-cron                    kubernetes:batch/v1:CronJob    update
~   vpc-native-deployment                                   kubernetes:apps/v1:Deployment  update
+   vpc-native-api-db-migration-688df2ea                    kubernetes:batch/v1:Job        create
~   vpc-native-update-tag-materialized-views-cron           kubernetes:batch/v1:CronJob    update
~   vpc-native-check-analytics-report-cron                  kubernetes:batch/v1:CronJob    update
~   vpc-native-expire-super-agent-trial-cron                kubernetes:batch/v1:CronJob    update
~   vpc-native-worker-job-deployment                        kubernetes:apps/v1:Deployment  update
~   vpc-native-update-tags-str-cron                         kubernetes:batch/v1:CronJob    update
~   vpc-native-post-analytics-achievements-cron             kubernetes:batch/v1:CronJob    update
~   vpc-native-clean-old-notifications-cron                 kubernetes:batch/v1:CronJob    update
~   vpc-native-daily-digest-cron                            kubernetes:batch/v1:CronJob    update
~   vpc-native-update-achievement-rarity-cron               kubernetes:batch/v1:CronJob    update
~   vpc-native-clean-stale-user-transactions-cron           kubernetes:batch/v1:CronJob    update
~   vpc-native-squad-posts-analytics-refresh-cron           kubernetes:batch/v1:CronJob    update
~   vpc-native-update-current-streak-cron                   kubernetes:batch/v1:CronJob    update
~   vpc-native-sync-subscription-with-cio-cron              kubernetes:batch/v1:CronJob    update
~   vpc-native-clean-zombie-users-cron                      kubernetes:batch/v1:CronJob    update
~   vpc-native-private-deployment                           kubernetes:apps/v1:Deployment  update
~   vpc-native-update-views-cron                            kubernetes:batch/v1:CronJob    update
~   vpc-native-update-trending-cron                         kubernetes:batch/v1:CronJob    update
~   vpc-native-generate-search-invites-cron                 kubernetes:batch/v1:CronJob    update
~   vpc-native-ws-deployment                                kubernetes:apps/v1:Deployment  update
~   vpc-native-materialize-monthly-best-post-archives-cron  kubernetes:batch/v1:CronJob    update
~   vpc-native-rotate-daily-quests-cron                     kubernetes:batch/v1:CronJob    update
~   vpc-native-clean-zombie-images-cron                     kubernetes:batch/v1:CronJob    update
~   vpc-native-clean-zombie-user-companies-cron             kubernetes:batch/v1:CronJob    update
~   vpc-native-hourly-notification-cron                     kubernetes:batch/v1:CronJob    update
~   vpc-native-materialize-yearly-best-post-archives-cron   kubernetes:batch/v1:CronJob    update
~   vpc-native-user-profile-analytics-clickhouse-cron       kubernetes:batch/v1:CronJob    update
~   vpc-native-calculate-top-readers-cron                   kubernetes:batch/v1:CronJob    update
... and 15 other changes

@rebelchris rebelchris merged commit 8a836ce into main Jul 3, 2026
7 of 9 checks passed
@rebelchris rebelchris deleted the fix/company-email-verification-experience-sync branch July 3, 2026 11:55
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.

1 participant