O sistema operativo de um grupo médico de quinze clínicas

Substituir um punhado de ferramentas desligadas por uma só plataforma: site público, reservas, registos de pacientes, logística de laboratório, inventário em vários armazéns, contabilidade fiscal, RH e relatórios de publicidade - por trás de um único admin, com isolamento por clínica e por região para nove papéis de pessoal.

13 clínicas numa só plataforma
9 papéis de pessoal, cada um com a sua vista
8 sistemas substituídos por um
0 falhas que possam bloquear uma reserva
O MEU PAPEL
A arquitetura e todo o código. Defini o modelo de dados, escrevi o backend e o front end, construí o admin e mantenho a infraestrutura onde assenta.
STACK
Django 5.2, PostgreSQL, Redis, Celery, front end renderizado no servidor, Nginx sobre Ubuntu endurecido.
A PARTE MAIS DIFÍCIL
Não as funcionalidades. Fazer com que quinze unidades partilhem um só sistema sem que nenhuma consiga ver os pacientes de outra.

A situação

Um grupo médico com quinze clínicas funcionava sobre oito coisas que não sabiam umas das outras: um site, um widget separado de marcações, um ficheiro Excel para os stocks, um segundo ficheiro para o laboratório, um programa de contabilidade, uma aplicação de assiduidade, um dashboard de publicidade e uma caixa de correio partilhada. Cada número que contava existia em pelo menos dois sítios, e onde não coincidiam ninguém sabia dizer qual era o correto.

Isto não é um problema de tecnologia. É um problema de negócio que aparece como um problema de tecnologia, e é exatamente a forma de trabalho em que sou melhor.

O que construí

Uma única plataforma Django, a servir todas as quinze localizações: o site público, as marcações, os registos dos pacientes, o CRM, a logística de laboratório, os stocks de vários armazéns, a contabilidade fiscal, os RH e o reporte sobre a despesa de publicidade. Tudo por trás de um único admin, com isolamento ao nível da clínica e da região para nove papéis de pessoal, de modo que uma rececionista numa cidade não consegue ver os pacientes de outra cidade e nem sequer tem de pensar porquê.

As funcionalidades são a parte banal. Três dos sistemas por baixo delas merecem ser descritos, porque são eles que fazem a diferença entre software que funciona no dia do lançamento e software em que ainda confias dois anos depois.

Um fluxo de consentimento que resistiria em tribunal

O consentimento médico ao abrigo do RGPD não é uma checkbox com um timestamp. O que tens de conseguir produzir, mais tarde, é exatamente o documento com que uma determinada pessoa concordou num determinado momento - não a tua versão de agora.

Por isso o fluxo gera o documento, mostra-o no ecrã, confirma a identidade com um código enviado por SMS e guarda o PDF renderizado juntamente com o texto, a língua em que foi apresentado, o endereço a partir do qual foi assinado e uma cadeia de hashes que o liga ao registo. Se alterares o modelo depois disso, muda o que o próximo paciente vê e nada do que os anteriores aceitaram.

A regra por baixo: o consentimento é dado a uma frase, não a um boolean. Se o teu sistema guarda true, guardou a coisa errada.

O stock como ledger, não como número

A maioria dos sistemas de stocks mantém uma coluna quantity em que o código escreve. Essa coluna acaba por ficar errada - um race, um retry, um clique errado, uma transferência aplicada a meio - e assim que fica errada já não tens como descobrir porquê, porque a prova foi sobrescrita pela resposta.

Aqui a quantidade não é guardada. Cada receção, transferência, consumo e correção é um lançamento imutável com sinal, e o saldo de qualquer armazém é a soma dos lançamentos que lhe tocam. As correções acrescentam o inverso em vez de editarem o histórico. Isso faz da reconciliação uma propriedade do desenho e não uma tarefa mensal, e significa que a resposta a «porque temos onze destes?» está sempre disponível e sempre completa.

Mais abaixo na página encontras uma versão funcional da ideia.

Um calendário que não pode sobrepor duas marcações

As marcações de quinze clínicas sobrepõem-se constantemente, e a receção precisa de ver um dia inteiro de uma vez, sem que duas marcações ocupem alguma vez o mesmo lugar. Este é o problema de interval scheduling: ordenas pela hora de início e depois pões cada marcação na primeira coluna cuja marcação anterior já terminou.

O que faz com que valha a pena implementá-lo bem e não por aproximação é que a versão greedy é demonstravelmente ótima - o número de colunas que produz é exatamente o maior número de marcações que se sobrepõem num único instante, ou seja, um limite inferior rígido que nenhum algoritmo consegue bater. Podes ver isso a confirmar-se na demo abaixo.

A realidade romena

Faturação, o diário de caixa e drivers para as impressoras fiscais exigidas por lei. Próteses seguidas por estafeta entre a clínica e o laboratório. Assiduidade com um pequeno cliente desktop que envia um heartbeat. Nada disto é engenharia interessante e tudo junto faz a diferença entre um sistema que as clínicas usam e um que elas contornam.

A decisão que defenderia com mais força

Todas as dependências externas da plataforma fazem fail open. Se o fornecedor de SMS estiver em baixo, se a API de publicidade estiver a limitar os pedidos ou se o serviço de faturação der timeout, a marcação conclui-se na mesma, e o trabalho que falta entra em fila e fica marcado para um humano.

A alternativa - recusar uma marcação porque um terceiro não está disponível - significa externalizar a tua receita para o uptime de outra pessoa. As proteções internas funcionam ao contrário: os rate limits, a validação e o honeypot fazem fail closed, porque aí não tens a quem deitar as culpas.

O que faria de outra maneira

Construiria a camada de reporte mais cedo. Concebi o ledger e o calendário corretamente desde o início e deixei o reporte crescer aos bocados, o que significou que os primeiros três meses de perguntas da gestão foram respondidos com consultas escritas à mão por mim. Correto, mas lento, e devia tê-lo previsto.

EXPERIMENTA · O ALGORITMO DE MARCAÇÕES

O empacotador do calendário, a correr aqui.

Esta é a rotina de interval scheduling descrita acima, no teu browser. Adiciona marcações e ele continua a usar o menor número possível de colunas sem colisões.

Isto é uma demo interativa e precisa de JavaScript ativado.

EXPERIMENTA · O LEDGER DE INVENTÁRIO

Stock derivado de movimentos com sinal.

O mesmo desenho de ledger, simplificado para três localizações. Aqui nada guarda uma quantidade - regista um movimento e vê os totais a recalcularem-se a partir do log.

Isto é uma demo interativa e precisa de JavaScript ativado.