MediConnect - Sistema de Agendamento Médico
Sistema completo de gestão de consultas médicas desenvolvido pela Squad 18 do programa Rise Up.
🚀 Acesso ao Sistema
- URL Principal: https://mediconnectbrasil.app/
- URL Cloudflare: https://mediconnect-5oz.pages.dev/
📋 Índice
- Visão Geral
- Arquitetura
- Tecnologias
- Estrutura do Projeto
- API e Serviços
- Autenticação
- Fluxos Principais
- Deploy
- Desenvolvimento Local
🎯 Visão Geral
O MediConnect é uma plataforma web que conecta pacientes, médicos e secretárias de forma eficiente e segura, permitindo:
- ✅ Agendamento de consultas online
- ✅ Gestão de disponibilidade dos médicos
- ✅ Acompanhamento de consultas e prontuários
- ✅ Sistema de avatares com upload de imagens
- ✅ Recuperação de senha
- ✅ Sistema de roles e permissões
- ✅ Interface responsiva e acessível
🏗️ Arquitetura
Diagrama de Arquitetura
┌─────────────────┐
│ Frontend │
│ React + TS │
│ (Cloudflare) │
└────────┬────────┘
│
│ HTTPS
▼
┌─────────────────┐
│ Supabase API │
│ (Backend) │
├─────────────────┤
│ • Auth │
│ • PostgreSQL │
│ • Functions │
│ • Storage │
└─────────────────┘
Camadas da Aplicação
-
Apresentação (UI)
- React 18.3.1 com TypeScript
- React Router para navegação
- Tailwind CSS para estilização
- Lucide React para ícones
-
Lógica de Negócio (Services)
- Services organizados por domínio
- Axios para requisições HTTP
- Interceptors para autenticação automática
-
Persistência (Supabase)
- PostgreSQL com Row Level Security (RLS)
- Supabase Auth para autenticação JWT
- Supabase Storage para upload de avatares
- Supabase Functions para lógica serverless
🛠️ Tecnologias
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
- Supabase Storage - Armazenamento de avatares
Deploy
- Cloudflare Pages - Hospedagem frontend
- Wrangler 4.44.0 - CLI Cloudflare
📁 Estrutura do Projeto
MEDICONNECT 2/
├── src/
│ ├── pages/ # Páginas da aplicação
│ │ ├── Home.tsx
│ │ ├── LoginPaciente.tsx
│ │ ├── LoginMedico.tsx
│ │ ├── LoginSecretaria.tsx
│ │ ├── ResetPassword.tsx
│ │ ├── PainelMedico.tsx
│ │ ├── PainelSecretaria.tsx
│ │ ├── AcompanhamentoPaciente.tsx
│ │ └── ...
│ │
│ ├── components/ # Componentes reutilizáveis
│ │ ├── Header.tsx
│ │ ├── HeroBanner.tsx
│ │ ├── Chatbot.tsx
│ │ ├── MetricCard.tsx
│ │ ├── auth/
│ │ ├── agenda/
│ │ ├── consultas/
│ │ └── secretaria/
│ │
│ ├── services/ # Serviços de API
│ │ ├── api/
│ │ │ ├── client.ts # Cliente HTTP
│ │ │ └── config.ts # Configurações
│ │ ├── auth/
│ │ │ ├── authService.ts
│ │ │ └── types.ts
│ │ ├── patients/
│ │ ├── doctors/
│ │ ├── appointments/
│ │ ├── availability/
│ │ └── users/
│ │
│ ├── hooks/ # React Hooks customizados
│ │ ├── useAuth.ts
│ │ └── useAccessibilityPrefs.ts
│ │
│ ├── context/ # Context API
│ │ └── AuthContext.tsx
│ │
│ ├── i18n/ # Internacionalização
│ │ ├── pt-BR.ts
│ │ └── en-US.ts
│ │
│ ├── types/ # Definições de tipos
│ │ └── api.d.ts
│ │
│ └── utils/ # Utilitários
│ └── validators.ts
│
├── public/ # Arquivos públicos
├── dist/ # Build de produção
├── scripts/ # Scripts utilitários
│ ├── manage-users.js
│ └── cleanup-users.js
│
├── vite.config.ts # Configuração Vite
├── tailwind.config.js # Configuração Tailwind
└── tsconfig.json # Configuração TypeScript
🔌 API e Serviços
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`,
FUNCTIONS_URL: `${SUPABASE_URL}/functions/v1`,
APP_URL: "https://mediconnectbrasil.app",
TIMEOUT: 30000,
STORAGE_KEYS: {
ACCESS_TOKEN: "mediconnect_access_token",
REFRESH_TOKEN: "mediconnect_refresh_token",
USER: "mediconnect_user",
},
};
Serviços Disponíveis
1. authService - Autenticação
// Login
await authService.login({ email, password });
// Registro
await authService.signup({ email, password, full_name });
// Logout
await authService.logout();
// Recuperação de senha
await authService.requestPasswordReset(email);
await authService.updatePassword(accessToken, newPassword);
// Refresh token
await authService.refreshToken(refreshToken);
2. userService - Usuários
// Buscar informações do usuário autenticado
const userInfo = await userService.getUserInfo();
// Criar usuário com role
await userService.createUser({ email, full_name, role });
// Deletar usuário
await userService.deleteUser(userId);
3. patientService - Pacientes
// Listar pacientes
const patients = await patientService.list();
// Buscar por ID
const patient = await patientService.getById(id);
// Criar paciente
await patientService.create({ email, full_name, cpf, phone });
// Atualizar
await patientService.update(id, data);
// Registrar paciente (público)
await patientService.register({ email, full_name, cpf });
4. doctorService - Médicos
// 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);
5. appointmentService - Consultas
// Listar consultas
const appointments = await appointmentService.list();
// Criar consulta
await appointmentService.create({
patient_id,
doctor_id,
scheduled_at,
reason,
});
// Atualizar status
await appointmentService.updateStatus(id, status);
// Cancelar
await appointmentService.cancel(id, reason);
6. availabilityService - Disponibilidade
// Gerenciar disponibilidade do médico
await availabilityService.create({
doctor_id,
day_of_week,
start_time,
end_time,
});
// Listar disponibilidade
const slots = await availabilityService.listByDoctor(doctorId);
🔐 Autenticação
Fluxo de Autenticação
- Login
// 1. Usuário envia credenciais
const response = await authService.login({ email, password });
// 2. Recebe tokens JWT
localStorage.setItem("access_token", response.access_token);
localStorage.setItem("refresh_token", response.refresh_token);
// 3. Busca informações completas
const userInfo = await userService.getUserInfo();
// 4. Valida roles
if (userInfo.roles.includes("medico")) {
navigate("/painel-medico");
}
- Interceptor Automático
// Todo request adiciona o token automaticamente
axios.interceptors.request.use((config) => {
const token = localStorage.getItem("access_token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
- Refresh Token Automático
axios.interceptors.response.use(
(response) => response,
async (error) => {
if (error.response?.status === 401) {
// Token expirado, tenta refresh
const refreshToken = localStorage.getItem("refresh_token");
const newTokens = await authService.refreshToken(refreshToken);
// Retry request original
}
}
);
Roles e Permissões
| Role | Acesso |
|---|---|
| admin | Acesso total ao sistema |
| gestor | Gestão de médicos, secretárias e relatórios |
| medico | Painel médico, consultas, prontuários |
| secretaria | Agendamento, gestão de pacientes |
| paciente | Agendamento, visualização de consultas |
Hierarquia de Roles:
admin > gestor > medico/secretaria > paciente
🔄 Fluxos Principais
1. Fluxo de Agendamento de Consulta
sequenceDiagram
Paciente->>LoginPaciente: Faz login
LoginPaciente->>Supabase: POST /auth/v1/token
Supabase-->>LoginPaciente: access_token
LoginPaciente->>UserService: getUserInfo()
UserService-->>LoginPaciente: dados + roles
Paciente->>ListaMedicos: Escolhe médico
ListaMedicos->>DoctorService: getAvailableSlots()
DoctorService-->>ListaMedicos: horários disponíveis
Paciente->>AppointmentService: create()
AppointmentService->>Supabase: POST /rest/v1/appointments
Supabase-->>Paciente: Consulta criada ✅
2. Fluxo de Recuperação de Senha
sequenceDiagram
Usuário->>LoginPage: Clica "Esqueceu a senha?"
LoginPage->>AuthService: requestPasswordReset(email)
AuthService->>Supabase: POST /auth/v1/recover
Supabase->>Email: Envia link de recuperação
Usuário->>Email: Clica no link
Email->>ResetPassword: Redireciona com token
ResetPassword->>AuthService: updatePassword(token, novaSenha)
AuthService->>Supabase: PUT /auth/v1/user
Supabase-->>ResetPassword: Senha atualizada ✅
3. Fluxo de Validação de Roles
// LoginMedico.tsx
const handleLogin = async () => {
// 1. Login
const loginResponse = await authService.login({ email, password });
// 2. Buscar roles
const userInfo = await userService.getUserInfo();
const roles = userInfo.roles || [];
// 3. Validar permissão
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;
}
// 4. Redirecionar
navigate("/painel-medico");
};
🚀 Deploy
Cloudflare Pages
O projeto é hospedado no Cloudflare Pages com deploy automático via Wrangler CLI.
Comandos de Deploy
# Build de produção
pnpm build
# Deploy para Cloudflare
npx wrangler pages deploy dist --project-name=mediconnect
# Deploy com branch específica
npx wrangler pages deploy dist --project-name=mediconnect --branch=production
# Deploy ignorando mudanças não commitadas
npx wrangler pages deploy dist --project-name=mediconnect --commit-dirty=true
Configuração do Cloudflare
- Production Branch:
production - Build Command:
pnpm build - Build Output:
dist - Custom Domain:
mediconnectbrasil.app
URLs de Deploy
- Production: https://mediconnectbrasil.app/
- Preview: https://mediconnect-5oz.pages.dev/
- Branch Preview: https://[branch].mediconnect-5oz.pages.dev/
💻 Desenvolvimento Local
Pré-requisitos
- Node.js 18+
- pnpm 8+
- Git
Instalação
# 1. Clone o repositório
git clone https://git.popcode.com.br/RiseUP/riseup-squad18.git
cd riseup-squad18/"MEDICONNECT 2"
# 2. Instale as dependências
pnpm install
# 3. Configure as variáveis de ambiente (se necessário)
# Crie um arquivo .env.local com as configurações do Supabase
# 4. Inicie o servidor de desenvolvimento
pnpm dev
# 5. Acesse http://localhost:5173
Scripts Disponíveis
# Desenvolvimento
pnpm dev # Inicia servidor dev
# Build
pnpm build # Build de produção
pnpm preview # Preview do build
# Testes
pnpm test # Executa testes
pnpm test:ui # UI de testes
# Lint
pnpm lint # Verifica código
# Type check
pnpm type-check # Verifica tipos TypeScript
Variáveis de Ambiente
# .env.local (opcional - já configurado no código)
VITE_SUPABASE_URL=https://yuanqfswhberkoevtmfr.supabase.co
VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
VITE_APP_URL=http://localhost:5173
📊 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)
🔧 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
🎨 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;
<EFBFBD> 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
📝 Changelog
v2.0.0 (Outubro 2024)
- ✅ Migração completa de Netlify Functions para Supabase
- ✅ Implementação de recuperação de senha
- ✅ Deploy no Cloudflare Pages
- ✅ Novo HeroBanner com imagens rotativas
- ✅ Chatbot integrado
- ✅ Sistema de roles e permissões
- ✅ Interface responsiva e dark mode
v1.0.0 (Setembro 2024)
- ✅ Lançamento inicial
- ✅ Login de pacientes, médicos e secretárias
- ✅ Agendamento de consultas
- ✅ Gestão de disponibilidade
📄 Licença
Este projeto é parte do programa Rise Up e está sob licença proprietária da PopCode.
Desenvolvido com ❤️ pela Squad 18
Description
Languages
TypeScript
95.9%
PowerShell
1.8%
CSS
1.2%
JavaScript
0.8%
Python
0.2%