# ✅ Implementação: Opção 2 - Vínculo por Email ## 🎯 Solução Implementada **Vínculo entre Supabase Auth e API Mock através do EMAIL** ``` ┌──────────────────────────┐ │ Supabase Auth │ │ (Login/Autenticação) │ │ │ │ email: "user@email.com"│ ◄─┐ │ password: "senha123!" │ │ │ userType: "paciente" │ │ └──────────────────────────┘ │ │ VÍNCULO ┌──────────────────────────┐ │ POR EMAIL │ API Mock (Apidog) │ │ │ (Dados do Sistema) │ │ │ │ │ │ email: "user@email.com"│ ◄─┘ │ full_name: "João Silva"│ │ cpf: "123.456.789-00" │ └──────────────────────────┘ ``` --- ## 📝 Código Implementado ### `lib/api.ts` - Funções de Criação de Usuários ```typescript import { ENV_CONFIG } from '@/lib/env-config'; import { API_KEY } from '@/lib/config'; // Gera senha aleatória (formato: senhaXXX!) export function gerarSenhaAleatoria(): string { const num1 = Math.floor(Math.random() * 10); const num2 = Math.floor(Math.random() * 10); const num3 = Math.floor(Math.random() * 10); return `senha${num1}${num2}${num3}!`; } // Cria usuário MÉDICO no Supabase Auth export async function criarUsuarioMedico(medico: { email: string; full_name: string; phone_mobile: string; }): Promise { const senha = gerarSenhaAleatoria(); // Endpoint do Supabase Auth (mesmo que auth.ts usa) const signupUrl = `${ENV_CONFIG.SUPABASE_URL}/auth/v1/signup`; const payload = { email: medico.email, // ◄── VÍNCULO! password: senha, data: { userType: 'profissional', full_name: medico.full_name, phone: medico.phone_mobile, }, }; const response = await fetch(signupUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', apikey: API_KEY, }, body: JSON.stringify(payload), }); if (!response.ok) { const errorText = await response.text(); throw new Error(`Erro ao criar usuário: ${response.status}`); } const responseData = await response.json(); return { success: true, user: responseData.user, email: medico.email, password: senha, }; } // Cria usuário PACIENTE no Supabase Auth export async function criarUsuarioPaciente(paciente: { email: string; full_name: string; phone_mobile: string; }): Promise { const senha = gerarSenhaAleatoria(); const signupUrl = `${ENV_CONFIG.SUPABASE_URL}/auth/v1/signup`; const payload = { email: paciente.email, // ◄── VÍNCULO! password: senha, data: { userType: 'paciente', full_name: paciente.full_name, phone: paciente.phone_mobile, }, }; const response = await fetch(signupUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', apikey: API_KEY, }, body: JSON.stringify(payload), }); if (!response.ok) { const errorText = await response.text(); throw new Error(`Erro ao criar usuário: ${response.status}`); } const responseData = await response.json(); return { success: true, user: responseData.user, email: paciente.email, password: senha, }; } ``` --- ## 🔄 Fluxo Completo ### 1️⃣ **Admin Cadastra Paciente** ```typescript // components/forms/patient-registration-form.tsx async function handleSubmit() { // 1. Salva paciente na API Mock const saved = await salvarPaciente({ full_name: form.nome, email: form.email, // ◄── EMAIL usado como vínculo cpf: form.cpf, telefone: form.telefone, // ...outros dados }); // 2. Cria usuário no Supabase Auth com MESMO EMAIL if (mode === 'create' && form.email) { try { const credentials = await criarUsuarioPaciente({ email: form.email, // ◄── MESMO EMAIL! full_name: form.nome, phone_mobile: form.telefone, }); // 3. Mostra popup com credenciais setCredentials(credentials); setShowCredentials(true); } catch (error) { alert('Paciente cadastrado, mas houve erro ao criar usuário de acesso'); } } } ``` ### 2️⃣ **Paciente Faz Login** ```typescript // Paciente vai em /login-paciente // Digita: email = "jonas@email.com", password = "senha481!" // hooks/useAuth.tsx const login = async (email, password, userType) => { // Autentica no Supabase Auth const response = await loginUser(email, password, userType); // Token JWT contém o email const token = response.access_token; const decoded = decodeJWT(token); console.log(decoded.email); // "jonas@email.com" // Salva sessão localStorage.setItem('token', token); // Redireciona para /paciente router.push('/paciente'); }; ``` ### 3️⃣ **Buscar Dados do Paciente na Área Logada** ```typescript // app/paciente/page.tsx export default function PacientePage() { const { user } = useAuth(); // user.email = "jonas@email.com" useEffect(() => { async function carregarDados() { // Busca paciente pelo EMAIL (vínculo) const response = await fetch( `https://mock.apidog.com/pacientes?email=${user.email}` ); const paciente = await response.json(); // Agora tem os dados completos do paciente console.log(paciente); // { // id: "123", // full_name: "Jonas Francisco", // email: "jonas@email.com", ◄── VÍNCULO! // cpf: "123.456.789-00", // ... // } } carregarDados(); }, [user.email]); return
Bem-vindo, {user.email}!
; } ``` --- ## 🔐 Estrutura dos Dados ### **Supabase Auth (`auth.users`)** ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "email": "jonas@email.com", "encrypted_password": "$2a$10$...", "created_at": "2025-10-03T00:00:00", "user_metadata": { "userType": "paciente", "full_name": "Jonas Francisco", "phone": "(79) 99649-8907" } } ``` ### **API Mock - Tabela `pacientes`** ```json { "id": "123", "full_name": "Jonas Francisco Nascimento Bonfim", "email": "jonas@email.com", "cpf": "123.456.789-00", "telefone": "(79) 99649-8907", "data_nascimento": "1990-01-15", "endereco": { "cep": "49000-000", "logradouro": "Rua Principal", "cidade": "Aracaju" } } ``` **Vínculo:** Campo `email` presente em ambos os sistemas! --- ## 📊 Vantagens da Opção 2 ✅ **Simples:** Não precisa modificar estrutura da API Mock ✅ **Natural:** Email já é único e obrigatório ✅ **Sem duplicação:** Usa campo existente ✅ **Funcional:** Supabase Auth retorna email no token JWT ✅ **Escalável:** Fácil de manter e debugar --- ## ⚠️ Considerações Importantes ### **Email DEVE ser único** - Cada email só pode ter um usuário no Supabase Auth - Cada email só pode ter um paciente/médico na API Mock - Se tentar cadastrar email duplicado, Supabase retorna erro ### **Email DEVE ser válido** - Supabase valida formato (nome@dominio.com) - Use validação no formulário antes de enviar ### **Formato da senha** - Supabase exige mínimo 6 caracteres - Geramos: `senhaXXX!` (10 caracteres) ✅ --- ## 🧪 Logs Esperados (Sucesso) ``` 🏥 [CRIAR PACIENTE] Iniciando criação no Supabase Auth... 📧 Email: jonas@email.com 👤 Nome: Jonas Francisco Nascimento Bonfim 📱 Telefone: (79) 99649-8907 🔑 Senha gerada: senha481! 📤 [CRIAR PACIENTE] Enviando para: https://yuanqfswhberkoevtmfr.supabase.co/auth/v1/signup 📋 [CRIAR PACIENTE] Status da resposta: 200 OK ✅ [CRIAR PACIENTE] Usuário criado com sucesso no Supabase Auth! 🆔 User ID: 550e8400-e29b-41d4-a716-446655440000 ``` --- ## ❌ Possíveis Erros ### **Erro: "Este email já está cadastrado no sistema"** ``` ❌ [CRIAR PACIENTE] Erro: User already registered ``` **Solução:** Email já existe no Supabase. Use outro email ou delete o usuário existente. ### **Erro: "Formato de email inválido"** ``` ❌ [CRIAR PACIENTE] Erro: Invalid email format ``` **Solução:** Valide o formato do email antes de enviar. ### **Erro: 429 - Too Many Requests** ``` ❌ [CRIAR PACIENTE] Erro: 429 ``` **Solução:** Aguarde 1 minuto. Supabase limita taxa de requisições. --- ## ✅ Resultado Final **Agora o sistema funciona assim:** 1. ✅ Admin cadastra paciente → Salva na API Mock 2. ✅ Sistema cria usuário no Supabase Auth (mesmo email) 3. ✅ Popup mostra credenciais (email + senha) 4. ✅ Paciente faz login em `/login-paciente` 5. ✅ Login funciona! Token JWT é gerado 6. ✅ Sistema busca dados do paciente pelo email 7. ✅ Paciente acessa área `/paciente` com todos os dados --- ## 📅 Data da Implementação 3 de outubro de 2025 ## 🔗 Arquivos Modificados - ✅ `susconecta/lib/api.ts` - Funções de criação (Supabase Auth) - ✅ `susconecta/components/forms/patient-registration-form.tsx` - Já integrado - ✅ `susconecta/components/forms/doctor-registration-form.tsx` - Já integrado - ✅ `susconecta/components/credentials-dialog.tsx` - Já implementado