Identidad vs Membresía
OmniBuy separa quién eres (identidad) de dónde trabajas (membresía). Un mismo email puede pertenecer a múltiples tiendas.
El problema que resuelve
En el modelo original, merchant_users tenía un UNIQUE(email) — cada email solo podía existir en una tienda. Si un merchant tenía 2 tiendas, necesitaba 2 cuentas con 2 emails.
El modelo nuevo
merchant_identities (identidad global)
├── id (UUID PK)
├── email (UNIQUE) ← una sola vez
├── password_hash ← una sola vez
├── verified
├── name
└── is_internal ← @omnibuy.net
merchant_users (membresía por tenant)
├── identity_id (FK → merchant_identities)
├── tenant_id
├── role ← owner, admin, staff, viewer
├── email (denormalizado) ← para compat con tenant.go
├── name (denormalizado)
└── UNIQUE(identity_id, tenant_id) ← una membresía por tenant por identidad
Ejemplo
[email protected] → merchant_identities
├── membresía en "Tienda Lima" (role: owner)
├── membresía en "Tienda Cusco" (role: admin)
└── membresía en "Tienda Arequipa" (role: viewer)
María inicia sesión una vez y elige en qué tienda trabajar.
Migración
La migración 000209 es no-destructiva (Opción C):
- Crea
merchant_identitiesy backfilla desdemerchant_users - Agrega
identity_idamerchant_users - NO dropea
password_hashniUNIQUE(email)demerchant_userstodavía - Se mantiene dual-write para compatibilidad
Diagrama
┌─────────────────────┐
│ merchant_identities │ ← Identidad global
│ (login) │
│ │
│ email │
│ password_hash │
│ verified │
└─────────┬───────────┘
│ 1:N
┌─────────┴───────────┐
│ merchant_users │ ← Membresía por tenant
│ │
│ identity_id (FK) │
│ tenant_id │
│ role │
└──────────────────────┘