Skip to content

Fix: reset anual real del ID de negocio de instancias y recordatorios

belen.varsi requested to merge pft/fix/id-negocio-varchar-overflow into master

Qué

Corrige el hallazgo #3 (Alto) de la auditoría de backend (2026-08-27):
el id de negocio de instancias y recordatorios podía exceder VARCHAR(16)
a largo plazo, porque la SEQUENCE de Postgres es global y nunca resetea
pese al formato "anual".

Por qué

Dos mitigaciones posibles: ensanchar la columna, o hacer que el contador
resetee de verdad por año. Se eligió la segunda porque es la corrección
real (el formato ya afirma ser anual) y no requiere volver a tocar el
ancho de columna nunca más — 6 dígitos por año es, para el volumen
esperado de este sistema, indefinidamente suficiente.

Cambios

  • Nueva tabla proyecto.contador_id_negocio (tipo, año, último_valor),
    reemplaza a seq_instancia/seq_recordatorio.
  • InstanciaIdGenerator/RecordatorioIdGenerator: UPSERT atómico
    (INSERT ... ON CONFLICT DO UPDATE ... RETURNING) contra esa tabla,
    en vez de nextval(). @Transactional explícito (se une a la
    transacción del caller — crear() en los services ya es transaccional).
  • id_neg_instancia/id_neg_recordatorio se quedan en VARCHAR(16)
    (sin cambios) — con reset anual real, 6 dígitos no van a agotarse.

Acción requerida en el deploy

Nada se desplegó todavía de la iteración anterior de este fix, así que
la migración a correr en Neon antes de este deploy es simplemente:

  CREATE TABLE proyecto.contador_id_negocio (                                                                                                                                                                                   
      tipo         VARCHAR(20) NOT NULL,                                                                                                                                                                                        
      anio         INT         NOT NULL,                                                                                                                                                                                        
      ultimo_valor INT         NOT NULL DEFAULT 0,                                                                                                                                                                              
      CONSTRAINT pk_contador_id_negocio PRIMARY KEY (tipo, anio)                                                                                                                                                                
  );                                                                                                                                                                                                                            
  DROP SEQUENCE IF EXISTS proyecto.seq_instancia;                                                                                                                                                                               
  DROP SEQUENCE IF EXISTS proyecto.seq_recordatorio;                                                                                                                                                                            

No hay que tocar el ancho de ninguna columna (se quedan en VARCHAR(16)
como ya estaban).

Testing

  • Compila limpio. Suite completa: 522 tests, 0 failures (516 + 6 nuevos
    entre los dos generadores).
  • Verificado contra Postgres real: dos llamadas consecutivas en el mismo
    año incrementan (1, 2); una llamada en un año distinto arranca en 1 sin
    importar el contador de otros años.

Merge request reports

Loading