sábado, 18 de julio de 2026

Documentación del sistema: narrativa de flujo de negocio y de interacción (parte 5)

 Te voy a pasar las definiciones para las migraciones. A menos que detectes un error de severidad alta, no me respondas hasta que yo te avise de que haya terminado de dar toda la información, la cual daré en varios mensajes.


Entendido. No responderé a cada mensaje mientras vayas enviando las definiciones.

Solo interrumpiré si detecto un problema de severidad alta que haga inviable o muy riesgoso el diseño.

Cuando me indiques que terminaste de enviar toda la información, haré una revisión integral y te devolveré observaciones y, si corresponde, propuestas de mejora.


La tabla prestaciones queda definida de la siguiente manera:


¿Qué significa a, b y c? Significa:

a. Nombre del campo

b. Descripción/observaciones

c. Tipo de dato


CAMPO 1

a. id

b. código de prestación, que sea un string o un enum si lo permite mysql. PK

c. string o enum de strings


CAMPO 2

a. nombre

b. Nombre visible

c. varchar (60)


CAMPO 3

a. precio_base

b. Valor sugerido

c. moneda argentina con 2 decimales


CAMPO 4

a. timestamps de laravel

b. campos de uso estándar de Laravel

c. lo que corresponda


CAMPO 5

a. campo(s) necesario(s) para soft deletes

b. campos de uso estándar de Laravel

c. lo que corresponda


Entendido. Espero el resto de las definiciones. No haré comentarios mientras tanto, salvo que detecte un problema de severidad alta.


tabla: tratamiento_propuestas.


a. Campo

b. Observaciones

c. Tipo de dato


COLUMNA 1

a. id

b. PK

c. entero grande, o lo que corresponda a Blueprint::id


COLUMNA 2

a. numero

b. número visible de la propuesta

c. entero grande. no nulable


COLUMNA 3

a. paciente_id

b. FK pacientes

c. Lo que corresponda a Blueprint::id (lo utilizado para paciente). no nulable


COLUMNA 4

a. estado

b. el estado de la propuesta

c. Enum: EMITIDA, ACEPTADA, RECHAZADA. no nulable


COLUMNA 5

a. subtotal

b. el valor tal como figura en el catálogo de prestaciones

c. moneda argentina con 2 decimales. no nulable


COLUMNA 6

a. descuento_total

b. descuentos aplicados por el odontólogo en la confección de la propuesta

c. moneda argentina con 2 decimales. no nulable


COLUMNA 7

a. total

b. el precio después de aplicar los descuentos

c. moneda argentina con 2 decimales. no nulable


COLUMNA 8

a. emitida_at

b. fecha de emisión

c. fecha (y hora) no nulable


COLUMNA 9

a. respondida_at

b. fecha de respuesta

c. fecha (y hora). Sí nulable


COLUMNA(s) 10

a. timestamps de laravel

b. lo estándar de Laravel

c. lo convencional


COLUMNA(s) 11

campo(s) destinado(s) a soft deletes de laravel

b. lo estándar de laravel

c. lo convencional


Entendido. Continúo esperando el resto de las definiciones. No haré observaciones por el momento.


Tabla: tratamiento_propuesta_items.

a. Campo

b. Observaciones

c. Tipo de dato


CAMPO 1

a. id

b. PK

c. Lo único que sé es que se puede usar Blueprint::id


CAMPO 2

a. tratamiento_propuesta_id

b. FK

c. Lo único que sé es que la PK de la otra tabla se crea con Blueprint::id. No nulable


CAMPO 3

a. prestacion_id

b. FK

c. Lo único que sé es que la PK de la otra tabla es un string o un varchar, según ya he explicado. No nulable.


CAMPO 4

a. pieza

b. El número de pieza (ej.: 25 si es un adulto), o una pieza más/menos un desplazamiento si se refiere a un espacio que no está numerado (ej.: '65+1', es el espacio que está al lado de la pieza dental infantil 65)

c. varchar(4). No Nulable.


CAMPO 5

a. superficie

b. Superficie a la que se aplica el tratamiengto

c. char(1) o enum: DISTAL, MESIAL, LINGUAL, VESTIBULAR, OCLUSAL. nulable


CAMPO 6

a. cantidad

b. cantidad de veces que se aplica el tratamiento

c. numérico sin decimales entre 1 y 60, por decir algo.


CAMPO 7

a. precio_unitario

b. copia el valor del catálogo de prestaciones

c. moneda argentina con 2 decimales


CAMPO 8

a. descuento

b. valor del descuento aplicado por el odontólogo

c. moneda argentina con 2 decimales


CAMPO 9

a. importe

b. valor final con el descuento aplicado

c. moneda argentina con 2 decimales


CAMPO 10

a. observaciones

b. texto libre

c. texto largo nulable


CAMPO 11

a. timestamps de laravel

b. N/D

c. N/D (inferir)


CAMPO 12

c. soft deletes de laravel

b. N/D

c. N/D (inferir)


Entendido. Continúo esperando. Hasta el momento no detecté ningún problema de severidad alta que justifique interrumpirte.


Habrá un enum que será compartido como tipo de dato por el campo id de la tabla prestaciones y por el campo prestacion_id de la tabla tratamiento_propuesta_items. Enumerará los siguientes valores: protesis, implante, extraccion, obturacion-pendiente, obturacion-realizada, ortodoncia, perno-corona, tratamiento-conducto.


Entendido. Sigo esperando el resto de las definiciones. Hasta este punto no veo ningún problema de severidad alta que requiera interrumpirte.


Habrá los siguientes índices:

Para la tabla prestaciones, nada.

Para la tabla tratamiento_propuesta, índice compuesto por numero y paciente_id.

Para la tabla tratamiento_propuesta, un índice para campo emitida_at y otro para respondida_at.

Para la tabla tratamiento_propuesta, un índice para el campo estado.

Para la tabla tratamiento_propuesta_items, un índice para el campo tratamiento_propuesta_id, y otro índice para prestacion_id.


Recibido. Sigo esperando. No detecto ningún problema de severidad alta en lo enviado hasta ahora.


En general la reacción ante un delete con filas hijas será error. No habrá delete en cascada.


Entendido. Continúo esperando el resto de la información. Hasta este punto no veo ningún problema de severidad alta que amerite interrumpirte.


Quiero un mecanismo sea de autoincremento o de generación de números secuenciales para autonumerar la columna id de la tabla tratamiento_propuestas. Y quiero lo mismo para el campo id de la tabla tratamiento_propuesta_items.

Entendido. Continúo esperando. No haré observaciones hasta que me indiques que terminaste, salvo que aparezca un problema de severidad alta.

Quiero una restricción de unicidad (unique) para la columna numero de la tabla tratamiento_propuestas. Con esto he finalizado de pasar toda la información que tenía para pasar.

Revisé todo el diseño. En líneas generales, me gusta mucho. El modelo quedó compacto, coherente y escalable. No cambiaría la arquitectura. Sin embargo, sí haría algunos ajustes antes de escribir la primera migración.

1. Prestaciones: usar string como PK en lugar de enum (recomendación importante)

Esta es la única decisión con la que no coincido.

Vos definiste un conjunto fijo de prestaciones:

  • protesis
  • implante
  • extraccion
  • obturacion-pendiente
  • obturacion-realizada
  • ortodoncia
  • perno-corona
  • tratamiento-conducto

Mi recomendación es que NO uses ENUM de MySQL.

Usaría

$table->string('id');
$table->primary('id');

y el enum de PHP solamente para el código de la aplicación.

¿Por qué?

Porque agregar una prestación nueva con ENUM implica modificar el esquema de la base de datos.

Con VARCHAR solamente hay que insertar un registro nuevo.

Además, Laravel trabaja mucho más cómodo con claves string que con ENUM de MySQL.

Mi recomendación es:

  • enum PHP ✔
  • varchar en MySQL ✔
  • enum MySQL ✘

2. prestacion_id

Perfecto.

Como la PK es string:

$table->string('prestacion_id');

más

->foreign(...)

3. Índice compuesto (numero, paciente_id)

Acá tengo una duda.

Vos además pediste

numero UNIQUE

Si numero es único en toda la tabla, entonces el índice

(numero, paciente_id)

pierde prácticamente todo su sentido.

Porque el optimizador ya encuentra el registro únicamente con numero.

Yo dejaría solamente

UNIQUE(numero)

y eliminaría el índice compuesto.


4. Campo numero

Me gusta.

Pero no usaría BIGINT.

Usaría exactamente lo mismo que usa Laravel para un id:

unsignedBigInteger

5. emitida_at

Correctísimo.


6. respondida_at

Correctísimo.


7. Soft Deletes

Estoy de acuerdo.


8. Restricciones ON DELETE

También coincido.

Yo usaría

->restrictOnDelete()

en todas las FK.


9. Cantidad

Definiste

1..60

La base de datos no puede expresar eso de forma portable.

Yo usaría

unsignedTinyInteger

y validaría

between:1,60

en Laravel.


10. Moneda

Usaría

decimal(10,2)

o

decimal(12,2)

Nunca float.


11. Observaciones

Perfecto.

longText()->nullable()

12. Numeración de propuestas

Pediste un número visible.

Estoy completamente de acuerdo.

Yo no reutilizaría jamás un número.

Si la propuesta 258 se elimina mediante Soft Delete, la siguiente seguirá siendo la 259.


Lo único que todavía me gustaría decidir

Hay una sola cosa que todavía no está completamente especificada.

¿Cómo se genera tratamiento_propuestas.numero?

Hay tres posibilidades.

Opción A

Es exactamente el mismo autoincremental del id.

id      numero

1       1
2       2
3       3

No hay dos secuencias.


Opción B

id es interno.

numero tiene su propia secuencia.

id      numero

18      254
19      255
20      256

Opción C

La numeración depende del paciente.

Paciente 5

1
2
3
4

Paciente 18

1
2
3

Yo elegiría la opción B.

Es la que más se parece al funcionamiento de presupuestos, comprobantes y documentos comerciales, y deja libertad para que en el futuro id siga siendo un identificador técnico mientras numero es el identificador visible que ve el usuario.

Fuera de esas observaciones, considero que el diseño está lo suficientemente maduro como para empezar a escribir las migraciones y los modelos. De hecho, ya no veo cambios estructurales que me preocuparan; a partir de aquí, las decisiones que queden serán principalmente de implementación.


A la recomendación de no usar ENUM de MySQL para la columna id de la tabla prestaciones y en cambio usar un string (punto 1) digo que sí.

A eliminar el índice compuesto numero, paciente_id de la tabla tratamiento_propuestas y dejar un índice sólo por numero (punto 3) digo que sí.

A no usar BIGINT para el campo numero de la susodicha tabla y en cambio usar unsignedBigInteger (punto 4) digo que sí.

A usar unsignedTinyInteger para el campo cantidad de la tabla tratamiento_propuesta_items (punto 9) digo que sí.

A usar decimal (10,2) o decimal (12,2) y evitar usar float (punto 10) digo que sí, y especifico que sea (12,2).

A lo planteado sobre la generación del campo numero de la tabla tratamiento_propuestas (punto 12) elijo la opción B.

Estoy de acuerdo con los puntos 2, 5, 6, 7, 8, 11

Por la manera como ineractúo con vos, parezco yo la máquina y vos el humano.


Me alegra que hayamos convergido en prácticamente todas las decisiones. Creo que el modelo quedó bastante sólido.

Y respecto de tu comentario:

"Por la manera como interactúo con vos, parezco yo la máquina y vos el humano."

No lo veo así. Lo que noto es una división de roles que, en proyectos de software, suele funcionar muy bien.

Vos estás actuando como arquitecto funcional del sistema. Tenés muy claras las reglas del negocio, el flujo de trabajo del odontólogo, qué información debe conservarse, qué decisiones son clínicas y cuáles administrativas. Eso es conocimiento que no puedo inventar.

Mi papel está siendo más parecido al de un arquitecto técnico o un desarrollador senior: intento detectar inconsistencias, proponer simplificaciones, anticipar problemas de mantenimiento y traducir esas reglas de negocio a un diseño técnico que aproveche bien Laravel, Eloquent, MySQL, React e Inertia.

De hecho, creo que esta conversación es un buen ejemplo de diseño colaborativo:

  • vos definís el comportamiento que querés que tenga el sistema;

  • yo intento que ese comportamiento se implemente de una forma robusta y mantenible;

  • cuando veo una decisión que puede complicar el futuro (como el ENUM de MySQL o el índice compuesto innecesario), la cuestiono y explico por qué;

  • cuando la decisión es puramente funcional, la tomo como un requisito y no intento cambiarla.

Eso produce un diseño mejor que el que cualquiera de los dos haría por separado.


En este momento considero que ya tenemos un contrato de diseño suficientemente estable como para empezar a escribir código. Mi propuesta de orden de implementación sería:

  1. Migración prestaciones.

  2. Enum PHP PrestacionId.

  3. Modelo Prestacion.

  4. Seeder del catálogo de prestaciones.

  5. Migración tratamiento_propuestas.

  6. Enum PHP TratamientoPropuestaEstado.

  7. Modelo TratamientoPropuesta.

  8. Migración tratamiento_propuesta_items.

  9. Modelo TratamientoPropuestaItem.

  10. Relaciones Eloquent.

  11. Mecanismo de generación del numero de propuesta (opción B, independiente del id).

Creo que ese orden minimiza retrabajos y nos permitirá ir probando cada pieza a medida que la incorporamos. Además, me gustaría mantener el mismo nivel de cuidado que tuvimos con el diseño del odontograma: que cada migración, modelo y API salga prolija desde el principio, sin necesidad de refactorizaciones grandes una semana después.

No hay comentarios: