Matías Fernández
← Todo el trabajo

SIDE PROJECT · MVP FUNCIONAL

PsiNota

Cómo construí un producto mobile-first y offline-first que transforma audio de consultas de salud mental en un borrador de nota clínica editable, versionado y auditable.

De un vistazo

Rol
Autor único · diseño de producto, arquitectura e ingeniería full stack
Período
2026 · REPOSITORIO PRIVADO
Equipo
Proyecto independiente · un ingeniero
Stack
React 19 · TypeScript · Express · PostgreSQL · TypeORM · OpenAI · PWA · Docker
Código y demo
Repositorio privado y sin demo pública. Este caso publica arquitectura, comportamiento y gates de calidad verificados sin exponer datos clínicos.

Límite de disclosure

Límite de disclosure

Base de la auditoríaRevisado contra el repositorio privado, sus controles automatizados y el brief técnico del proyecto. El producto se presenta como un MVP de ingeniería, no como software médico certificado ni como adopción comercial validada.

Publicado aquí

  • Flujo de producto, límites del sistema, stack, decisiones de ingeniería y manejo de fallas.
  • Estado verificado de lint, typecheck, tests y builds de producción a la fecha de revisión.
  • Límites explícitos sobre revisión humana, privacidad, preparación para beta y trabajo regulatorio.

Mantenido privado

  • Código fuente privado, credenciales, detalles de despliegue y cualquier registro clínico real o representativo.
  • Una demo pública hasta revisar seguridad, privacidad, consentimiento, retención y requisitos del mercado objetivo.

01 / Overview

PsiNota explora un problema de producto completo, no una llamada aislada a un modelo: preservar la grabación de una consulta, procesarla de forma confiable, producir un borrador estructurado y mantener al profesional en control de la nota clínica final.

02 / El problema

El problema

Una transcripción no elimina por sí sola la carga de documentación. La información relevante todavía debe estructurarse, revisarse, corregirse, finalizarse y trazarse sin perder la grabación original cuando la conectividad es inestable.

03 / Mi responsabilidad

Mi responsabilidad

  • Diseñé los estados del producto e implementé autenticación, seguimiento de consultas, grabación en el navegador, cargas reanudables, procesamiento asíncrono, revisión, versionado, finalización e historial de auditoría.
  • Construí la PWA en React y la API Express, modelé el dominio en PostgreSQL, integré transcripción y extracción estructurada y empaqueté el sistema para un despliegue pragmático con Docker Compose.
  • Definí invariantes de backend para aislamiento por usuario, versiones secuenciales, notas finalizadas inmutables, jobs persistidos, retries y cambios de estado auditables.

Restricciones

Restricciones

  • El output de AI debía seguir siendo un borrador editable y requerir aprobación explícita del profesional; no podía convertirse en una decisión clínica.
  • La grabación es el input más difícil de repetir, por lo que una conexión intermitente no podía descartarla.
  • El MVP necesitaba un despliegue de bajo costo y procesamiento recuperable sin introducir infraestructura distribuida antes de validar el producto.

04 / Arquitectura

Arquitectura

Recorrido de consulta a nota

La PWA protege la captura localmente y carga de forma directa o por chunks. La API valida identidad y ownership, crea un job persistido y transmite progreso. Un worker transaccional transcribe, extrae, renderiza, versiona y audita el borrador en PostgreSQL.

  1. 01PWA de capturaReact · IndexedDB · cola offline
  2. 02API de aplicaciónExpress · JWT · Zod · carga por chunks
  3. 03Jobs persistidosPostgreSQL · claim transaccional · heartbeat
  4. 04Borrador clínicoOpenAI · versiones · auditoría · aprobación humana

05 / Decisiones clave

Decisiones clave

01

Persistir el trabajo en vez de mantener requests abiertos

Contexto
La transcripción y la extracción pueden superar timeouts HTTP y fallar después de un progreso parcial.
Decisión
Responder 202 Accepted, persistir processing jobs y permitir que workers los reclamen con FOR UPDATE SKIP LOCKED, heartbeat, recuperación de jobs estancados y retries.
Consecuencia
La UI recibe progreso por SSE con fallback REST, mientras el trabajo interrumpido permanece observable y recuperable.
02

Hacer de la revisión humana un estado de dominio

Contexto
Un output fluido del modelo no es un documento clínico final y no debe reemplazar silenciosamente el criterio profesional.
Decisión
Crear una versión ai-render, registrar cada edición como una nueva versión y exigir una finalización explícita que bloquee cambios posteriores.
Consecuencia
El producto distingue estados generados, revisados y finalizados y puede reconstruir cómo cambió la nota.
03

Proteger la captura antes de optimizar el procesamiento

Contexto
Una carga fallida después de una consulta arriesga perder trabajo que puede ser imposible de repetir.
Decisión
Guardar audio pendiente en IndexedDB, encolarlo localmente, reanudar con Background Sync y soportar cargas por chunks en redes inestables.
Consecuencia
La conectividad se convierte en un estado recuperable del producto en vez de una razón para repetir la captura.

06 / Trade-offs

Trade-offs

Jobs en PostgreSQL antes que una cola separada

Qué habilitaEstado transaccional, menos piezas, bajo costo operativo y recuperación adecuada al volumen de un MVP.

Qué cuestaAPI y worker comparten un límite de coordinación en base de datos que deberá revisarse si crecen el throughput o los requisitos de aislamiento.

Storage en volumen local para el MVP

Qué habilitaUn producto vertical desplegable en una VPS económica con mecanismos simples de backup y restore.

Qué cuestaEl uso productivo necesita object storage cifrado, acceso firmado, borrado verificable y controles de retención específicos del mercado.

SSE con fallback REST

Qué habilitaActualizaciones simples de progreso del servidor al cliente con una vía de recuperación cuando se interrumpe el streaming.

Qué cuestaEs comunicación unidireccional y requiere reconexión y autorización cuidadosas en los límites de proxies.

07 / Modos de falla

Modos de falla

  1. El audio pendiente permanece en IndexedDB y en la cola local hasta que vuelve la conectividad en vez de desaparecer después de un request fallido.
  2. Los workers emiten heartbeat durante tareas largas; los jobs estancados se pueden detectar y reintentar en vez de quedar permanentemente en progreso.
  3. Cada consulta clínica se filtra por el userId del JWT verificado; la API nunca confía en un identificador de owner enviado por el cliente.
  4. Las notas finalizadas rechazan ediciones posteriores, mientras versiones previas y eventos de auditoría preservan la secuencia que produjo el documento final.

08 / Resultados y evidencia

Resultados y evidencia

7 / 7

tests automatizados aprobados en el gate verificado

Resultado medido · individualAbrir evidencia ↗
3

builds de producción verificados: API, app web y service worker

Resultado medido · individualAbrir evidencia ↗
202

contrato de respuesta Accepted para procesamiento asíncrono

Capacidad implementada · individualAbrir evidencia ↗
OFFLINE

recuperación local del audio implementada antes de la carga

Capacidad implementada · individualAbrir evidencia ↗

09 / Estado de entrega

Estado de entrega

  1. 01
    Entregado · Captura → nota revisada

    MVP funcional end-to-end

    Autenticación, estados de consulta, entrada de audio o texto, procesamiento asíncrono, edición, versionado, finalización e historial de auditoría.

  2. 02
    Entregado · PWA · cola offline · carga reanudable

    Flujo mobile resiliente

    IndexedDB, Background Sync, cargas directas y por chunks, progreso SSE, retries y recuperación de jobs estancados.

  3. 03
    Entregado · Lint · tipos · tests · builds

    Gate de ingeniería verificado

    Typechecks de API y web, siete tests automatizados y builds de producción de API, app web y service worker aprobados el 2026-08-25.

  4. 04
    Planeado · Seguridad · E2E · observabilidad · evidencia de producto

    Beta cerrada y endurecimiento para producción

    Threat modeling, storage cifrado de audio, borrado verificable, pruebas de restore, cobertura Playwright, métricas operativas y validación consentida con datos ficticios o desidentificados.

10 / Qué mejoraría después

Qué mejoraría después

  1. Cubrir el recorrido crítico de crear, capturar, procesar, editar y finalizar con Playwright y tests de integración sobre PostgreSQL efímero.
  2. Completar un threat model, cifrar audio en reposo, verificar el borrado por retención y ensayar el restore de backups antes de cualquier beta con datos reales.
  3. Realizar una beta pequeña y consentida y medir éxito de procesamiento, latencia mediana del borrador, tasa de edición, tiempo ahorrado, recurrencia y costo unitario sin presentar objetivos como resultados.

12 / Sigamos la conversación

Sigamos la conversación

El CV brinda el contexto completo de carrera. Para detalles sensibles de cliente, escribime y puedo conversar sobre el trabajo con el nivel de disclosure apropiado.

Escribime Abrir CV