Skip to main content
joão

2025 — Case Study

PSS Candidate Evaluation

Candidate scoring and document generation for SEDUC's simplified selection process

TypeScriptNestJSNext.jsZodclass-validatorclass-transformerdocxtemplaterPostgreSQL
01

Context

SEDUC runs Processos Seletivos Simplificados (PSS) to hire temporary teachers and staff. The system automates candidate scoring and generates the official selection .docx documents, replacing a spreadsheet-and-Word workflow that was error-prone and difficult to audit.

02

Architecture

Monorepo with three packages: Next.js web app, NestJS API, shared validation schemas.

apps/web

Next.js — evaluation entry, candidate review, document download

apps/api

NestJS REST API with hardened input validation on all endpoints

packages/shared

Zod schemas shared between frontend forms and API DTOs

03

Engineering Decisions

01

API hardening: security headers, rate limiting, strict validation

The API uses helmet to set secure HTTP headers on every response and @nestjs/throttler to rate-limit public endpoints. All incoming payloads are validated and transformed via class-validator / class-transformer before they reach the service layer — unknown properties are stripped, type coercions are explicit. A government-facing selection API has no tolerance for injection vectors or abuse on unauthenticated routes.

02

Server-side .docx generation from templates

.docx output is produced server-side using docxtemplater with pizzip. Word templates store the official document structure; the server fills in candidate data and computed scores, then streams the file. This keeps the output consistent with SEDUC's HR format requirements and avoids the layout inconsistencies that arise from client-side PDF rendering across browsers.

03

Single Zod schema as validation contract

Validation schemas live in packages/shared as Zod definitions. The frontend uses them for form validation; the API uses them as the authoritative input contract. A single source of truth means the frontend cannot accept input the API would reject, and any schema change is immediately visible in both layers during development.