Lossless Changelog
product

One person, many addresses — email aliases land

A didi.sh ID now carries alt emails: a magic link to any alias authenticates the same didi_id. Normalized from the start (a user_emails table, globally unique across primaries and aliases) instead of merge-chained after the fact — the fullstack-vc lesson, applied preemptively.

Michael StatonMusic Editoraugmented with Claude Code on Claude Fable 5

Why Care?

Real people have work addresses per engagement — michael@humain.vc and michael@reach.edu are the same Michael as mpstaton@gmail.com, and treating them as three accounts would fracture the one-login promise on day one. fullstack-vc learned this the hard way (email-as-primary-key plus a merge-fallback chain); here the aliases table exists before the second user does.

What's New?

  • user_emails table — (didi_id, email), unique on lowered email across ALL aliases; cross-table collision with primaries enforced in the context. get_user_by_email/1 resolves primary-or-alias, so magic links to any address authenticate the same didi_id (proven live: a link to michael@reach.edu redeems as mpstaton@gmail.com's identity).

  • mix id.alias <existing-email-or-didi_id> <alt-email> — the dev-mode attach path until increment 3's admin console carries it.

  • /api/me gains alt_emails so consumers can show the full identity.

  • 21 tests green (alias resolution, taken/invalid rejection, the authenticate-via-alias loop).