riseup-squad20/IMPLEMENTACAO_OPCAO2_VINCULO_EMAIL.md

371 lines
9.2 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ✅ 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<CreateUserWithPasswordResponse> {
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<CreateUserWithPasswordResponse> {
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 <div>Bem-vindo, {user.email}!</div>;
}
```
---
## 🔐 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