riseup-squad18/README.md
2025-12-06 19:13:27 -03:00

32 KiB
Raw Permalink Blame History

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

Credenciais de Teste

Admin/Gestor:

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.ps1 para deploy automatizado
  • Flag --no-verify-jwt para 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.ts completo
  • Funções: start(), end(), getStatus(), openRoom(), checkMediaDevices()
  • Edge Functions: teleconsult-start, teleconsult-end, teleconsult-status

🔔 Sistema de Notificações (Implementado)

Services:

  • notificationService.ts com 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-gestor protegida (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 (usar unknown quando 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.



Ú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:

  1. Usuário solicita magic link na tela de login
  2. localStorage.setItem("magic_link_redirect", "/painel-medico") salva contexto
  3. Supabase envia email com link único
  4. Usuário clica no link
  5. Home.tsx detecta hash params e redireciona para /auth/callback
  6. AuthCallback.tsx processa tokens, salva no localStorage
  7. window.location.href redireciona para painel salvo
  8. Página recarrega com AuthContext atualizado
  9. 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: true permite 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


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.example como 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

  1. Usuário clica em "Esqueceu a senha?"
  2. Sistema envia email com link de recuperação
  3. Usuário clica no link → redireciona para /reset-password
  4. Sistema extrai token do URL (#access_token=...)
  5. Usuário define nova senha
  6. 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:

  1. CSP + bloqueio de inline script não autorizado.
  2. Auditoria de dependências e lockfile imutável.
  3. (Opcional) Migrar refresh para cookie httpOnly + rotacionamento curto (exige backend/proxy).

Fallback / Migração:

  • Em primeira utilização o tokenStore migra chaves legacy (authToken, refreshToken, authUser) e remove do localStorage.

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:

  1. Requisição falha com 401.
  2. Wrapper (http.ts) obtém refresh do tokenStore.

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


Desenvolvido com ❤️ pela Squad 18