Back to .md Directory

📚 DOCUMENTAÇÃO TÉCNICA COMPLETA - E-VOLUA

**Data:** Outubro de 2025

May 2, 2026
0 downloads
0 views
ai rag
View source

📚 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
  2. Especificações Técnicas
  3. Arquitetura e Infraestrutura
  4. Configuração do Ambiente
  5. Estrutura do Banco de Dados
  6. Sistema de Autenticação
  7. Funcionalidades Principais
  8. Segurança Implementada
  9. Guia de Replicação
  10. 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

┌─────────────────────────────────────────────────────────┐
│                    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

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

git clone https://github.com/julioventura/evolua.git
cd evolua

2. Instalar Dependências

npm install

3. Configurar Variáveis de Ambiente

Criar arquivo .env na raiz do projeto:

# Windows
copy .env.example .env

# Linux/Mac
cp .env.example .env

Editar .env com suas credenciais:

# 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
  2. Vá em Project SettingsAPI
  3. Copie Project URL e anon public key

4. Executar em Desenvolvimento

npm run dev

Windows (usando batch file):

run.bat

Aplicação disponível em: http://localhost:5173

5. Build para Produção

npm run build

Windows:

build.bat

Arquivos gerados em: dist/

6. Preview da Build

npm run preview

🗄️ ESTRUTURA DO BANCO DE DADOS

Tabelas Principais

1. profiles - Perfis de Usuário

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

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

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

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

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

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

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

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

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

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:

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

<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

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

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

<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

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)
let profileCache: { data: Profile; timestamp: number } | null = null;
Camada 2: localStorage (persistente)
localStorage.setItem('user_profile_cache', JSON.stringify(profile));
Camada 3: Supabase (source of truth)
const { data, error } = await supabase
  .from('profiles')
  .select('*')
  .eq('id', userId)
  .single();

Retry Logic com Backoff Exponencial

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

// ERRADO
categoria: 'professor' // PERIGOSO!

// CORRETO
categoria: 'outro' // Será bloqueado pela validação

Health Check do Supabase

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

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

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:

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:

// ❌ PERIGOSO - Permitia escalação de privilégios
categoria: 'professor' // Fallback anterior

Solução Implementada:

// ✅ 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

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

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

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

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

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)

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

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

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

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

sql/executar_tudo.sql

⚠️ Se encontrar erro "Database error saving new user":

Execute imediatamente:

sql/FIX_URGENTE_profile_trigger.sql

Passo 3: Clonar e Configurar Frontend

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

VITE_SUPABASE_URL=https://api.seudominio.com.br
VITE_SUPABASE_ANON_KEY=sua_chave_aqui

Passo 4: Build e Deploy

Desenvolvimento Local

npm run dev

Build para Produção

npm run build

Deploy no Apache

# Copiar build para Apache
sudo cp -r dist/* /var/www/html/evolua/

# Configurar VirtualHost
sudo nano /etc/apache2/sites-available/evolua.conf

evolua.conf:

<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>
# Ativar site
sudo a2ensite evolua
sudo a2enmod rewrite
sudo systemctl reload apache2

Passo 5: Configurar N8N (Opcional)

# 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

-- No Supabase SQL Editor
-- 1. Registrar usuário via interface
-- 2. Promover para admin:
UPDATE profiles 
SET categoria = 'admin' 
WHERE email = 'seu@email.com';

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:

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

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

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

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:
// No console do navegador
const { data, error } = await supabase
  .from('profiles')
  .select('*')
  .limit(1);
console.log(data, error);

2. Limpar cache e storage:

3. Limpar cache e storage:

localStorage.clear();
sessionStorage.clear();
location.reload();

3. Verificar logs do AuthProvider:

4. Verificar logs do AuthProvider:

🎭 AuthProvider useEffect INICIANDO...
🎯 AuthProvider - Init simples
🔄 Auth mudou: SIGNED_IN [email]
✅ Perfil carregado
🏁 Loading finalizado

4. Se persistir, usar AuthProvider alternativo:

// 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:
VITE_SUPABASE_URL=https://...  (sem barra no final)
VITE_SUPABASE_ANON_KEY=eyJ...  (chave completa)
  1. Reiniciar servidor dev:
# 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:

-- Corrigir categoria no banco
UPDATE profiles 
SET categoria = 'aluno'  -- ou professor, admin, monitor
WHERE email = 'usuario@email.com';

Problema: Avaliações Não Aparecem

Checklist:

Verificar se usuário está na turma:

SELECT * FROM turma_membros WHERE aluno_id = 'user_id';

Verificar distribuição:

SELECT * FROM instancias_avaliacao 
WHERE aluno_id = 'user_id' 
ORDER BY created_at DESC;

Verificar RLS:

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

# Limpar cache TypeScript
rm -rf node_modules/.cache
rm -rf dist
npm run build
Vite errors
# Reinstalar dependências
rm -rf node_modules
rm package-lock.json
npm install
Memory errors
# Aumentar limite Node
NODE_OPTIONS=--max_old_space_size=4096 npm run build

Logs de Diagnóstico

Habilitar logs detalhados

// 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

// 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


📝 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

Related Documents