Loading...
Loading...
Loading...
# 📚 DOCUMENTAÇÃO TÉCNICA COMPLETA - E-VOLUA
## Sistema de Avaliação de Desempenho na Prática de Alunos
**Versão:** 1.0.0
**Data:** Outubro de 2025
**Repositório:** github.com/julioventura/evolua
**Domínio:** cirurgia.com.br/evolua
---
## 📋 ÍNDICE
1. [Visão Geral](#-visão-geral)
2. [Especificações Técnicas](#-especificações-técnicas)
3. [Arquitetura e Infraestrutura](#️-arquitetura-e-infraestrutura)
4. [Configuração do Ambiente](#️-configuração-do-ambiente)
5. [Estrutura do Banco de Dados](#️-estrutura-do-banco-de-dados)
6. [Sistema de Autenticação](#-sistema-de-autenticação)
7. [Funcionalidades Principais](#-funcionalidades-principais)
8. [Segurança Implementada](#-segurança-implementada)
9. [Guia de Replicação](#-guia-de-replicação)
10. [Resolução de Problemas](#-resolução-de-problemas)
---
## 🎯 VISÃO GERAL
O **e-volua** é uma plataforma web moderna para avaliação de desempenho de alunos em aulas práticas, especialmente voltada para contextos médicos e de saúde. O sistema permite que professores criem avaliações, gerenciem turmas e acompanhem o progresso dos alunos em tempo real.
### Principais Características
- ✅ Sistema completo de gestão de turmas e alunos
- ✅ Avaliações periódicas estruturadas
- ✅ Dashboard interativo com estatísticas em tempo real
- ✅ Sistema de autenticação robusto com múltiplos papéis de usuário
- ✅ Interface responsiva e moderna
- ✅ Armazenamento seguro de dados com PostgreSQL
- ✅ Integração com automações via N8N
---
## 💻 ESPECIFICAÇÕES TÉCNICAS
### Frontend e Build
#### Linguagem de Programação
- **TypeScript** `5.8.3`
- Linguagem fortemente tipada baseada em JavaScript
- Configuração strict mode para máxima segurança de tipos
- Target: ES2022 (ECMAScript 2022)
- Module System: ESNext
#### Framework e Bibliotecas React
- **React** `19.1.0` - Biblioteca para construção de interfaces
- **React DOM** `19.1.0` - Integração com navegador
- **React Router DOM** `7.6.3` - Sistema de roteamento SPA
#### Ferramenta de Build
- **Vite** `7.0.0`
- Build tool de alta performance
- Hot Module Replacement (HMR)
- Otimização automática de bundles
- Code splitting inteligente
#### Framework de Estilização
- **Tailwind CSS** `4.1.11`
- Framework utility-first
- Customização via `tailwind.config.js`
- Paleta de cores personalizada (primary blue)
- **PostCSS** `8.5.6` - Processador CSS
- **Autoprefixer** `10.4.21` - Compatibilidade cross-browser
#### Bibliotecas de UI e Utilitários
- **@heroicons/react** `2.2.0` - Ícones SVG otimizados
- **date-fns** `4.1.0` - Manipulação de datas
- **clsx** `2.1.1` - Construção condicional de classes
- **tailwind-merge** `3.3.1` - Merge de classes Tailwind sem conflitos
### Backend e Banco de Dados
#### Plataforma Backend
- **Supabase** (Auto-hospedado/Open Source)
- PostgreSQL 15+ para banco de dados
- Autenticação integrada (JWT)
- Row Level Security (RLS)
- Real-time subscriptions
- Storage para arquivos
- **@supabase/supabase-js** `2.50.3`
- Cliente JavaScript oficial
- Suporte a persistência de sessão
- Auto-refresh de tokens
- Detecção automática de sessão
### Infraestrutura e Hospedagem
#### Servidor VPS (Auto-hospedado)
- **Supabase Open Source**
- PostgreSQL database
- PostgREST API
- GoTrue authentication
- Realtime server
- Storage server
- **N8N** (Workflow Automation)
- Automação de processos
- Integrações com serviços externos
- Triggers e webhooks
- **Apache Web Server**
- Hospedagem do domínio cirurgia.com.br
- Configuração SSL/TLS
- Proxy reverso para Supabase
### Ferramentas de Desenvolvimento
#### IDE e Editor
- **Visual Studio Code** (VSCode)
- Editor gratuito da Microsoft
- Extensões TypeScript nativas
- Integrated terminal
- Git integration
#### Assistência de IA (GitHub Copilot)
Assinatura profissional com acesso aos seguintes modelos:
**Anthropic Claude:**
- Claude Sonnet 3.7
- Claude Sonnet 4
- Claude Sonnet 4.5
**OpenAI:**
- GPT-4o
- GPT-4.1
- GPT-5
#### Controle de Versão
- **Git** - Sistema de controle de versão
- **GitHub.com** (Microsoft)
- Repositório remoto
- Controle de versões
- Backup automático online
- CI/CD pipelines (se configurado)
### Qualidade de Código
#### Linting e Análise Estática
- **ESLint** `9.29.0`
- Análise estática de código
- Detecção de erros e bad practices
- **TypeScript ESLint** `8.34.1`
- Regras específicas para TypeScript
- **eslint-plugin-react-hooks** `5.2.0`
- Validação de React Hooks
- **eslint-plugin-react-refresh** `0.4.20`
- Suporte para Fast Refresh
---
## 🏗️ ARQUITETURA E INFRAESTRUTURA
### Arquitetura da Aplicação
```text
┌─────────────────────────────────────────────────────────┐
│ FRONTEND (React) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Dashboard │ │ Turmas │ │ Avaliações │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Login │ │ Membros │ │ Relatórios │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
│
HTTPS/REST API
│
┌─────────────────────────────────────────────────────────┐
│ SUPABASE (VPS Auto-hospedado) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ PostgreSQL │ │ GoTrue │ │ PostgREST │ │
│ │ Database │ │ Auth │ │ REST API │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Realtime │ │ Storage │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
│
Automações
│
┌─────────────────────────────────────────────────────────┐
│ N8N WORKFLOWS │
│ • Notificações automáticas │
│ • Sincronização de dados │
│ • Relatórios agendados │
└─────────────────────────────────────────────────────────┘
```
### Estrutura de Diretórios
```text
evolua/
├── public/ # Arquivos estáticos públicos
│ ├── favicon.svg
│ └── assets/
│
├── sql/ # Scripts SQL do banco de dados
│ ├── avaliacoes_periodicas.sql
│ ├── create_user_configs.sql
│ └── ...
│
├── src/ # Código-fonte principal
│ ├── assets/ # Imagens e recursos
│ │
│ ├── components/ # Componentes React
│ │ ├── features/ # Componentes específicos
│ │ ├── layout/ # Componentes de layout
│ │ ├── ui/ # Componentes reutilizáveis
│ │ ├── ChatbotModal.tsx
│ │ ├── ProtectedRoute.tsx
│ │ └── SecurityGuard.tsx
│ │
│ ├── config/ # Configurações
│ │ └── roleConfig.ts # Configuração de papéis
│ │
│ ├── contexts/ # Contextos React
│ │ ├── AuthContext.tsx
│ │ ├── AuthContext.types.ts
│ │ ├── SettingsContext.tsx
│ │ └── ThemeContext.tsx
│ │
│ ├── hooks/ # Custom Hooks
│ │ ├── useAuth.ts
│ │ ├── useProfile.ts
│ │ ├── useRoleMonitor.ts
│ │ ├── useTurmas.ts
│ │ └── useUserValidation.ts
│ │
│ ├── lib/ # Serviços e utilitários
│ │ ├── supabaseClient.ts # Cliente Supabase
│ │ ├── turmasService.ts
│ │ ├── avaliacoesService.ts
│ │ ├── avaliacoesPeriodicas.ts
│ │ ├── profileService.ts
│ │ ├── roleValidation.ts
│ │ └── utils.ts
│ │
│ ├── pages/ # Páginas da aplicação
│ │ ├── DashboardPage.tsx
│ │ ├── LoginPage.tsx
│ │ ├── TurmasPage.tsx
│ │ ├── AvaliacoesPage.tsx
│ │ └── ...
│ │
│ ├── types/ # Definições TypeScript
│ │ ├── supabase.ts
│ │ └── ...
│ │
│ ├── App.tsx # Componente principal
│ ├── main.tsx # Ponto de entrada
│ └── types.ts # Tipos globais
│
├── .env.example # Exemplo de variáveis de ambiente
├── .gitignore # Arquivos ignorados pelo Git
├── index.html # HTML principal
├── package.json # Dependências do projeto
├── tsconfig.json # Configuração TypeScript
├── vite.config.ts # Configuração Vite
└── tailwind.config.js # Configuração Tailwind
```
### Otimizações de Build
O projeto implementa **code splitting** estratégico:
#### Separação de Vendors
- `vendor-react`: React, React DOM, React Router
- `vendor-supabase`: Cliente Supabase
- `vendor-heroicons`: Ícones
- `vendor-date`: date-fns
- `vendor-other`: Outras dependências
#### Separação de Páginas
- `page-dashboard`: Página principal
- `page-avaliacoes`: Sistema de avaliações
- `page-turmas`: Gestão de turmas
- `page-membros`: Gestão de membros
- `pages-other`: Outras páginas
#### Separação de Serviços
- `services`: Serviços de turmas, avaliações e periódicas
**Limite de Warning:** 600KB por chunk
---
## ⚙️ CONFIGURAÇÃO DO AMBIENTE
### Pré-requisitos
- **Node.js** >= 18.0.0
- **npm** >= 9.0.0 ou **yarn** >= 1.22.0
- **Git** >= 2.30.0
- Conta Supabase (ou instalação auto-hospedada)
### Instalação Passo a Passo
#### 1. Clonar o Repositório
```bash
git clone https://github.com/julioventura/evolua.git
cd evolua
```
#### 2. Instalar Dependências
```bash
npm install
```
#### 3. Configurar Variáveis de Ambiente
Criar arquivo `.env` na raiz do projeto:
```bash
# Windows
copy .env.example .env
# Linux/Mac
cp .env.example .env
```
Editar `.env` com suas credenciais:
```env
# Supabase Configuration
VITE_SUPABASE_URL=https://seu-projeto.supabase.co
VITE_SUPABASE_ANON_KEY=eyJ... (chave completa)
```
**Como obter as credenciais:**
1. Acesse [supabase.com](https://supabase.com)
2. Vá em **Project Settings** → **API**
3. Copie **Project URL** e **anon public key**
#### 4. Executar em Desenvolvimento
```bash
npm run dev
```
**Windows (usando batch file):**
```batch
run.bat
```
Aplicação disponível em: `http://localhost:5173`
#### 5. Build para Produção
```bash
npm run build
```
**Windows:**
```batch
build.bat
```
Arquivos gerados em: `dist/`
#### 6. Preview da Build
```bash
npm run preview
```
---
## 🗄️ ESTRUTURA DO BANCO DE DADOS
### Tabelas Principais
#### 1. `profiles` - Perfis de Usuário
```sql
CREATE TABLE profiles (
id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
nome TEXT NOT NULL,
email TEXT,
whatsapp TEXT,
cidade TEXT,
estado TEXT,
avatar_url TEXT,
categoria TEXT NOT NULL DEFAULT 'aluno'
CHECK (categoria IN ('aluno', 'professor', 'admin', 'monitor', 'outro')),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
PRIMARY KEY (id)
);
```
**Papéis de Usuário:**
- `admin`: Acesso total ao sistema
- `professor`: Gerencia turmas e avaliações
- `monitor`: Auxilia em turmas específicas
- `aluno`: Participa de turmas e responde avaliações
- `outro`: Sem permissões (estado transitório)
#### 2. `turmas` - Gestão de Turmas
```sql
CREATE TABLE turmas (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
nome TEXT NOT NULL,
descricao TEXT,
professor_id UUID REFERENCES profiles(id),
codigo_acesso TEXT UNIQUE,
ativa BOOLEAN DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
```
#### 3. `turma_membros` - Relacionamento Turma-Aluno
```sql
CREATE TABLE turma_membros (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
turma_id UUID REFERENCES turmas(id) ON DELETE CASCADE,
aluno_id UUID REFERENCES profiles(id) ON DELETE CASCADE,
papel TEXT DEFAULT 'aluno' CHECK (papel IN ('aluno', 'monitor')),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(turma_id, aluno_id)
);
```
#### 4. `formularios_avaliacao` - Templates de Avaliação
```sql
CREATE TABLE formularios_avaliacao (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
titulo TEXT NOT NULL,
descricao TEXT,
professor_id UUID REFERENCES profiles(id),
schema_json JSONB NOT NULL,
ativo BOOLEAN DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
```
#### 5. `instancias_avaliacao` - Avaliações Distribuídas
```sql
CREATE TABLE instancias_avaliacao (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
formulario_id UUID REFERENCES formularios_avaliacao(id),
aluno_id UUID REFERENCES profiles(id),
turma_id UUID REFERENCES turmas(id),
status TEXT DEFAULT 'pendente'
CHECK (status IN ('pendente', 'iniciada', 'concluida', 'vencida')),
data_inicio TIMESTAMP WITH TIME ZONE,
data_limite TIMESTAMP WITH TIME ZONE,
data_conclusao TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
```
#### 6. `respostas_avaliacao` - Respostas dos Alunos
```sql
CREATE TABLE respostas_avaliacao (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
instancia_id UUID REFERENCES instancias_avaliacao(id) ON DELETE CASCADE,
respostas_json JSONB NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
```
### Triggers e Funções
#### 🔴 CRÍTICO: Auto-criação de Profile
**⚠️ Este trigger é ESSENCIAL para o cadastro funcionar!**
Sem ele, você receberá o erro: `Database error saving new user`
**Script completo:** `sql/create_profile_trigger.sql` ou `sql/FIX_URGENTE_profile_trigger.sql`
```sql
-- Função que cria profile automaticamente
CREATE OR REPLACE FUNCTION public.evolua_handle_new_user()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
v_nome TEXT;
v_categoria TEXT;
BEGIN
-- Extrair dados do metadata
v_nome := COALESCE(
NEW.raw_user_meta_data->>'nome',
NEW.raw_user_meta_data->>'full_name',
split_part(NEW.email, '@', 1)
);
v_categoria := COALESCE(
NEW.raw_user_meta_data->>'categoria',
'aluno'
);
-- Inserir profile
INSERT INTO public.profiles (
id, nome, email, categoria, created_at, updated_at
) VALUES (
NEW.id, v_nome, NEW.email, v_categoria, NOW(), NOW()
)
ON CONFLICT (id) DO UPDATE SET
nome = EXCLUDED.nome,
email = EXCLUDED.email,
updated_at = NOW();
RETURN NEW;
EXCEPTION
WHEN OTHERS THEN
RAISE WARNING 'Erro ao criar profile: % - %', SQLSTATE, SQLERRM;
RETURN NEW;
END;
$$;
-- Trigger que dispara a função
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW
EXECUTE FUNCTION public.evolua_handle_new_user();
```
**Verificar se existe:**
```sql
SELECT trigger_name, event_object_table
FROM information_schema.triggers
WHERE trigger_name = 'on_auth_user_created';
```
### Row Level Security (RLS)
#### Políticas de Segurança para `profiles`
```sql
-- Habilitar RLS
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
-- Usuários podem ver seu próprio perfil
CREATE POLICY "Users can view their own profile"
ON profiles FOR SELECT
USING (auth.uid() = id);
-- Usuários podem atualizar seu próprio perfil
CREATE POLICY "Users can update their own profile"
ON profiles FOR UPDATE
USING (auth.uid() = id);
-- Admins podem ver todos os perfis
CREATE POLICY "Admins can view all profiles"
ON profiles FOR SELECT
USING (
EXISTS (
SELECT 1 FROM profiles
WHERE id = auth.uid() AND categoria = 'admin'
)
);
```
#### Políticas para `turmas`
```sql
ALTER TABLE turmas ENABLE ROW LEVEL SECURITY;
-- Professores veem suas turmas
CREATE POLICY "Professors can view their turmas"
ON turmas FOR SELECT
USING (professor_id = auth.uid());
-- Alunos veem turmas em que estão matriculados
CREATE POLICY "Students can view their enrolled turmas"
ON turmas FOR SELECT
USING (
id IN (
SELECT turma_id FROM turma_membros
WHERE aluno_id = auth.uid()
)
);
```
---
## 🔐 SISTEMA DE AUTENTICAÇÃO
### Arquitetura de Autenticação
O sistema utiliza múltiplas camadas de segurança:
#### 1. AuthProvider (Context API)
**Arquivo:** `src/contexts/AuthProviderEmergency.tsx`
Responsabilidades:
- Gerenciar estado de autenticação
- Carregar perfil do usuário
- Sincronizar sessão com Supabase
- Implementar retry logic com backoff exponencial
- Cache multi-camadas de perfil
**Características:**
```typescript
interface AuthContextType {
user: AppUser | null;
loading: boolean;
login: (email: string, password: string) => Promise<void>;
logout: () => Promise<void>;
signup: (data: SignupData) => Promise<void>;
}
```
#### 2. Proteção de Rotas
**Arquivo:** `src/components/ProtectedRoute.tsx`
```typescript
<ProtectedRoute>
<DashboardPage />
</ProtectedRoute>
```
Funcionalidades:
- Verifica autenticação antes de renderizar
- Redireciona para login se não autenticado
- Exibe loading durante verificação
- Integra com useUserValidation
#### 3. Validação de Usuário
**Arquivo:** `src/hooks/useUserValidation.ts`
```typescript
const { isValid, error } = useUserValidation();
```
Validações:
- Detecta categoria "outro" (inválida)
- Força logout de usuários inválidos
- Redireciona para login com mensagem
- Log de auditoria de validações
#### 4. Monitor de Papéis
**Arquivo:** `src/hooks/useRoleMonitor.ts`
```typescript
const { hasPermission, userRole } = useRoleMonitor();
```
Funcionalidades:
- Detecta mudanças suspeitas de papel
- Alerta sobre escalações não autorizadas
- Log de segurança para auditoria
- Prevenção de privilege escalation
#### 5. SecurityGuard Component
**Arquivo:** `src/components/SecurityGuard.tsx`
```typescript
<SecurityGuard requiredRoles={['professor', 'admin']}>
<ConteudoProtegido />
</SecurityGuard>
```
Proteção granular por componente:
- Validação de permissões em tempo real
- Controle de acesso baseado em papéis
- Mensagens customizadas de acesso negado
### Fluxo de Autenticação
```text
1. USUÁRIO ACESSA APLICAÇÃO
↓
2. AuthProvider.useEffect() INICIA
↓
3. Verifica sessão no Supabase
↓
4. Se autenticado:
├─→ Carrega perfil (com retry/cache)
├─→ Valida categoria !== 'outro'
├─→ Atualiza contexto
└─→ Libera acesso
↓
5. Se não autenticado:
└─→ Redireciona para /login
↓
6. LOGIN:
├─→ Supabase.auth.signInWithPassword()
├─→ Carrega perfil completo
├─→ Valida categoria
└─→ Redireciona para dashboard
↓
7. MONITORAMENTO CONTÍNUO:
├─→ useRoleMonitor detecta mudanças
├─→ useUserValidation valida estado
└─→ SecurityGuard protege componentes
```
### Estratégia de Cache
#### Cache Multi-Camada
##### Camada 1: Memória (5 minutos)
```typescript
let profileCache: { data: Profile; timestamp: number } | null = null;
```
##### Camada 2: localStorage (persistente)
```typescript
localStorage.setItem('user_profile_cache', JSON.stringify(profile));
```
##### Camada 3: Supabase (source of truth)
```typescript
const { data, error } = await supabase
.from('profiles')
.select('*')
.eq('id', userId)
.single();
```
#### Retry Logic com Backoff Exponencial
```typescript
const delays = [1000, 2000, 4000]; // 1s, 2s, 4s
for (let attempt = 0; attempt < 3; attempt++) {
try {
return await loadProfile();
} catch (error) {
if (attempt < 2) {
await sleep(delays[attempt]);
}
}
}
```
### Segurança de Fallbacks
*❌ NUNCA usar "professor" como fallback
```typescript
// ERRADO
categoria: 'professor' // PERIGOSO!
// CORRETO
categoria: 'outro' // Será bloqueado pela validação
```
### Health Check do Supabase
```typescript
const checkSupabaseHealth = async (): Promise<boolean> => {
try {
const { error } = await supabase
.from('profiles')
.select('id')
.limit(1);
return !error;
} catch {
return false;
}
};
```
---
## 🎨 FUNCIONALIDADES PRINCIPAIS
### 1. Dashboard Interativo
**Arquivo:** `src/pages/DashboardPage.tsx`
#### Cards de Estatísticas
- **Avaliações**: Total e filtros por status
- **Turmas**: Ativas e arquivadas
- **Alunos**: Total matriculados
- **Atividades Recentes**: Timeline de ações
#### Modais Interativos
Todos os cards abrem modais detalhados:
- Lista completa de items
- Filtros e busca
- Ações rápidas (criar, editar, excluir)
- Modo maximizado (tela cheia)
#### Ações Rápidas
- 📝 Nova Avaliação
- 👥 Gerenciar Alunos
- 📊 Gerar Relatórios
- 📁 Arquivos de Referência (Google Drive)
#### Card Exclusivo para Admins
- 👤 **Usuários**: Visível apenas para admins
- Lista todos os usuários por categoria
- Detalhes completos de perfil
- Gerenciamento de permissões
### 2. Gestão de Turmas
**Arquivo:** `src/pages/TurmasPage.tsx`
#### Funcionalidades
- Criar/editar/arquivar turmas
- Código de acesso único por turma
- Adicionar/remover alunos
- Definir monitores
- Visualizar estatísticas da turma
#### Configuração por Papel
```typescript
// Admin vê todas as turmas
// Professor vê suas turmas
// Monitor vê turmas que monitora
// Aluno vê turmas matriculadas
```
### 3. Sistema de Avaliações Periódicas
**Arquivo:** `src/pages/AvaliacoesPage.tsx`
#### Para Professores/Monitores
**Criar Formulário:**
```typescript
const formulario = {
titulo: "Avaliação Prática Diária",
descricao: "Avaliação de desempenho em procedimentos",
schema_json: {
paginas: [
{
titulo: "Dados do Paciente",
campos: [/* ... */]
},
{
titulo: "Avaliação por Competências",
questoes: [/* ... */]
}
]
}
};
```
**Distribuir para Turma:**
```typescript
await distribuirAvaliacao({
formularioId,
turmaId,
destinatarios: ['aluno1', 'aluno2'],
dataLimite: '2025-11-30'
});
```
#### Para Alunos
**Visualizar Avaliações:**
- Aba "Avaliações Periódicas"
- Status: Pendente, Iniciada, Concluída, Vencida
- Prazo limite destacado
**Responder Avaliação:**
- Formulário multi-página
- Salvamento automático
- Validação de campos obrigatórios
- Confirmação de envio
#### Estrutura do Formulário
##### Página 1: Informações Iniciais
- Seleção de aluno (professores/monitores)
- Nome do paciente
- Idade do paciente
- Configuração de turnos (manhã/tarde)
- Anamnese
- Exame físico
- Procedimentos
- Finalização
##### Página 2: Questões de Avaliação
- Informações do estudante
- Pontuação por competência (1-5)
- Pontos fortes observados
- Pontos a melhorar
- Justificativas para notas baixas
### 4. Gestão de Membros
**Arquivo:** `src/pages/MembrosPage.tsx`
** Funcionalidades
- Adicionar alunos por código de acesso
- Promover aluno a monitor
- Remover membros da turma
- Visualizar perfil completo
- Histórico de avaliações do aluno
---
## 🔒 SEGURANÇA IMPLEMENTADA
### Correções Críticas de Segurança
#### 1. Eliminação de Fallback Inseguro
**Problema Identificado:**
```typescript
// ❌ PERIGOSO - Permitia escalação de privilégios
categoria: 'professor' // Fallback anterior
```
**Solução Implementada:**
```typescript
// ✅ SEGURO - Sempre usa menor privilégio
categoria: 'outro' // Será bloqueado automaticamente
```
**Arquivos Corrigidos:**
- `src/contexts/AuthProviderProduction.tsx`
- `src/contexts/AuthProviderFinal.tsx`
- `src/contexts/AuthProviderEmergency.tsx`
#### 2. Sistema de Validação Robusto
**Arquivo:** `src/lib/roleValidation.ts`
```typescript
export function sanitizeRole(role: any): UserRole {
const validRoles = ['admin', 'professor', 'monitor', 'aluno'];
if (!role || typeof role !== 'string') {
return 'outro';
}
return validRoles.includes(role) ? role : 'outro';
}
export function isRoleChangeValid(
oldRole: UserRole,
newRole: UserRole
): boolean {
// Previne escalações não autorizadas
const roleHierarchy = {
'aluno': 0,
'monitor': 1,
'professor': 2,
'admin': 3,
'outro': -1
};
return roleHierarchy[newRole] <= roleHierarchy[oldRole];
}
```
#### 3. Log de Auditoria
```typescript
export function logRoleChange(
userId: string,
oldRole: UserRole,
newRole: UserRole,
context: string
): void {
console.log(`[AUDIT] Mudança de papel:`, {
userId,
oldRole,
newRole,
context,
timestamp: new Date().toISOString(),
valid: isRoleChangeValid(oldRole, newRole)
});
if (!isRoleChangeValid(oldRole, newRole)) {
console.error(`[SECURITY] Escalação não autorizada detectada!`);
}
}
```
### Proteções em Tempo Real
#### useRoleMonitor Hook
```typescript
export function useRoleMonitor() {
const { user } = useAuth();
const [previousRole, setPreviousRole] = useState<UserRole | null>(null);
useEffect(() => {
if (user?.categoria && previousRole) {
if (user.categoria !== previousRole) {
logRoleChange(
user.id,
previousRole,
user.categoria,
'runtime-change'
);
if (!isRoleChangeValid(previousRole, user.categoria)) {
alert('Mudança de permissão detectada. Por segurança, você será desconectado.');
logout();
}
}
}
setPreviousRole(user?.categoria || null);
}, [user?.categoria]);
}
```
### Políticas de RLS para Tabelas
Todas as tabelas implementam Row Level Security (RLS):
```sql
-- Exemplo: Turmas
CREATE POLICY "Users can only see relevant turmas"
ON turmas FOR SELECT
USING (
-- Admins veem todas
(SELECT categoria FROM profiles WHERE id = auth.uid()) = 'admin'
OR
-- Professores veem suas turmas
professor_id = auth.uid()
OR
-- Alunos veem turmas matriculadas
id IN (
SELECT turma_id FROM turma_membros
WHERE aluno_id = auth.uid()
)
);
```
### Validação de Input
#### Frontend
```typescript
const schema = z.object({
email: z.string().email(),
password: z.string().min(8),
nome: z.string().min(3),
categoria: z.enum(['aluno', 'professor', 'monitor', 'admin'])
});
```
#### Backend (Supabase Functions)
```sql
CHECK (categoria IN ('aluno', 'professor', 'admin', 'monitor', 'outro'))
```
### Proteção CSRF
- Tokens JWT com expiração
- Refresh token automático
- SameSite cookies
- CORS configurado
---
## 📖 GUIA DE REPLICAÇÃO
### Passo 1: Preparar Infraestrutura
#### Opção A: Supabase Cloud (Mais Fácil)
1. Criar conta em [supabase.com](https://supabase.com)
2. Criar novo projeto
3. Anotar credenciais (URL e anon key)
#### Opção B: Supabase Auto-hospedado (VPS)
**Requisitos:**
- VPS com 2GB+ RAM
- Ubuntu 20.04+ ou Debian 11+
- Docker e Docker Compose
- Domínio apontado para VPS
**Instalação:**
```bash
# Clonar Supabase
git clone --depth 1 https://github.com/supabase/supabase
cd supabase/docker
# Configurar .env
cp .env.example .env
nano .env
# Iniciar serviços
docker-compose up -d
```
**Configurar Apache Reverse Proxy:**
```apache
<VirtualHost *:443>
ServerName api.seudominio.com.br
ProxyPass / http://localhost:8000/
ProxyPassReverse / http://localhost:8000/
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/seudominio.com.br/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/seudominio.com.br/privkey.pem
</VirtualHost>
```
### Passo 2: Configurar Banco de Dados
**🔴 IMPORTANTE: Execute os scripts na ordem correta!**
#### Ordem de Execução (via SQL Editor do Supabase):
```bash
# 1. 🔴 CRÍTICO - Trigger de profile (OBRIGATÓRIO)
sql/create_profile_trigger.sql
# 2. Estrutura base
sql/avaliacoes_periodicas.sql
# 3. Configurações de usuário
sql/create_user_configs.sql
# 4. Funções auxiliares
sql/avaliacoes_periodicas_funcoes.sql
```
**Ou executar tudo de uma vez:**
```bash
sql/executar_tudo.sql
```
**⚠️ Se encontrar erro "Database error saving new user":**
Execute imediatamente:
```bash
sql/FIX_URGENTE_profile_trigger.sql
```
### Passo 3: Clonar e Configurar Frontend
```bash
# Clonar repositório
git clone https://github.com/julioventura/evolua.git
cd evolua
# Instalar dependências
npm install
# Configurar ambiente
cp .env.example .env
nano .env
```
**.env:**
```env
VITE_SUPABASE_URL=https://api.seudominio.com.br
VITE_SUPABASE_ANON_KEY=sua_chave_aqui
```
### Passo 4: Build e Deploy
#### Desenvolvimento Local
```bash
npm run dev
```
#### Build para Produção
```bash
npm run build
```
#### Deploy no Apache
```bash
# Copiar build para Apache
sudo cp -r dist/* /var/www/html/evolua/
# Configurar VirtualHost
sudo nano /etc/apache2/sites-available/evolua.conf
```
**evolua.conf:**
```apache
<VirtualHost *:443>
ServerName cirurgia.com.br
DocumentRoot /var/www/html/evolua
<Directory /var/www/html/evolua>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
# SPA Routing
RewriteEngine On
RewriteBase /evolua/
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /evolua/index.html [L]
</Directory>
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/cirurgia.com.br/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/cirurgia.com.br/privkey.pem
</VirtualHost>
```
```bash
# Ativar site
sudo a2ensite evolua
sudo a2enmod rewrite
sudo systemctl reload apache2
```
### Passo 5: Configurar N8N (Opcional)
```bash
# Instalar N8N
npm install n8n -g
# Ou via Docker
docker run -it --rm \
--name n8n \
-p 5678:5678 \
-v ~/.n8n:/home/node/.n8n \
n8nio/n8n
```
**Workflows Úteis:**
- Notificações de novas avaliações (email/WhatsApp)
- Lembretes de prazos
- Relatórios automáticos semanais
- Backup automático do banco
### Passo 6: Criar Primeiro Usuário Admin
```sql
-- No Supabase SQL Editor
-- 1. Registrar usuário via interface
-- 2. Promover para admin:
UPDATE profiles
SET categoria = 'admin'
WHERE email = '[email protected]';
```
### Passo 7: Testar Sistema
**Checklist:**
- [ ] Login funciona
- [ ] Dashboard carrega estatísticas
- [ ] Pode criar turma
- [ ] Pode criar avaliação
- [ ] Pode adicionar alunos
- [ ] Avaliações são distribuídas
- [ ] Aluno consegue responder
- [ ] Estatísticas atualizam
---
## 🔧 RESOLUÇÃO DE PROBLEMAS
### Problema: "Database error saving new user" ao Cadastrar
**Sintomas:**
- Erro 500 ao tentar criar conta
- Mensagem: "Database error saving new user"
- Console mostra: `Failed to load resource: the server responded with a status of 500`
**Causa:**
Trigger de auto-criação de profile não existe, está quebrado, ou há **triggers duplicados/conflitantes** no banco de dados.
**Diagnóstico - Verificar triggers existentes:**
```sql
-- Ver TODOS os triggers na tabela auth.users
-- IMPORTANTE: Deve haver apenas 1 trigger para criar profile!
SELECT
trigger_name,
event_manipulation,
action_statement
FROM information_schema.triggers
WHERE event_object_schema = 'auth'
AND event_object_table = 'users';
```
**Se houver mais de 1 trigger**, remova os duplicados:
```sql
-- Remover triggers conflitantes (manter apenas on_auth_user_created)
DROP TRIGGER IF EXISTS on_auth_user_created_safe ON auth.users;
DROP TRIGGER IF EXISTS create_user_config_on_signup ON auth.users;
-- Adicione outros triggers duplicados se existirem
-- Verificar se só sobrou o correto
SELECT trigger_name
FROM information_schema.triggers
WHERE event_object_schema = 'auth'
AND event_object_table = 'users';
```
**Solução Rápida (se não existir trigger):**
1. Acesse o **Supabase Dashboard** → **SQL Editor**
2. Execute o script: `sql/FIX_URGENTE_profile_trigger.sql`
3. Verifique se aparece "Trigger criado com sucesso!"
4. Tente criar usuário novamente
**Ou execute manualmente:**
```sql
-- Copie e cole este código no SQL Editor do Supabase
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users CASCADE;
DROP FUNCTION IF EXISTS public.evolua_handle_new_user() CASCADE;
CREATE OR REPLACE FUNCTION public.evolua_handle_new_user()
RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER
SET search_path = public AS $$
DECLARE
v_nome TEXT;
v_categoria TEXT;
BEGIN
v_nome := COALESCE(
NEW.raw_user_meta_data->>'nome',
NEW.raw_user_meta_data->>'full_name',
split_part(NEW.email, '@', 1)
);
v_categoria := COALESCE(
NEW.raw_user_meta_data->>'categoria',
'aluno'
);
INSERT INTO public.profiles (id, nome, email, categoria, created_at, updated_at)
VALUES (NEW.id, v_nome, NEW.email, v_categoria, NOW(), NOW())
ON CONFLICT (id) DO UPDATE SET
nome = EXCLUDED.nome, email = EXCLUDED.email, updated_at = NOW();
RETURN NEW;
EXCEPTION
WHEN OTHERS THEN
RAISE WARNING 'Erro ao criar profile: % - %', SQLSTATE, SQLERRM;
RETURN NEW;
END;
$$;
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW
EXECUTE FUNCTION public.evolua_handle_new_user();
```
**Verificar se funcionou:**
```sql
SELECT trigger_name, event_object_table
FROM information_schema.triggers
WHERE trigger_name = 'on_auth_user_created';
```
---
### Problema: "Verificando autenticação..." Infinito
**Sintomas:**
- App fica em loading infinito
- Login não completa
- Console mostra timeouts
**Solução:**
1. **Verificar conexão Supabase:**
```javascript
// No console do navegador
const { data, error } = await supabase
.from('profiles')
.select('*')
.limit(1);
console.log(data, error);
```
**2. Limpar cache e storage:**
```javascript
```
**3. Limpar cache e storage:**
```javascript
localStorage.clear();
sessionStorage.clear();
location.reload();
```
**3. Verificar logs do AuthProvider:**
```text
```
**4. Verificar logs do AuthProvider:**
```text
🎭 AuthProvider useEffect INICIANDO...
🎯 AuthProvider - Init simples
🔄 Auth mudou: SIGNED_IN [email]
✅ Perfil carregado
🏁 Loading finalizado
```
**4. Se persistir, usar AuthProvider alternativo:**
```typescript
// Em src/contexts/AuthContext.tsx
export { AuthProvider } from './AuthProviderWorking';
```
### Problema: ERR_NAME_NOT_RESOLVED
**Causa:** Variáveis de ambiente não configuradas
**Solução:**
1. Verificar se `.env` existe
2. Verificar valores:
```env
VITE_SUPABASE_URL=https://... (sem barra no final)
VITE_SUPABASE_ANON_KEY=eyJ... (chave completa)
```
1. Reiniciar servidor dev:
```bash
# Ctrl+C para parar
npm run dev
```
### Problema: Usuário com Categoria "outro"
**Causa:** Falha no carregamento de perfil
**Solução Automática:**
- Sistema detecta e força logout
- Mensagem aparece no login
- Verificar RLS policies no Supabase
**Solução Manual:**
```sql
-- Corrigir categoria no banco
UPDATE profiles
SET categoria = 'aluno' -- ou professor, admin, monitor
WHERE email = '[email protected]';
```
### Problema: Avaliações Não Aparecem
**Checklist:**
Verificar se usuário está na turma:
```sql
SELECT * FROM turma_membros WHERE aluno_id = 'user_id';
```
Verificar distribuição:
```sql
SELECT * FROM instancias_avaliacao
WHERE aluno_id = 'user_id'
ORDER BY created_at DESC;
```
Verificar RLS:
```sql
-- Testar query diretamente
SELECT * FROM instancias_avaliacao WHERE aluno_id = auth.uid();
```
### Problema: Dashboard Vazio
**Causa:** Queries falhando silenciosamente
**Solução:**
1. Abrir DevTools (F12)
2. Procurar erros no console
3. Verificar Network tab para erros 401/403
4. Testar queries manualmente no Supabase
### Problema: Build Falha
**Erros Comuns:**
#### TypeScript errors
```bash
# Limpar cache TypeScript
rm -rf node_modules/.cache
rm -rf dist
npm run build
```
##### Vite errors
```bash
# Reinstalar dependências
rm -rf node_modules
rm package-lock.json
npm install
```
##### Memory errors
```bash
# Aumentar limite Node
NODE_OPTIONS=--max_old_space_size=4096 npm run build
```
### Logs de Diagnóstico
#### Habilitar logs detalhados
```typescript
// Em src/lib/supabaseClient.ts
export const supabase = createClient(url, key, {
auth: {
persistSession: true,
autoRefreshToken: true,
detectSessionInUrl: true,
debug: true // <- Adicionar esta linha
}
});
```
#### Verificar saúde do sistema
```typescript
// Executar no console
async function diagnostico() {
console.log('🔍 Iniciando diagnóstico...');
// 1. Supabase conectado?
const { data: health } = await supabase
.from('profiles')
.select('id')
.limit(1);
console.log('✅ Supabase:', health ? 'OK' : 'ERRO');
// 2. Usuário autenticado?
const { data: { user } } = await supabase.auth.getUser();
console.log('✅ Usuário:', user?.email || 'Não autenticado');
// 3. Profile carregado?
if (user) {
const { data: profile } = await supabase
.from('profiles')
.select('*')
.eq('id', user.id)
.single();
console.log('✅ Profile:', profile);
}
}
diagnostico();
```
---
## 📞 SUPORTE E CONTATO
### Documentação Adicional
- **README.md**: Guia básico de início
- **SUPABASE_CONFIG.md**: Configuração detalhada do Supabase
- **AUTH_PROVIDER_DOC.md**: Documentação completa de autenticação
- **SECURITY_FIX_REPORT.md**: Correções de segurança implementadas
- **AVALIACAO_PERIODICA_GUIDE.md**: Guia de uso das avaliações
### Recursos Externos
- **React**: [react.dev](https://react.dev)
- **TypeScript**: [typescriptlang.org](https://www.typescriptlang.org)
- **Vite**: [vitejs.dev](https://vitejs.dev)
- **Tailwind CSS**: [tailwindcss.com](https://tailwindcss.com)
- **Supabase**: [supabase.com/docs](https://supabase.com/docs)
---
## 📝 CHANGELOG
### Versão 1.0.0 (Outubro 2025)
**Funcionalidades Implementadas:**
- ✅ Sistema completo de autenticação multi-papel
- ✅ Dashboard interativo com estatísticas em tempo real
- ✅ Gestão de turmas com códigos de acesso
- ✅ Sistema de avaliações periódicas
- ✅ Distribuição automática de avaliações
- ✅ Interface responsiva e moderna
- ✅ Segurança robusta com RLS
- ✅ Cache multi-camadas
- ✅ Retry logic com backoff exponencial
- ✅ Monitoramento de papéis em tempo real
- ✅ Validação automática de usuários
- ✅ Logs de auditoria completos
**Correções de Segurança:**
- ✅ Eliminado fallback inseguro "professor"
- ✅ Implementado sistema de validação robusto
- ✅ Prevenção de escalação de privilégios
- ✅ Proteção contra categoria "outro"
- ✅ Log de auditoria de mudanças de papel
---
## 🎯 PRÓXIMOS PASSOS
### Melhorias Planejadas
- [ ] Modo offline com sincronização
- [ ] Notificações push
- [ ] Exportação de relatórios em PDF
- [ ] Dashboard analytics avançado
- [ ] Integração com Google Classroom
- [ ] App mobile (React Native)
- [ ] Sistema de badges e gamificação
- [ ] Vídeo-chamadas integradas
- [ ] Editor de formulários visual
- [ ] Cria modal de envio de mensagens de whatsapp via Servidor de Whatsapp (e não Whatsapp Web)
- [ ] Destacar "Período deve estar no formato AAAA.S (ex: 2025.1, 2025-2, ou apenas 2025)" na criação
- [ ] Ativar/Desativar turma
---
**Desenvolvido com:**
- 💙 React + TypeScript
- ⚡ Vite
- 🎨 Tailwind CSS
- 🗄️ Supabase
- 🤖 GitHub Copilot (Claude & GPT)
**Licença:** Proprietário
**Autor:** Equipe e-volua
**Última Atualização:** Outubro 2025
A standalone type stub package for spotipy using Pydantic models generated from the official Spotify Web API OpenAPI schema.
**Generated**: 2026-03-22
This project provides a comprehensive LLM pricing comparison website with:
<laravel-boost-guidelines>