-- ============================================================ -- Migration 049: 创建 social_accounts 表 (第三方社交账号绑定) -- -- 支持微信 / Google / Apple 等第三方 OAuth 登录。 -- 一个用户可绑定多个 Provider,通过 userId 外键关联到 users 表。 -- -- openid: Provider 内唯一(微信 openid 每个 App 不同) -- unionid: 微信开放平台跨 App 唯一标识(优先用于用户查找) -- raw_data: 完整 provider 响应(JSONB),保留全量信息备用 -- ============================================================ CREATE TABLE IF NOT EXISTS social_accounts ( id BIGSERIAL PRIMARY KEY, user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, provider VARCHAR(20) NOT NULL, openid VARCHAR(128) NOT NULL, unionid VARCHAR(128), nickname VARCHAR(100), avatar_url VARCHAR(500), raw_data JSONB, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- provider + openid 唯一索引(防止同一 App 下重复绑定) CREATE UNIQUE INDEX IF NOT EXISTS idx_social_provider_openid ON social_accounts(provider, openid); -- provider + unionid 索引(优先用 unionid 查找用户) CREATE INDEX IF NOT EXISTS idx_social_provider_unionid ON social_accounts(provider, unionid) WHERE unionid IS NOT NULL; -- userId 索引(查某用户绑定了哪些 provider) CREATE INDEX IF NOT EXISTS idx_social_user_id ON social_accounts(user_id); -- updated_at 自动更新触发器 CREATE OR REPLACE FUNCTION update_social_accounts_updated_at() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_social_accounts_updated_at BEFORE UPDATE ON social_accounts FOR EACH ROW EXECUTE FUNCTION update_social_accounts_updated_at(); COMMENT ON TABLE social_accounts IS '第三方社交账号绑定记录(微信/Google/Apple 等)'; COMMENT ON COLUMN social_accounts.provider IS 'Provider 标识: wechat | google | apple'; COMMENT ON COLUMN social_accounts.openid IS 'Provider 内用户唯一 ID(微信 openid)'; COMMENT ON COLUMN social_accounts.unionid IS '微信开放平台跨 App 唯一标识(优先用于查找)'; COMMENT ON COLUMN social_accounts.raw_data IS 'Provider 原始响应(JSONB),保留全量数据';