PrimoDev/ apps

Teorical Questions DETRAN

API serving 1,500 Brazilian driving theory exam questions

  • API
  • Self-hosted
  • Free (public GitHub repository)
  • Open source
View on GitHub

What is Teorical Questions DETRAN?

Teorical Questions DETRAN is a REST API that serves a bank of 1,500 questions from Brazil's driver's license (CNH) theory exam, extracted from the Banco Nacional de Questões PDF. It's the base for building practice tests and study apps for people getting a driver's license in Brazil.

The code is in a public GitHub repository and you run the API yourself with Node 20+ and PostgreSQL 16+ (the repo includes docker compose, a Dockerfile and Railway deploy steps).

What it does

  1. 011,500 questions with prompt, correct answer, 3 wrong answers and an explanation
  2. 024 modules covering road signs, choices and consequences, safe driving, and first aid and the environment
  3. 03Easy, intermediate or hard difficulty on every question
  4. 04Road sign code on signage questions
  5. 05Endpoints for paginated list, random question, detail and modules
  6. 06Filters by part, module, difficulty and text search
  7. 07OpenAPI 3.0 contract and Swagger UI at /docs
  8. 08Python extractor that turns the PDF into JSON, JSONL and CSV

FAQ

How many questions are in the bank?
1,500: 1,340 from the main bank and 160 from the Teste seus conhecimentos section, across 4 modules.
Where do the questions come from?
From the Banco Nacional de Questões (CNH) PDF, converted by a Python script that also outputs JSON, JSONL and CSV.
Are the questions in English?
No. The questions and the API docs are in Brazilian Portuguese, since the exam is Brazilian.
Can I get a random question for a practice test?
Yes. GET /questions/random returns a random question and accepts the same filters as the list, like module and difficulty.
How do I run it locally?
Start Postgres with docker compose up -d, copy .env.example, run npm install, npm run migrate and npm run import:questions, then npm run dev. The API runs on localhost:3000 with docs at /docs.

Guides

Documentation

README from the lucianodiisouza/teorical-questions-detran repository, refreshed on every deploy.

API REST em Node 20, Express, TypeScript e PostgreSQL para servir o banco de questões extraído em tools/extractor/data/questions.json.

  • Contrato HTTP: OpenAPI 3.0 em openapi/openapi.yaml (também servido em GET /openapi.json).
  • Documentação interativa: GET /docs (Swagger UI), exceto se ENABLE_SWAGGER=false.

Requisitos

  • Node.js >= 20
  • PostgreSQL 16+ (local ou Docker)

Banco e responsabilidades

Esta API só cria e mantém o schema de questões (migrations/questions_*.sql → tabela questions). Usuários, tokens e perfil ficam na kuaa-api (auto-quiz-api).

Mesmo Postgres para os dois serviços: use o mesmo DATABASE_URL se quiser. Cada API guarda o histórico de migrações numa tabela separada (SCHEMA_MIGRATIONS_TABLE, por defeito questions_schema_migrations aqui e schema_migrations na kuaa-api), por isso não há colisão entre ficheiros com o mesmo nome (ex.: 001_init.sql) nem entre equipas de migrações.

Se já tinha migrado antes com a tabela antiga schema_migrations, defina SCHEMA_MIGRATIONS_TABLE=schema_migrations até migrar os dados ou renomear a tabela.

Desenvolvimento local

1. Banco de dados

Na raiz do repositório:

docker compose up -d

Isso sobe Postgres em localhost:5432 com:

  • Banco autocurso (desenvolvimento)
  • Banco autocurso_test (testes de integração)

Credenciais padrão: postgres / postgres (veja docker-compose.yml).

2. Variáveis de ambiente

cp .env.example .env
# Ajuste DATABASE_URL se necessário

3. Instalar dependências e migrar

npm install
npm run migrate

4. Importar questões (uma vez ou após atualizar o JSON)

npm run import:questions

Por padrão o script lê tools/extractor/data/questions.json. Use QUESTIONS_JSON_PATH para outro caminho.

5. Subir a API

npm run dev

Scripts

Script Descrição
npm run dev Servidor com hot reload (tsx)
npm run build Compila para dist/
npm start Produção: node dist/server.js (migrações rodam na subida)
npm run migrate Executa migrações SQL em migrations/
npm run import:questions Importa/atualiza questões a partir do JSON (upsert por id)
npm test Testes (Vitest)
npm run test:coverage Testes + cobertura
npm run ci build + test:coverage
npm run lint:openapi Valida openapi/openapi.yaml (Redocly)

Endpoints principais

Método Caminho Descrição
GET /health Saúde do serviço
GET /openapi.json Especificação OpenAPI (JSON)
GET /docs Swagger UI
GET /questions Lista paginada (page, limit, parte, modulo_numero, dificuldade, q)
GET /questions/random Uma questão aleatória (filtros opcionais)
GET /questions/:id Detalhe
GET /modules Módulos com contagem de questões

Erros seguem o schema ErrorResponse no OpenAPI (error.code, error.message, error.details).

Testes

Requer Postgres com o banco autocurso_test (gerado pelo docker compose da raiz).

# Na raiz do repo
docker compose up -d

npm run test:coverage

src/test/setup-env.ts define TEST_DATABASE_URL (sobrescrevível). A suíte de integração aplica migrações e insere dados de teste.

Docker (imagem de produção)

Na raiz do repositório:

docker build -t autocurso-api .
docker run --rm -p 3000:3000 -e DATABASE_URL=postgresql://... autocurso-api

A imagem não inclui dados: use import:questions uma vez no ambiente (job manual ou release) após o primeiro deploy.

Deploy no Railway

Nome do serviço no Railway: teoretical-questions-detran (API de questões teóricas DETRAN).

  1. Crie um projeto e conecte o repositório (a API está na raiz do repo).

  2. Adicione o recurso PostgreSQL ao projeto (botão New → Database → Postgres).

  3. Ligue o DATABASE_URL ao serviço da API (passo que costuma faltar):

    • Abra o serviço da API (não só o Postgres) → Variables.
    • Add variable → Reference → selecione o serviço Postgres → escolha DATABASE_URL.
    • Sem isso os logs mostram DATABASE_URL: Required, o processo reinicia e o healthcheck falha.
  4. Build: use o Dockerfile (veja railway.toml) ou build Nixpacks com npm run build e npm start.

  5. Variáveis: PORT é injetado; não fixe manualmente em produção.

  6. Primeiro deploy: após o banco vazio, rode uma vez o import das questões, por exemplo:

    railway run --service teoretical-questions-detran npm run import:questions

    (ou job one-off no dashboard), com QUESTIONS_JSON_PATH apontando para o JSON se necessário.

  7. Migrações: no arranque, após o servidor passar a escutar, runMigrations() aplica os SQL em migrations/.

  8. Release command (opcional): você pode configurar no Railway npm run migrate como release step e remover migrações do startup no futuro para deploys mais controlados.

Estrutura

openapi/openapi.yaml     # Contrato OpenAPI
migrations/              # SQL versionado
src/
  app.ts                 # Express + rotas + Swagger
  server.ts              # Entrada + migrações + HTTP server
  config/                # Env (Zod)
  db/                    # Pool + migrações
  modules/questions/     # Rotas, serviço, repositório
  scripts/               # import-questions
  test/                  # setup Vitest
tools/extractor/         # Extração PDF → JSON (Python), opcional