Trabajo
PropioProducto propio · Firma electrónica
Signperu

Signperu

Firma electrónica de documentos PDF: el emisor arma un sobre, los firmantes firman desde un enlace con código por correo, y el PDF final se sella y se puede verificar públicamente.

Captura de Signperu
SYSTEM.md

El problema

Un contrato enviado por mensaje deja a cada parte esperando a ciegas, sin versiones ni un cierre claro, y nada impide que el archivo cambie después de firmado.

Qué construí

Construí un monolito modular (Spring Boot 4, Java 21, DDD hexagonal) con un frontend Angular 22. Los firmantes entran sin cuenta con un enlace y un código por correo; al completar, el sistema estampa las firmas, añade una página de evidencia y sella el PDF con PAdES y un sello de tiempo.

Resultado

Producto propio de acceso privado, con el ciclo completo: sobre, firma, sellado y verificación pública.

Decisiones que importaron

  1. 01

    Evidencia, no solo una imagen

    Cada firma guarda correo verificado, IP, navegador, hora, hash del PDF y la versión del consentimiento aceptado. La bitácora se encadena con hashes: alterar un registro rompe la cadena.

  2. 02

    El PDF final se prueba solo

    Se sella con PAdES B-T: firma con certificado propio más un sello de tiempo RFC 3161 de una autoridad externa, con una de respaldo. Sin sello, el sobre sigue en SELLANDO y se reintenta.

  3. 03

    El enlace no basta

    El token viaja en el fragmento de la URL, en la base solo queda su hash y hay que ingresar un código de 6 dígitos, con 5 intentos como máximo.

  4. 04

    Eventos con outbox

    Cada cambio de estado escribe sus eventos en una tabla outbox dentro de la misma transacción. Las tareas de fondo usan FOR UPDATE SKIP LOCKED y también se pueden disparar desde Cloud Scheduler.

  5. 05

    Monolito, a propósito

    Sin microservicios, Kafka ni Redis: costo sin beneficio a este volumen. Los contextos (sobres, documentos, identidad, notificaciones, auditoría) se hablan por fachadas y eventos.

  6. 06

    Pensado para Cloud Run

    Imagen Docker sin root, PDFs en un bucket privado, clave del sello en Secret Manager y Cloud Scheduler disparando las tareas de fondo.

Tecnologías

  • Java 21
  • Spring Boot 4
  • PostgreSQL
  • Angular 22
  • PDFBox
  • BouncyCastle
  • Resend
  • Cloud Run
  • Cloud Storage

Modelo C4. La línea con pulso es el recorrido principal de una solicitud.

Nivel 1 · quién usa el sistema y con qué se conecta

HTTPS · session + TOTPHTTPS · link + code1Public checkRFC 31612HTTPS · webhookStorage APIEmisorArma el sobre y lo envíaFirmanteFirma desde un enlace, sincuentaTerceroVerifica un documentoSignperuFirma electrónica conevidenciaResend[Resend]Correos y avisos de reboteAutoridad de sellode tiempo[RFC 3161]Sello externo RFC 3161Almacén de PDF[Google Cloud Storage · bucketprivado]Bucket privado conretención

Nivel 2 · las aplicaciones y almacenes que lo componen

HTTPSHTTPS ·link1HTTPSREST ·/api2HTTP · tokenenv · secretsJDBC · outbox3StorageAPIRFC 31614HTTPS · webhookEmisorArma el sobre y lo envíaFirmanteFirma desde un enlace, sincuentaTerceroVerifica un documentoAplicación web[Angular 22 · Tailwind 4 · GSAP]Panel, firma y verificaciónSecret Manager[Secret Manager]Claves y credencialesCloud Scheduler[Cloud Scheduler]Dispara las tareas de fondoAPI de Signperu[Spring Boot 4 · Java 21 · CloudRun]Monolito modular, DDDhexagonalResend[Resend]Correos y avisos de reboteBase de datos[PostgreSQL 16 · Flyway]Sobres, firmantes,auditoría y outboxAlmacén de PDF[Google Cloud Storage · bucketprivado]Bucket privado conretenciónAutoridad de sellode tiempo[RFC 3161]Sello externo RFC 3161

Nivel 3 · los componentes dentro de la API

sessionvalidates access1eventseventshandlerHTTPSACL · facade2port3RFC 31614portIdentidad[Bounded context]Argon2id, TOTP y sesionesAcceso de firma[Aggregate]Token, código y sesióncortaAuditoría[Hash chain]Bitácora encadenada porhashResend[Resend]Correos y avisos de reboteAlmacén de PDF[Google Cloud Storage · bucketprivado]Bucket privado conretenciónSobres[Bounded context]Ciclo de vida, firmantes ycamposOutbox y tareas[Outbox · SKIP LOCKED]Eventos y trabajo de fondoNotificaciones[Bounded context]Correos con reintentosDocumentos[Bounded context]Valida, estampa y sella elPDFSellador PAdES[PDFBox · BouncyCastle]Firma y sello de tiempoAutoridad de sellode tiempo[RFC 3161]Sello externo RFC 3161
  • Persona
  • Sistema
  • Contenedor
  • Base de datos
  • Externo
  • Recorrido principal
  1. 01Emisor sube el PDF
  2. 02Sobre y campos
  3. 03Enlace y código
  4. 04Firma con evidencia
  5. 05Sellado PAdES
  6. 06Verificación pública

CV

Descarga mi CV

Déjame tu correo y te envío el CV ahí. Primero verifico que el correo es tuyo con un código.