API em Rust + Axum + PostgreSQL para uma plataforma gratuita de estudos para o ENEM.
O projeto é open source, sem anúncios, sem IA e sem cobrança. O conteúdo inicial é autoral e licenciado em CC BY-SA 4.0; o código é MIT.
- Cadastro e login com e-mail e senha, sem confirmação de e-mail.
- Sessão em cookie
HttpOnlycom token opaco armazenado como hash no banco. - Currículo por área, disciplina e conceito.
- Questões com cinco alternativas, tentativa, correção e explicação.
- Discussão da questão após a tentativa: comentários gerais ou por alternativa.
- Gabarito e explicação só são liberados depois de uma tentativa (endpoint protegido).
- Importador de questões oficiais do ENEM (2009–2023) via API do enem.dev, com imagens, idioma, fonte e licença.
- Separação entre conceitos e provas: o currículo expõe conceitos; o arquivo oficial é exposto em
/examse oculto da lista de disciplinas. - Estatísticas básicas do estudante e últimos estudos.
- Calendário oficial do ENEM 2026, com datas confirmadas e itens "a definir".
- Endpoint de doação Pix; a chave fica apenas em variável de ambiente do backend.
- Testes unitários e testes de integração com PostgreSQL real.
- Dockerfile e Docker Compose para execução local (Compose somente com PostgreSQL).
| Camada | Tecnologia |
|---|---|
| Linguagem | Rust 1.99, edition 2024 |
| HTTP | Axum 0.8 |
| Banco | PostgreSQL 18 |
| Acesso a dados | SQLx 0.9 |
| Senhas | Argon2id |
| Sessão | Cookie HttpOnly + token opaco com hash SHA-256 |
| Testes | cargo test + sqlx::test |
O docker-compose.yml sobe apenas o PostgreSQL. Backend e frontend rodam diretamente na máquina:
cp .env.example .env
# edite o .env e preencha PIX_KEY, se quiser habilitar a doação
docker compose up -dDepois, em outro terminal:
cargo run- API local:
http://localhost:8081(configurável emBIND_ADDR) - PostgreSQL:
localhost:5432
A porta
8080desta máquina pode estar ocupada por outro serviço. O.envde exemplo usa8081para evitar conflito; o frontend faz proxy para a porta definida noproxy.conf.json. Em produção, o container usa8080internamente.
As migrações são aplicadas automaticamente na inicialização.
Os Dockerfiles continuam no projeto para build independente das imagens de backend e frontend. O Compose não sobe esses serviços; ele é apenas o banco local.
O binário import-enem baixa as provas disponíveis na API pública do enem.dev e grava no PostgreSQL de forma idempotente. Ele cria, por área e por ano, uma disciplina “Questões oficiais” e um conceito “ENEM {ano}”.
# importa 2009–2023
cargo run --bin import-enem -- --from-year 2009 --to-year 2023
# teste rápido, sem gravar
cargo run --bin import-enem -- --from-year 2023 --to-year 2023 --limit 5 --dry-run
# um ano específico
cargo run --bin import-enem -- --from-year 2023 --to-year 2023O importador:
- usa
limit=50e paginação, respeitando o limite da API; - tenta novamente em caso de
429; - deduplica por
external_id; - atualiza a questão e recria os assets em reimportações;
- mantém
sourceelicensevisíveis na questão; - registra imagens de contexto e de alternativas em
question_assets.
Fonte e direitos: os dados são obtidos do enem.dev, que se descreve como projeto comunitário e declara os dados como públicos. O projeto mantém a atribuição e a fonte no banco. Antes de usar comercialmente ou em maior escala, confira os termos da fonte e dos direitos de textos/imagens de terceiros.
Com um PostgreSQL acessível:
DATABASE_URL=postgres://enem:enem@localhost:5432/enem cargo testO sqlx::test cria bancos temporários e aplica as migrações. Os testes cobrem:
- cadastro, login, sessão, logout e e-mail duplicado;
- autorização para resposta, discussão e comentário;
- correção de tentativa sem vazamento de gabarito;
- comentários e denúncias;
- calendário oficial;
- endpoint Pix;
- seed do currículo.
Verificações de qualidade:
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings| Variável | Obrigatória | Padrão | Descrição |
|---|---|---|---|
DATABASE_URL |
Sim | — | URL do PostgreSQL |
BIND_ADDR |
Não | 0.0.0.0:8080 |
Endereço da API |
CORS_ORIGIN |
Não | http://localhost:4200 |
Origem permitida no CORS |
COOKIE_SECURE |
Não | false |
Use true em produção com HTTPS |
SESSION_TTL_DAYS |
Não | 30 |
Duração da sessão |
PIX_KEY |
Não | — | Chave Pix exposta apenas pelo endpoint de doação |
A chave Pix não é embutida no frontend. O botão de apoio só a busca quando o usuário clica.
Base: /api/v1
| Método | Rota | Descrição |
|---|---|---|
GET |
/health |
Healthcheck |
POST |
/auth/register |
Cadastro com {email, password} |
POST |
/auth/login |
Login |
POST |
/auth/logout |
Encerra a sessão |
GET |
/auth/me |
Usuário da sessão |
GET |
/curriculum/areas |
Áreas, disciplinas e contagens |
GET |
/curriculum/subjects/{id}/concepts |
Conceitos da disciplina |
GET |
/curriculum/concepts/{id} |
Conceito e explicação |
GET |
/questions?concept_id={id} |
Questões do conceito |
GET |
/questions/{id} |
Questão sem gabarito |
POST |
/questions/{id}/attempts |
Tentativa {selected_option} |
GET |
/questions/{id}/discussion |
Discussão (exige tentativa) |
POST |
/questions/{id}/comments |
Comentário (exige tentativa) |
POST |
/comments/{id}/report |
Denúncia de comentário |
GET |
/questions/{id}/answer |
Gabarito e explicação (exige tentativa) |
GET |
/me/stats |
Estatísticas e últimos estudos |
GET |
/exams |
Provas oficiais por área e ano |
GET |
/enem/calendar |
Calendário oficial do ENEM |
GET |
/support/pix |
Chave Pix, se configurada |
Erros seguem o formato:
{
"error": {
"code": "bad_request",
"message": "Informe um e-mail válido."
}
}src/
auth.rs # cadastro, login, sessão e extractor de usuário
calendar.rs # calendário oficial
config.rs # configuração por ambiente
curriculum.rs # áreas, disciplinas e conceitos
error.rs # erros HTTP
exams.rs # provas oficiais separadas dos conceitos
importer.rs # importação idempotente via enem.dev
questions.rs # questões, tentativas, discussão, resposta e estatísticas
support.rs # Pix
validation.rs # validação e normalização
lib.rs # router
main.rs # bootstrap
bin/import-enem.rs
migrations/
0001_initial.sql
0002_seed.sql
0003_official_questions.sql
0004_external_id_constraint.sql
tests/
api.rs
- Sem IA. Não há tutor, RAG ou geração de conteúdo em tempo real.
- Sem observabilidade externa. Apenas logs básicos de aplicação.
- Sem backups automáticos. O servidor/banco deve ter a política definida pelo operador.
- Sem painel administrativo. O conteúdo inicial é carregado por migração. A curadoria pode ser adicionada depois.
- Sem confirmação de e-mail. O cadastro é imediato, conforme definido para esta versão.
- Sem pagamentos. A doação é opcional e via Pix.
A taxonomia de trabalho, a estrutura das quatro áreas e a situação de cobertura estão em docs/curriculum.md.
Código: MIT. Conteúdo autoral de exemplo: CC BY-SA 4.0. Questões oficiais: fonte e licença registradas por item; consulte a fonte original.