Controle de qualidade,
em produção.

Quality control,
in production.

BioQC é a versão sanitizada de um sistema de Controle de Qualidade que substituiu, depois de paridade controlada, a operação Python de um laboratório clínico brasileiro. Java/Spring Boot, React, Postgres. Em produção desde fevereiro de 2026 — com autorização do cliente para mostrar o código.

BioQC is the sanitized version of a quality control system that replaced, after parity testing, the Python operation of a Brazilian clinical lab. Java/Spring Boot, React, Postgres. In production since February 2026 — with client authorization to show the source.

§ 01 Como começou How it started

O laboratório rodava o controle de qualidade diário num app Python desktop, herdado de anos.

Uma analista por vez registrava medições em SQLite que viajava entre estações por pendrive. Relatórios saíam em Word — qualquer um podia editar depois de assinar. Rastreabilidade de reagentes vivia em planilha. Regras Westgard eram aplicadas por leitura humana de impressões.

A operação funcionava. A auditoria ISO 15189, prevista para três meses adiante, não funcionaria.

Reescrevi o sistema em Java/Spring com frontend em React. A migração foi feita em paridade controlada: código novo e velho rodando lado a lado, contra o mesmo input, por uma a duas semanas em cada módulo. Diff diário sinalizava qualquer divergência. Cutover de escrita num sábado, com o sistema antigo mantido em modo leitura. Zero downtime para a analista que entrou na segunda.

Boring tech, deployed, with tests, beats novel tech in a slide deck. — princípio de trabalho

The lab ran daily quality control on a Python desktop app, inherited over years.

One analyst at a time recorded measurements into SQLite that traveled between stations by USB stick. Reports went out as Word docs — anyone could edit them after signing. Reagent traceability lived in a spreadsheet. Westgard rules were applied by human reading of printouts.

The operation worked. The ISO 15189 audit, three months out, would not.

I rewrote the system in Java/Spring with a React frontend. Migration ran in controlled parity: new and old code running side by side, against the same input, for one to two weeks per module. A daily diff flagged any divergence. Write-side cutover on a Saturday, old system kept read-only. Zero downtime for the analyst who walked in on Monday.

Boring tech, deployed, with tests, beats novel tech in a slide deck. — working principle

§ 02 O sistema The system

Quatro engrenagens carregam o produto.

Westgard como função pura sobre janela histórica. As regras (1-2s, 1-3s, 2-2s, R-4s, 4-1s, 10x) avaliam cada nova medição contra a história recente da combinação analito × equipamento × lote × nível. Saída persistida em WestgardViolation, indexada por severidade — dashboards e relatórios consultam sem recomputar.

Cadeia de assinaturas em PDF, hash-encadeada. Cada relatório assinado guarda sha256(bytes_do_pdf) e o hash do anterior. Alterar qualquer relatório passado quebra todos os hashes seguintes. Um QR code no impresso aponta para /verify/{hash}, página pública que confirma autenticidade na hora.

Ciclo de vida do reagente como máquina de estados explícita. EM_ESPERA → ABERTO → EM_USO → FINAL_DE_USO → INATIVO, com transições mediadas em service e eventDate separado de createdAt. Um lote aberto na segunda registrado quarta tem dois timestamps que importam para a auditoria.

Trilha de auditoria primária, não opcional. Toda mutação persiste com ator, timestamp e diff antes/depois. JWT em cookie HttpOnly cross-origin com rotação de refresh; RBAC granular por permission, não por role.

Four mechanisms carry the product.

Westgard as a pure function over the historical window. The rules (1-2s, 1-3s, 2-2s, R-4s, 4-1s, 10x) evaluate each new measurement against the recent history for the combination analyte × instrument × lot × level. Output persisted in WestgardViolation, indexed by severity — dashboards and reports read without recomputing.

Hash-chained signature log on PDFs. Each signed report stores sha256(pdf_bytes) and the previous hash. Tampering with any past report breaks every downstream hash. A QR code on the printout points to /verify/{hash}, a public page that confirms authenticity on the spot.

Reagent lifecycle as an explicit state machine. EM_ESPERA → ABERTO → EM_USO → FINAL_DE_USO → INATIVO, transitions mediated in the service layer and eventDate kept separate from createdAt. A lot opened on Monday but recorded on Wednesday has two timestamps that matter for audit.

Audit trail as a primary surface, not an option. Every mutation persisted with actor, timestamp, and before/after diff. JWT in cross-origin HttpOnly cookie with refresh rotation; RBAC granular by permission, not by role.

backend
Java 21 · Spring Boot 3.3 · Spring Security · JPA · Flyway
frontend
React 18 · TypeScript · Vite · TanStack Query · Tailwind
data
PostgreSQL on Supabase
ops
Docker · Railway · Vercel · Prometheus · logstash-logback
pdf
OpenPDF · JFreeChart · ZXing
ai
Gemini (commentary, opcional)

§ 03 Números Numbers

Em produção desde fevereiro de 2026.

15 migrations Flyway shipped, nenhum rollback. 282 arquivos Java, 116 TypeScript. 406 casos de teste backend verdes — cobrindo cada regra Westgard, integridade da cadeia de assinaturas, transições do ciclo de reagente, surfaces de auth e CORS. Suite frontend em Vitest + Testing Library.

Operação multi-analista em paralelo desde o cutover. Relatórios mensais aceitos por auditores sem retorno. Rastreabilidade lote-paciente respondida em segundos pela aplicação — não pelo arquivo do laboratório.

In production since February 2026.

15 Flyway migrations shipped, zero rollbacks. 282 Java files, 116 TypeScript. 406 backend test cases green — covering every Westgard rule, signature chain integrity, reagent lifecycle transitions, auth and CORS surfaces. Frontend suite in Vitest + Testing Library.

Multi-analyst concurrent operation since cutover. Monthly reports accepted by auditors without follow-up. Lot-to-patient traceability answered in seconds by the application — no longer by the lab archive.

§ 04 Experimentar Try it

A demo é um deploy separado, com banco populado por seed fictício. Sem dados de paciente, equipe ou identidade do laboratório real. Reseed nightly.

Os dois usuários cobrem os papéis principais — admin com permissões plenas, analista com escopo de registro de medição e leitura.

The demo is a separate deployment, populated with fictitious seed data. No real patient, staff, or lab-identity information. Reseeded nightly.

The two users cover the main roles — admin with full permissions, analyst scoped to measurement entry and reading.

adminadmin@demo.bioqc.dev · Demo123!
analistaanalystanalyst@demo.bioqc.dev · Demo123!

§ 05 Sobre quem fez About the author

Sou Otávio Machado, 20, graduando em engenharia de software na PUCRS. Construo sistemas onde corretude pesa mais que velocidade — porque vão ser auditados, regulados ou pagam contas reais.

Disponível para freelance: backend Java/Spring ou Node, frontend React/TypeScript, migrações full-stack, domínios regulados (saúde clínica, finanças, compliance, ISO).

otavio100206@gmail.com — respondo em até 24h.

Otávio Machado

Porto Alegre · MMXXVI

I'm Otávio Machado, 20, software engineering student at PUCRS in Porto Alegre. I build systems where correctness weighs more than velocity — because they get audited, regulated, or pay real bills.

Available for freelance: backend Java/Spring or Node, frontend React/TypeScript, full-stack migrations, regulated domains (clinical, finance, compliance, ISO).

otavio100206@gmail.com — I respond within 24h.

Otávio Machado

Porto Alegre · MMXXVI