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 emGET /openapi.json). - Documentação interativa:
GET /docs(Swagger UI), exceto seENABLE_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 -dIsso 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ário3. Instalar dependências e migrar
npm install
npm run migrate4. Importar questões (uma vez ou após atualizar o JSON)
npm run import:questionsPor padrão o script lê tools/extractor/data/questions.json. Use QUESTIONS_JSON_PATH para outro caminho.
5. Subir a API
npm run dev- API: http://localhost:3000
- Swagger UI: http://localhost:3000/docs
- Health: http://localhost:3000/health
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:coveragesrc/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-apiA 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).
-
Crie um projeto e conecte o repositório (a API está na raiz do repo).
-
Adicione o recurso PostgreSQL ao projeto (botão New → Database → Postgres).
-
Ligue o
DATABASE_URLao 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.
-
Build: use o
Dockerfile(vejarailway.toml) ou build Nixpacks comnpm run buildenpm start. -
Variáveis:
PORTé injetado; não fixe manualmente em produção. -
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_PATHapontando para o JSON se necessário. -
Migrações: no arranque, após o servidor passar a escutar,
runMigrations()aplica os SQL emmigrations/. -
Release command (opcional): você pode configurar no Railway
npm run migratecomo 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