32 KiB
MediConnect - Sistema de Gestão Médica Completo
Sistema completo de gestão médica com agendamento inteligente, teleconsultas, prontuários eletrônicos e gerenciamento multi-nível.
Stack: React + TypeScript + Vite + TailwindCSS + Supabase Edge Functions
Deploy: Cloudflare Pages
Última Atualização: 29/11/2025
🚀 Acesso ao Sistema
- URL Principal: https://mediconnectbrasil.app/
- URL Cloudflare: https://mediconnect-5oz.pages.dev/
Credenciais de Teste
Admin/Gestor:
- Email: admin@mediconnect.app
- Senha: admin123
- Acesso: Todos os painéis
Médico:
- Email: medico@teste.com
- Senha: senha123
- Acesso: Painel Médico, Sala de Espera, Teleconsultas
Paciente:
- Email: paciente@teste.com
- Senha: senha123
- Acesso: Agendamento, Acompanhamento, Teleconsultas
Secretária:
- Email: secretaria@teste.com
- Senha: senha123
- Acesso: Gerenciamento de Consultas, Pacientes e Médicos
🏗️ Arquitetura
Frontend (React/Vite + TypeScript)
↓
API Gateway (Edge Functions - Deno)
↓
Dual Supabase Architecture
├── EXTERNAL Supabase (Auth + RLS)
│ ├── Auth (JWT + Magic Link)
│ ├── PostgreSQL (Source of Truth)
│ └── Storage (Avatares, Documentos)
└── NEW Supabase (Functions + No RLS)
├── 65 Edge Functions (CORS Fixed)
├── 34 Tabelas (Gamification, Analytics)
└── Real-time Subscriptions
↓
Integrations
├── Jitsi (Teleconsultas)
├── Twilio (SMS)
└── Resend (Email)
↓
Cloudflare Pages (Deploy Global)
✨ Funcionalidades Principais
🎯 NOVO: Painel do Gestor
- ✅ Dashboard executivo com KPIs
- ✅ Visão geral do sistema (pacientes, médicos, consultas)
- ✅ Métricas de atividade (hoje, semana, mês)
- ✅ Lista de consultas recentes com status
- ✅ Filtros de período (7d, 30d, 90d, 1 ano)
- ✅ Tabs: Dashboard, Análises, Relatórios, Usuários, Configurações
- ✅ Design moderno com gradientes e animações
🏥 Para Médicos
- ✅ Painel modernizado com design da Landing Page
- ✅ Agenda personalizada com disponibilidade configurável
- ✅ Sala de Espera Virtual - Pacientes com check-in em tempo real
- ✅ Teleconsulta integrada com Jitsi (vídeo HD)
- ✅ Gerenciamento completo de disponibilidade semanal
- ✅ Sistema de exceções (bloqueios e horários extras)
- ✅ Prontuário eletrônico completo
- ✅ Histórico de consultas do paciente
- ✅ Dashboard com métricas e estatísticas
- ✅ Consultas presenciais e remotas
- ✅ Confirmação/Cancelamento/Remarcar consultas
- ✅ Status dinâmicos (scheduled, confirmed, in_progress, completed, cancelled, no_show)
👥 Para Pacientes
- ✅ Dashboard modernizado com gradientes e animações hover
- ✅ Teleconsulta - Entrar em videochamada com médico
- ✅ Verificação automática de dispositivos (câmera/microfone)
- ✅ Agendamento inteligente com slots disponíveis em tempo real
- ✅ Histórico completo de consultas com filtros
- ✅ Visualização detalhada de laudos médicos com modal
- ✅ Visualização e download de relatórios médicos (PDF)
- ✅ Perfil com avatar e dados pessoais
- ✅ Filtros por médico, especialidade e data
- ✅ Gamificação (pontos, streaks, badges)
- ✅ Cards de estatísticas com cores dinâmicas
🏢 Para Secretárias
- ✅ Painel modernizado com tabs em gradiente
- ✅ Gerenciamento completo de médicos, pacientes e consultas
- ✅ Cadastro com validação de CPF e CRM
- ✅ Configuração de agenda médica (horários e exceções)
- ✅ Relatórios com nomes de médicos (não apenas IDs)
- ✅ Busca e filtros avançados
- ✅ Confirmação profissional para exclusões
- ✅ Gestão de sala de espera
- ✅ Envio de notificações (SMS, Email, WhatsApp)
🔐 Para Administradores
- ✅ Painel modernizado com design consistente
- ✅ Gerenciamento de usuários e permissões (roles)
- ✅ CRUD completo de Pacientes, Médicos e Secretárias
- ✅ Controle de acesso granular
- ✅ Logs de auditoria
- ✅ Configurações globais do sistema
- ✅ Tabs organizadas (Pacientes, Usuários, Médicos)
🔐 Sistema de Autenticação
- ✅ Login com email/senha
- ✅ Magic Link (login sem senha)
- ✅ Recuperação de senha
- ✅ Tokens JWT com refresh automático
- ✅ Controle de acesso por role (admin, gestor, médico, paciente, secretária)
- ✅ Dual Supabase (EXTERNAL para auth, NEW para functions)
🎨 Design System (Atualizado 29/11/2025)
Padrões Visuais da Landing Page
Todos os painéis foram modernizados seguindo o design da Landing Page:
Cores e Gradientes:
/* Gradientes principais */
from-blue-600 to-purple-600 /* Títulos e botões ativos */
from-blue-500 to-cyan-600 /* Ícones e destaques */
from-purple-500 to-pink-600 /* Variações */
from-green-500 to-teal-600 /* Status positivos */
/* Backgrounds */
bg-gradient-to-br from-blue-50 via-purple-50 to-pink-50 /* Fundo dos painéis */
bg-white/80 backdrop-blur-md /* Cards glassmorphism */
Componentes:
/* Cards */
rounded-2xl shadow-lg hover:shadow-2xl hover:-translate-y-1 transition-all
/* Botões */
px-6 py-3 bg-gradient-to-r text-white rounded-xl hover:shadow-lg hover:scale-105
/* Ícones em containers */
w-14 h-14 bg-gradient-to-br rounded-xl group-hover:scale-110 transition-transform
/* Tabs ativos */
bg-gradient-to-r from-blue-600 to-purple-600 text-white shadow-lg scale-105
/* Bordas sutis */
border border-gray-100 /* Ao invés de gray-200 */
Tipografia:
/* Títulos */
text-3xl sm:text-4xl font-bold
text-transparent bg-clip-text bg-gradient-to-r /* Títulos com gradiente */
/* Valores de métricas */
text-3xl font-bold text-blue-600 /* Números destacados */
🔧 Tecnologias
Frontend
- React 18 - Interface moderna e reativa
- TypeScript - Tipagem estática
- Vite - Build ultra-rápido (HMR em <200ms)
- TailwindCSS - Estilização utilitária + Design System customizado
- React Router - Navegação SPA com rotas protegidas
- Axios - Cliente HTTP com interceptors
- date-fns - Manipulação de datas (i18n pt-BR)
- jsPDF - Geração de PDFs
- Lucide Icons - 1000+ ícones SVG modernos
- React Hot Toast - Notificações elegantes
Backend (Supabase)
- PostgreSQL 15 - Banco de dados relacional
- PostgREST - API REST automática
- Edge Functions (Deno) - 65 funções serverless
- ✅ CORS corrigido (status: 200 explícito)
- ✅ Auth bypass com SERVICE_ROLE_KEY
- ✅ URL normalization (/ → -)
- Storage - Armazenamento de arquivos (avatares, PDFs)
- Auth - JWT + RLS (EXTERNAL Supabase)
- Real-time - Subscriptions via WebSocket
Integrações
- Jitsi Meet - Teleconsultas HD (vpaas-magic-cookie)
- Twilio - SMS notifications (+1 978-981-4520)
- Resend - Email transacional (noreply@mediconnectbrasil.app)
Deploy
- Cloudflare Pages - Hospedagem global com CDN
- Wrangler CLI - Deploy automatizado
- GitHub Actions - CI/CD pipeline
📦 Instalação e Execução
Pré-requisitos
- Node.js 18+
- pnpm (recomendado) ou npm
- Supabase CLI (para deploy de functions)
Instalação
# Clone o repositório
git clone https://github.com/seu-usuario/mediconnect.git
cd riseup-squad18
# Instalar dependências
pnpm install
# Configurar variáveis de ambiente
cp .env.example .env
# Edite .env com suas credenciais Supabase, Jitsi, Twilio, Resend
# Iniciar desenvolvimento
pnpm dev
# Acessar em http://localhost:5173
Build e Deploy
# Build de produção
pnpm build
# Preview do build
pnpm preview
# Deploy para Cloudflare Pages
pnpm wrangler pages deploy dist --project-name=mediconnect --branch=production
Deploy de Edge Functions
# Deploy individual
supabase functions deploy <nome-funcao> --project-ref etblfypcxxtvvuqjkrgd --no-verify-jwt
# Deploy em massa (17 funções corrigidas)
.\deploy-fixed-functions.ps1
# Deploy de todas as funções
supabase functions deploy --project-ref etblfypcxxtvvuqjkrgd
🚀 Melhorias Recentes (Novembro 2025)
🎨 Modernização de UI (29/11/2025)
4 Painéis Modernizados:
- ✅ PainelMedico.tsx - Design da Landing Page aplicado
- ✅ PainelSecretaria.tsx - Tabs com gradiente, glassmorphism
- ✅ PainelAdmin.tsx - Header e tabs modernizados
- ✅ AcompanhamentoPaciente.tsx - Cards com hover effects, gradientes dinâmicos
1 Painel Novo:
- 🆕 PainelGestor.tsx - Dashboard executivo com KPIs e analytics
- Métricas do sistema (pacientes, médicos, consultas, relatórios)
- Atividade temporal (hoje, semana, mês)
- Filtros de período (7d, 30d, 90d, 1 ano)
- Lista de consultas recentes
- Tabs: Dashboard, Análises, Relatórios, Usuários, Configurações
Padrões Aplicados:
- Gradientes:
from-blue-600 to-purple-600,from-blue-500 to-cyan-600 - Cards:
rounded-2xl shadow-lg hover:shadow-2xl hover:-translate-y-1 - Glassmorphism:
bg-white/80 backdrop-blur-md - Ícones com gradiente:
bg-gradient-to-br rounded-xl group-hover:scale-110 - Bordas sutis:
border-gray-100(ao invés de gray-200)
🔧 Correção Massiva de CORS (29/11/2025)
17 Edge Functions Corrigidas:
Todas agora têm status: 200 explícito no OPTIONS handler:
if (req.method === "OPTIONS") {
return new Response("ok", {
status: 200, // ✅ EXPLÍCITO!
headers: corsHeaders(),
});
}
Funções corrigidas:
- appointments: checkin, confirm, no-show, reschedule, suggest-slot
- gamification: add-points, doctor-badges, patient-streak
- notifications: send, confirm
- teleconsult: start, end, status
- offline: agenda-today, patient-basic
- reports: export
- virtual-queue: advance
Script de Deploy:
- Criado
deploy-fixed-functions.ps1para deploy automatizado - Flag
--no-verify-jwtpara bypass de autenticação - Deploy em massa de todas as 17 funções
🎥 Sistema de Teleconsulta (Implementado)
Painel do Paciente:
- ✅ Botão "Entrar na Consulta" visível em consultas agendadas
- ✅ Verificação automática de dispositivos (câmera/microfone)
- ✅ Integração com Jitsi Meet (vpaas-magic-cookie)
- ✅ Abertura de sala em nova janela
- ✅ Toast notifications para feedback
Painel do Médico:
- ✅ Botão de videochamada nas consultas
- ✅ Tab "Sala de Espera" dedicada
- ✅ Componente WaitingRoom integrado
- ✅ Status de consultas em tempo real
Services:
- ✅
teleconsultService.tscompleto - ✅ Funções: start(), end(), getStatus(), openRoom(), checkMediaDevices()
- ✅ Edge Functions: teleconsult-start, teleconsult-end, teleconsult-status
🔔 Sistema de Notificações (Implementado)
Services:
- ✅
notificationService.tscom CRUD completo - ✅ Tipos: SMS, Email, WhatsApp
- ✅ Status: pending, sent, failed, scheduled
- ✅ Integração com Twilio (SMS) e Resend (Email)
Edge Functions:
- ✅ notifications-send (envio multi-canal)
- ✅ notifications-confirm (confirmação de leitura)
- ✅ notifications-subscription (push notifications)
📅 Sistema de Agendamento Completo
Status de Consultas:
- scheduled → confirmed → checked_in → in_progress → completed
- Também: cancelled, no_show
Edge Functions:
- ✅ appointments-create (criar consulta)
- ✅ appointments-update (atualizar)
- ✅ appointments-cancel (cancelar)
- ✅ appointments-confirm (confirmar)
- ✅ appointments-checkin (check-in para sala de espera)
- ✅ appointments-no-show (marcar falta)
- ✅ appointments-reschedule (reagendar)
- ✅ appointments-suggest-slot (sugerir novo horário)
Componentes:
- ✅ WaitingRoom.tsx - Sala de espera virtual
- ✅ ConsultaModal.tsx - Modal de gerenciamento
- ✅ Integração completa nos painéis
🎮 Sistema de Gamificação
Features:
- ✅ Pontos por ações (consultas, check-ins, etc)
- ✅ Streaks de pacientes (dias consecutivos)
- ✅ Badges de médicos (conquistas)
- ✅ Edge Functions: add-points, patient-streak, doctor-badges
🚀 Melhorias de Navegação
Command Palette (Ctrl+K):
- ✅ Adicionado "Painel Gestor" aos comandos
- ✅ Adicionado "Painel Admin" aos comandos
- ✅ Keywords: gestor, gerencial, analytics, métricas
Header:
- ✅ Link para "Gestor" (roxo/indigo) entre Admin e Médico
- ✅ Versão mobile com ícone 📈
- ✅ Navegação consistente em todos os painéis
Rotas:
- ✅
/painel-gestorprotegida (roles: admin, gestor) - ✅ Importação e integração no App.tsx
- ✅ ProtectedRoute com verificação de roles
Chatbot AI 🤖
- ✅ Assistente virtual inteligente com IA
- ✅ Interface de chat moderna e responsiva
- ✅ Posicionamento otimizado (canto inferior esquerdo)
- ✅ Respostas personalizadas sobre o sistema
- ✅ Suporte a dúvidas sobre agendamento e funcionalidades
Gerenciamento de Disponibilidade Médica 📅
- ✅ Painel completo de disponibilidade no painel do médico
- ✅ Criação e edição de horários semanais
- ✅ Sistema de exceções (bloqueios e horários extras)
- ✅ Visualização em abas (Horário Semanal e Exceções)
- ✅ Interface intuitiva com validações completas
Visualização de Laudos 🔍
- ✅ Botão de visualização (ícone de olho) no painel do paciente
- ✅ Modal detalhado com informações completas do laudo
- ✅ Exibição de: número do pedido, status, exame, diagnóstico, CID, conclusão
- ✅ Suporte a modo escuro
- ✅ Formatação de datas em português
Melhorias no Painel da Secretária 👩💼
- ✅ Relatórios mostram nome do médico ao invés de ID
- ✅ Mensagem de boas-vindas personalizada com nome real
- ✅ Busca e resolução automática de nomes de médicos
- ✅ Fallback para email caso nome não esteja disponível
Sistema de Agendamento
- ✅ API de slots disponíveis (Edge Function)
- ✅ Cálculo automático de horários
- ✅ Validação de antecedência mínima
- ✅ Verificação de conflitos
- ✅ Interface otimizada
UX/UI
- ✅ Toast único de boas-vindas após login (removidas mensagens duplicadas)
- ✅ Chatbot responsivo adaptado ao tamanho da tela
- ✅ Diálogos de confirmação profissionais
- ✅ Filtros de busca em todas as listas
- ✅ Feedback visual melhorado
- ✅ Loading states consistentes
- ✅ Mensagens de erro claras
Performance
- ✅ Build otimizado (~467KB)
- ✅ Code splitting
- ✅ Lazy loading de rotas
- ✅ Cache de assets
- ✅ Remoção de dependências não utilizadas
📝 Convenções de Código
TypeScript
- Interfaces para todas as entidades
- Tipos explícitos em funções
- Evitar
any(usarunknownquando necessário)
Componentes React
- Functional components com hooks
- Props tipadas com interfaces
- Estado local com useState/useContext
- Effects para side effects
Serviços
- Um serviço por entidade (doctorService, patientService)
- Métodos assíncronos com try/catch
- Logs de debug no console
- Tratamento de erros consistente
Nomenclatura
- Componentes: PascalCase (ex:
AgendamentoConsulta) - Arquivos: kebab-case ou PascalCase conforme tipo
- Variáveis: camelCase (ex:
selectedDate) - Constantes: UPPER_SNAKE_CASE (ex:
API_CONFIG)
🐛 Troubleshooting
Erro 401 (Unauthorized)
- Verificar se token está no localStorage
- Tentar logout e login novamente
- Verificar permissões RLS no Supabase
Slots não aparecem
- Verificar se médico tem disponibilidade configurada
- Verificar se data é futura
- Verificar logs da Edge Function
Upload de avatar falha
- Verificar tamanho do arquivo (max 2MB)
- Verificar formato (jpg, png)
- Verificar permissões do Storage no Supabase
Build falha
- Limpar cache:
rm -rf node_modules dist - Reinstalar:
pnpm install - Verificar versão do Node (18+)
👥 Equipe
RiseUp Squad 18
- Desenvolvimento: GitHub Copilot + Equipe
- Data: Outubro 2025
📄 Licença
Este projeto é privado e desenvolvido para fins educacionais.
<EFBFBD> Links Úteis
Última atualização: 30 de Outubro de 2025
- ✅ Veem apenas seus próprios dados
- ✅ Veem apenas seus próprios laudos (filtro:
patient_id = paciente) - ✅ Veem apenas seus próprios agendamentos
- ✅ Podem agendar consultas
👩💼 Secretárias:
- ✅ Veem todos os pacientes
- ✅ Veem todos os agendamentos
- ✅ Veem todos os laudos
- ✅ Podem criar/editar agendamentos
📡 API e Serviços
Estrutura de Services
O projeto usa uma arquitetura de services que encapsulam toda comunicação com o Supabase:
src/services/
├── api/
│ ├── client.ts # Cliente HTTP (Axios configurado)
│ └── config.ts # Configurações da API
├── auth/
│ ├── authService.ts # Login, signup, recuperação de senha
│ └── types.ts
├── users/
│ └── userService.ts # getUserInfo, createUser, deleteUser
├── patients/
│ └── patientService.ts # CRUD de pacientes
├── doctors/
│ └── doctorService.ts # CRUD de médicos
├── appointments/
│ └── appointmentService.ts # Agendamentos
└── availability/
└── availabilityService.ts # Disponibilidade médica
Principais Endpoints
🔐 Autenticação (authService)
// Login com Email e Senha
await authService.login({ email, password });
// Retorna: { access_token, refresh_token, user }
// Magic Link (Login sem senha)
await authService.sendMagicLink("email@example.com");
// Envia email com link de autenticação
// Usuário clica no link e é automaticamente autenticado
// Recuperação de senha
await authService.requestPasswordReset("email@example.com");
// Envia email com link de reset
// Atualizar senha
await authService.updatePassword(accessToken, newPassword);
// Usado na página /reset-password
// Refresh token
await authService.refreshToken(refreshToken);
Fluxo Magic Link:
- Usuário solicita magic link na tela de login
localStorage.setItem("magic_link_redirect", "/painel-medico")salva contexto- Supabase envia email com link único
- Usuário clica no link
Home.tsxdetecta hash params e redireciona para/auth/callbackAuthCallback.tsxprocessa tokens, salva no localStoragewindow.location.hrefredireciona para painel salvo- Página recarrega com
AuthContextatualizado - Usuário autenticado no painel correto ✅
👤 Usuários (userService)
// Buscar informações do usuário autenticado (com roles)
const userInfo = await userService.getUserInfo();
// Retorna: { id, email, full_name, roles: ['medico', 'admin'] }
// Criar usuário com role
await userService.createUser({
email: "user@example.com",
full_name: "Nome Completo",
role: "medico", // ou 'admin', 'paciente', 'secretaria'
});
// Deletar usuário
await userService.deleteUser(userId);
🏥 Pacientes (patientService)
// Listar pacientes
const patients = await patientService.list();
// Buscar por ID
const patient = await patientService.getById(id);
// Criar paciente
await patientService.create({
email: "paciente@example.com",
full_name: "Nome Paciente",
cpf: "12345678900",
phone_mobile: "11999999999",
});
// Atualizar paciente
await patientService.update(id, { phone_mobile: "11888888888" });
// Deletar paciente
await patientService.delete(id);
👨⚕️ Médicos (doctorService)
// Listar médicos
const doctors = await doctorService.list();
// Buscar por ID
const doctor = await doctorService.getById(id);
// Buscar disponibilidade
const slots = await doctorService.getAvailableSlots(doctorId, date);
📅 Agendamentos (appointmentService)
// Listar agendamentos (filtrado por role automaticamente)
const appointments = await appointmentService.list();
// Criar agendamento
await appointmentService.create({
patient_id: "uuid-paciente",
doctor_id: "uuid-medico",
scheduled_at: "2025-10-25T10:00:00",
reason: "Consulta de rotina",
});
// Atualizar status
await appointmentService.updateStatus(id, "confirmed");
// Status: requested, confirmed, completed, cancelled
// Cancelar
await appointmentService.cancel(id, "Motivo do cancelamento");
📸 Avatares (avatarService)
// Upload de avatar (usa FormData com x-upsert: true)
const file = event.target.files[0]; // File do input
const result = await avatarService.upload({
userId: user.id,
file: file,
});
// Retorna: { Key: "url-publica-do-avatar" }
// Obter URL pública do avatar
const url = avatarService.getPublicUrl({
userId: user.id,
ext: "png", // ou 'jpg', 'webp'
});
// Retorna: https://yuanqfswhberkoevtmfr.supabase.co/storage/v1/object/avatars/{userId}/avatar.png
// Auto-load de avatar (testa múltiplas extensões)
const extensions = ["png", "jpg", "webp"];
for (const ext of extensions) {
const url = avatarService.getPublicUrl({ userId: user.id, ext });
const response = await fetch(url, { method: "HEAD" });
if (response.ok) {
setAvatarUrl(url);
break;
}
}
Detalhes importantes:
- Upload usa multipart/form-data via FormData
- Header
x-upsert: truepermite sobrescrever avatares existentes - Suporta formatos: PNG, JPG, WEBP (máx 2MB)
- URLs públicas não requerem autenticação
- Avatar é carregado automaticamente nos painéis
🔧 Configuração da API
// src/services/api/config.ts
export const API_CONFIG = {
SUPABASE_URL: "https://yuanqfswhberkoevtmfr.supabase.co",
SUPABASE_ANON_KEY: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
AUTH_URL: `${SUPABASE_URL}/auth/v1`,
REST_URL: `${SUPABASE_URL}/rest/v1`,
APP_URL: "https://mediconnectbrasil.app",
TIMEOUT: 30000,
STORAGE_KEYS: {
ACCESS_TOKEN: "mediconnect_access_token",
REFRESH_TOKEN: "mediconnect_refresh_token",
USER: "mediconnect_user",
},
};
🚀 Deploy no Cloudflare Pages
Via Wrangler CLI
# Build
pnpm build
# Deploy para production
npx wrangler pages deploy dist --project-name=mediconnect --branch=production
# Deploy com mudanças não commitadas
npx wrangler pages deploy dist --project-name=mediconnect --commit-dirty=true
Configuração do Projeto
- Production Branch:
production - Build Command:
pnpm build - Build Output:
dist - Custom Domain:
mediconnectbrasil.app
URLs
- Production: https://mediconnectbrasil.app/
- Preview: https://mediconnect-5oz.pages.dev/
- Branch Preview: https://[branch].mediconnect-5oz.pages.dev/
1. Variáveis de Ambiente (.env / .env.local)
| Variável | Obrigatória | Descrição |
|---|---|---|
VITE_SUPABASE_URL |
Sim | URL base do projeto Supabase (https://<ref>.supabase.co) |
VITE_SUPABASE_ANON_KEY |
Sim | Chave pública (anon) usada para Auth password grant e PostgREST |
VITE_APP_ENV |
Não | Identifica ambiente (ex: dev, staging, prod) |
Nota: As variáveis já estão configuradas no código em src/services/api/config.ts. Não é necessário criar arquivo .env para desenvolvimento local.
Boas práticas:
- Nunca exponha Service Role Key no frontend.
- Não comitar
.env– usar.env.examplecomo referência (se houver).
2. Fluxo de Login e Validação de Roles
Exemplo: Login de Médico
// pages/LoginMedico.tsx
const handleLogin = async (e: FormEvent) => {
e.preventDefault();
try {
// 1. Autenticar com Supabase
const loginResponse = await authService.login({ email, password });
// 2. Salvar tokens
localStorage.setItem("access_token", loginResponse.access_token);
localStorage.setItem("refresh_token", loginResponse.refresh_token);
// 3. Buscar informações do usuário com roles
const userInfo = await userService.getUserInfo();
const roles = userInfo.roles || [];
// 4. Validar permissões
const isAdmin = roles.includes("admin");
const isGestor = roles.includes("gestor");
const isMedico = roles.includes("medico");
if (!isAdmin && !isGestor && !isMedico) {
toast.error("Você não tem permissão para acessar esta área");
await authService.logout();
return;
}
// 5. Redirecionar para o painel
navigate("/painel-medico");
} catch (error) {
toast.error("Email ou senha incorretos");
}
};
3. Recuperação de Senha
Fluxo Completo
- Usuário clica em "Esqueceu a senha?"
- Sistema envia email com link de recuperação
- Usuário clica no link → redireciona para
/reset-password - Sistema extrai token do URL (#access_token=...)
- Usuário define nova senha
- Sistema atualiza senha e redireciona para login
Implementação
// Solicitar recuperação (páginas de login)
const handlePasswordReset = async () => {
try {
await authService.requestPasswordReset(email);
toast.success("Link de recuperação enviado para seu email");
} catch (error) {
toast.error("Erro ao enviar email de recuperação");
}
};
// Página de reset (ResetPassword.tsx)
useEffect(() => {
// Extrair token do URL
const hash = window.location.hash;
const params = new URLSearchParams(hash.substring(1));
const token = params.get("access_token");
if (token) {
setAccessToken(token);
setIsLoading(false);
}
}, []);
const handleSubmit = async (e: FormEvent) => {
try {
await authService.updatePassword(accessToken, newPassword);
toast.success("Senha atualizada com sucesso!");
navigate("/login-paciente");
} catch (error) {
toast.error("Erro ao atualizar senha");
}
};
5. Estrutura do Banco de Dados
Tabelas Principais
profiles
- id (uuid, PK)
- email (text, unique)
- full_name (text)
- phone (text)
- created_at (timestamp)
- updated_at (timestamp)
patients
- id (uuid, PK, FK -> profiles)
- email (text, unique)
- full_name (text)
- cpf (text, unique)
- phone_mobile (text)
- birth_date (date)
- address (text)
- created_at (timestamp)
doctors
- id (uuid, PK, FK -> profiles)
- email (text, unique)
- full_name (text)
- specialty (text)
- crm (text, unique)
- phone (text)
- created_at (timestamp)
appointments
- id (uuid, PK)
- patient_id (uuid, FK -> patients)
- doctor_id (uuid, FK -> doctors)
- scheduled_at (timestamp)
- status (enum: requested, confirmed, completed, cancelled)
- reason (text)
- notes (text)
- created_at (timestamp)
user_roles
- user_id (uuid, FK -> profiles)
- role (text: admin, gestor, medico, secretaria, paciente)
- created_at (timestamp)
6. Armazenamento de Tokens
O sistema usa uma estratégia híbrida para máxima segurança:
| Tipo | Local | Expiração Natural |
|---|---|---|
| Access Token | localStorage | 1 hora (renovado automaticamente) |
| Refresh Token | localStorage | 30 dias (ou revogação backend) |
| User Snapshot | localStorage | Limpo em logout |
Segurança:
- Tokens são limpos automaticamente no logout
- Refresh automático quando access_token expira (401)
- Interceptors garantem tokens válidos em todas as requisições
Riscos remanescentes:
- XSS ainda pode ler refresh token dentro da mesma aba.
- Ataques supply-chain podem capturar tokens em runtime.
Mitigações planejadas:
- CSP + bloqueio de inline script não autorizado.
- Auditoria de dependências e lockfile imutável.
- (Opcional) Migrar refresh para cookie httpOnly + rotacionamento curto (exige backend/proxy).
Fallback / Migração:
- Em primeira utilização o
tokenStoremigra chaves legacy (authToken,refreshToken,authUser) e remove dolocalStorage.
Operações:
tokenStore.setTokens(access, refresh?)atualiza memória e session.tokenStore.clear()remove tudo (usado em logout e erro crítico de refresh).
Fluxo de Refresh:
- Requisição falha com 401.
- Wrapper (
http.ts) obtém refresh dotokenStore.
7. Scripts Utilitários
Gerenciamento de Usuários
# Listar todos os usuários
node scripts/manage-users.js list
# Criar usuário
node scripts/manage-users.js create email@example.com "Nome Completo"
# Deletar usuário
node scripts/manage-users.js delete user-id
# Limpar usuários de teste
node scripts/cleanup-users.js
Testes de API
# Testar recuperação de senha
node test-password-recovery.js
# Criar usuário Fernando (exemplo)
node create-fernando.cjs
# Buscar usuário Fernando
node search-fernando.cjs
8. Padrões de Código
Nomenclatura
- Componentes: PascalCase (
LoginPaciente.tsx) - Serviços: camelCase (
authService.ts) - Hooks: camelCase com prefixo
use(useAuth.ts) - Tipos: PascalCase (
LoginInput,AuthUser)
Estrutura de Componentes
// Imports
import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { serviceImport } from "../services";
// Types
interface Props {
// ...
}
// Component
const ComponentName: React.FC<Props> = ({ ...props }) => {
// Hooks
const navigate = useNavigate();
const [state, setState] = useState();
// Effects
useEffect(() => {
// ...
}, []);
// Handlers
const handleAction = async () => {
// ...
};
// Render
return <div>{/* JSX */}</div>;
};
export default ComponentName;
9. Tecnologias Utilizadas
Frontend
- React 18.3.1 - Biblioteca UI
- TypeScript 5.9.3 - Tipagem estática
- Vite 7.1.10 - Build tool
- React Router 6.30.1 - Roteamento
- Tailwind CSS 3.4.17 - Estilização
- Axios 1.12.2 - Cliente HTTP
- React Hot Toast 2.4.1 - Notificações
- date-fns 4.1.0 - Manipulação de datas
Backend
- Supabase - Backend as a Service
- PostgreSQL - Banco de dados relacional
- Supabase Auth - Autenticação JWT
Deploy
- Cloudflare Pages - Hospedagem frontend
- Wrangler 4.44.0 - CLI Cloudflare
10. Suporte e Contato
- Equipe: Squad 18 - Rise Up
- Repositório: https://git.popcode.com.br/RiseUP/riseup-squad18.git
- Trello: Squad 18 - Idealização/Planejamento
Desenvolvido com ❤️ pela Squad 18