Aprende un método práctico para convertir historias de usuario, entidades y flujos de trabajo en un esquema de base de datos claro, y cómo el razonamiento de IA puede ayudar a detectar huecos y reglas.

Un esquema de base de datos es el plan de cómo tu app recordará cosas. En términos prácticos, es:
Cuando el esquema coincide con el trabajo real, refleja lo que la gente realmente hace: crear, revisar, aprobar, programar, asignar, cancelar—en lugar de lo que suena ordenado en una pizarra.
Las historias de usuario y los criterios de aceptación describen necesidades reales en lenguaje llano: quién hace qué y qué significa “hecho”. Si usas eso como fuente, el esquema es menos propenso a perder detalles clave (como “debemos registrar quién aprobó el reembolso” o “una reserva puede reprogramarse varias veces”).
Empezar desde las historias también te mantiene honesto respecto al alcance. Si no está en las historias (o en el flujo de trabajo), considéralo opcional en lugar de construir silenciosamente un modelo complejo “por si acaso”.
La IA puede ayudarte a avanzar más rápido al:
La IA no puede, de forma fiable:
Trata a la IA como un asistente potente, no como el decisor.
Si quieres convertir ese asistente en impulso, una plataforma de “vibe-coding” como Koder.ai puede ayudarte a pasar de decisiones de esquema a una app funcional React + Go + PostgreSQL más rápido, manteniéndote en control del modelo, las restricciones y las migraciones.
El diseño de esquema es un ciclo: bosquejo → prueba contra historias → encontrar datos faltantes → refinar. El objetivo no es un output perfecto al primer intento; es un modelo al que puedas trazar cada historia y decir con confianza: “Sí, podemos almacenar todo lo que este flujo necesita—y podemos explicar por qué existe cada tabla”.
Antes de convertir requisitos en tablas, aclara qué estás modelando. Un buen esquema rara vez parte de una hoja en blanco—parte de trabajo concreto que la gente hace y de la evidencia que necesitarás más tarde (pantallas, salidas y casos límite).
Las historias son el titular, pero no bastan por sí solas. Reúne:
Si usas IA, estas entradas mantienen el modelo anclado. La IA puede proponer entidades y campos rápido, pero necesita artefactos reales para no inventar una estructura que no coincide con tu producto.
Los criterios de aceptación a menudo contienen las reglas de base de datos más importantes, incluso si no mencionan datos explícitamente. Busca declaraciones como:
Historias vagas (“Como usuario, puedo gestionar proyectos”) ocultan múltiples entidades y flujos. Otra brecha frecuente es olvidar casos límite como cancelaciones, reintentos, reembolsos parciales o reasignaciones.
Antes de pensar en tablas o diagramas, lee las historias y subraya los sustantivos. En redacción de requisitos, los sustantivos suelen apuntar a las “cosas” que tu sistema debe recordar—estas suelen convertirse en entidades en tu esquema.
Un modelo mental rápido: los sustantivos se vuelven entidades, mientras que los verbos indican acciones o flujos. Si una historia dice “Un manager asigna un técnico a un trabajo”, las entidades probables son manager, technician y job—y “asigna” sugiere una relación que modelarás luego.
No todo sustantivo merece su propia tabla. Un sustantivo es buen candidato a entidad cuando:
Si un sustantivo aparece solo una vez, o solo describe otra cosa (“botón rojo”, “viernes”), puede no ser una entidad.
Un error común es convertir cada detalle en una tabla. Usa esta regla empírica:
Dos ejemplos clásicos:
La IA puede acelerar el descubrimiento de entidades al escanear historias y devolver una lista inicial de sustantivos agrupados por tema (personas, ítems de trabajo, documentos, ubicaciones). Un prompt útil es: “Extrae sustantivos que representen datos que debemos almacenar, y agrupa duplicados/sinónimos.”
Trata el resultado como un punto de partida, no la respuesta final. Haz seguimientos como:
El objetivo del Paso 1 es una lista corta y limpia de entidades que puedas defender señalando las historias reales.
Una vez nombradas las entidades (como Order, Customer, Ticket), el siguiente trabajo es capturar los detalles que necesitarás más tarde. En la base de datos, esos detalles son campos (también llamados atributos): los recordatorios que tu sistema no puede permitirse olvidar.
Empieza con la historia de usuario, luego lee los criterios de aceptación como una lista de verificación de lo que debe almacenarse.
Si un requisito dice “Los usuarios pueden filtrar pedidos por fecha de entrega”, entonces delivery_date no es opcional—debe existir como campo (o derivarse de forma fiable de otros datos almacenados). Si dice “Mostrar quién aprobó la solicitud y cuándo”, probablemente necesites approved_by y approved_at.
Una prueba práctica: ¿Alguien necesitará esto para mostrar, buscar, ordenar, auditar o calcular algo? Si la respuesta es sí, probablemente pertenece como campo.
Muchas historias incluyen palabras como “estado”, “tipo” o “prioridad”. Trátalas como vocabularios controlados—un conjunto limitado de valores permitidos.
Si el conjunto es pequeño y estable, un campo estilo enum puede funcionar. Si puede crecer, necesita etiquetas o permisos (p. ej., categorías administradas por admin), usa una tabla de consulta separada (p. ej., status_codes) y guarda una referencia.
Así las historias se convierten en campos en los que puedes confiar—buscables, reportables y difíciles de ingresar mal.
Una vez listadas las entidades (User, Order, Invoice, Comment, etc.) y bosquejados sus campos, el siguiente paso es conectarlas. Las relaciones son la capa de “cómo interactúan estas cosas” implícita en tus historias.
Uno-a-uno (1:1) significa “una cosa tiene exactamente otra”.
User ↔ Profile (a menudo puedes unirlas a menos que haya razón para separarlas).Uno-a-muchos (1:N) significa “una cosa puede tener muchas de otra”. Esto es lo más común.
User → Order (almacena user_id en Order).Muchos-a-muchos (M:N) significa “muchas cosas pueden relacionarse con muchas cosas”. Esto necesita una tabla extra.
Las bases de datos no manejan bien “una lista de IDs” dentro de Order para relaciones M:N; causa problemas para buscar, actualizar e informar. En cambio, crea una tabla de unión que represente la relación en sí.
Ejemplo:
OrderProductOrderItem (tabla de unión)OrderItem típicamente incluye:
order_idproduct_idquantity, unit_price, discountFíjate cómo los detalles de la historia (“cantidad”) suelen pertenecer a la relación, no a ninguna de las entidades por separado.
Las historias también te dicen si una conexión es obligatoria o a veces ausente.
Order necesita un user_id (no debe permitirse vacío).phone puede quedar vacío.shipping_address_id puede estar vacío para pedidos digitales.Una comprobación rápida: si la historia implica que no puedes crear el registro sin el enlace, trátalo como obligatorio. Si la historia dice “puede”, “puede que” o da excepciones, trátalo como opcional.
Cuando leas una historia, reescríbela como un emparejamiento simple:
User 1:N CommentComment N:1 UserHaz esto para cada interacción en tus historias. Al final tendrás un modelo conectado que refleja cómo ocurre el trabajo—antes de abrir cualquier herramienta de diagrama ER.
Las historias dicen qué quieren las personas. Los flujos de trabajo muestran cómo se mueve el trabajo realmente, paso a paso. Traducir un flujo de trabajo a datos es una de las formas más rápidas de detectar problemas de “no guardamos esto”—antes de construir nada.
Escribe el flujo como una secuencia de acciones y cambios de estado. Por ejemplo:
Esas palabras en negrita suelen convertirse en un campo status (o una pequeña tabla de “estado”), con valores permitidos claros.
Mientras recorres cada paso, pregunta: “¿Qué necesitaríamos saber después?” Los flujos suelen revelar campos como:
submitted_at, approved_at, completed_atcreated_by, assigned_to, approved_byrejection_reason, approval_notesequence para procesos de múltiples pasosSi tu flujo incluye esperas, escalados o entregas, normalmente necesitarás al menos un timestamp y un campo de “quién lo tiene ahora”.
Algunos pasos del flujo no son solo campos—son estructuras de datos separadas:
Dale a la IA: (1) las historias y criterios de aceptación, y (2) los pasos del flujo. Pídele listar cada paso e identificar datos requeridos para cada uno (estado, actor, timestamps, salidas), luego resaltar cualquier requisito que no pueda ser soportado por los campos/tablas actuales.
En plataformas como Koder.ai, esta “verificación de huecos” es especialmente práctica porque puedes iterar rápido: ajustas supuestos del esquema, regeneras scaffolding y sigues avanzando sin un gran desvío por boilerplate manual.
Al convertir historias en tablas, no solo listas campos: decides cómo los datos permanecen identificables y consistentes a lo largo del tiempo.
Una clave primaria identifica de forma única un registro—piénsalo como la tarjeta de identidad permanente de la fila.
Por qué cada fila la necesita: las historias implican actualizaciones, referencias e historial. Si una historia dice “Soporte puede ver un pedido y emitir un reembolso”, necesitas una forma estable de apuntar al pedido—aunque el cliente cambie su correo, la dirección se edite o el estado cambie.
En la práctica, suele ser un id interno (número o UUID) que nunca cambia.
Una clave foránea es cómo una tabla apunta de forma segura a otra. Si orders.customer_id referencia customers.id, la base de datos puede hacer cumplir que cada pedido pertenece a un cliente real.
Esto coincide con historias como “Como usuario, puedo ver mis facturas.” La factura no está flotando; está adjunta a un cliente (y a menudo a un pedido o suscripción).
Las historias contienen requisitos de unicidad ocultos regularmente:
Estas reglas evitan duplicados confusos que aparecen meses después como “bugs de datos”.
Los índices aceleran búsquedas como “buscar cliente por correo” o “listar pedidos por cliente”. Empieza con índices alineados a tus consultas más comunes y reglas de unicidad.
Qué dejar para después: indexado pesado para informes raros o filtros especulativos. Registra esas necesidades en historias, valida el esquema primero y optimiza según uso real y evidencia de consultas lentas.
La normalización tiene un objetivo simple: evitar duplicados conflictivos. Si el mismo hecho puede guardarse en dos sitios, tarde o temprano discrepancias surgirán (dos ortografías, dos precios, dos direcciones “actuales”). Un esquema normalizado almacena cada hecho una vez y lo referencia.
1) Vigila grupos repetidos
Si ves patrones como “Phone1, Phone2, Phone3” o “ItemA, ItemB, ItemC”, es señal de otra tabla (p. ej., CustomerPhones, OrderItems). Los grupos repetidos complican la búsqueda, validación y escalado.
2) No copies el mismo nombre/detalle en varias tablas
Si CustomerName aparece en Orders, Invoices y Shipments, creaste múltiples fuentes de la verdad. Mantén los detalles del cliente en Customers y guarda solo customer_id en otros sitios.
3) Evita “múltiples columnas para lo mismo”
Columnas como billing_address, shipping_address, home_address pueden estar bien si realmente son conceptos distintos. Pero si modelas “muchas direcciones de distintos tipos”, usa una tabla Addresses con un campo type.
4) Separa lookup de texto libre
Si los usuarios eligen de un conjunto conocido (estado, categoría, rol), módelos consistentemente: o un enum restringido o una tabla de consulta. Esto evita “Pending” vs “pending” vs “PENDING”.
5) Comprueba que cada campo no-ID dependa de lo correcto
Un chequeo útil: en una tabla, si una columna describe algo distinto de la entidad principal de la tabla, probablemente pertenece en otra tabla. Ejemplo: Orders no debe almacenar product_price a menos que signifique “precio al momento del pedido” (un snapshot histórico).
A veces sí almacenas duplicados a propósito:
La clave es que sea intencional: documenta cuál campo es la fuente de verdad y cómo se actualizan las copias.
La IA puede señalar duplicaciones sospechosas (columnas repetidas, nombres similares, campos de “estado” inconsistentes) y sugerir divisiones en tablas. Los humanos siguen eligiendo el trade-off—simplicidad vs. flexibilidad vs. rendimiento—según el uso real del producto.
Una regla útil: almacena hechos que no puedes recrear con fiabilidad; calcula todo lo demás.
Datos almacenados son la fuente de verdad: partidas, timestamps, cambios de estado, quién hizo qué. Datos calculados se derivan de esos hechos: totales, contadores, banderas como “está atrasado” y rollups como “inventario actual”.
Si dos valores pueden calcularse a partir de los mismos hechos subyacentes, prefiere almacenar los hechos y calcular el resto. Si no, corres el riesgo de contradicciones.
Los derivados cambian cuando cambian sus entradas. Si almacenas tanto las entradas como el resultado derivado, debes mantenerlos sincronizados en cada flujo y caso límite (ediciones, reembolsos, cambios con efecto retroactivo). Un fallo y la base cuenta dos historias distintas.
Ejemplo: almacenar order_total junto con order_items. Si alguien cambia una cantidad o aplica un descuento y el total no se actualiza perfectamente, finanzas ve un número y el carrito otro.
Los flujos revelan cuándo necesitas verdad histórica, no solo “verdad actual”. Si los usuarios necesitan saber cuál fue el valor en ese momento, almacena un snapshot.
Para un pedido, puedes almacenar:
order_total capturado en el checkout (snapshot), porque impuestos, descuentos y reglas de precios cambian despuésPara inventario, “nivel de inventario” suele calcularse desde movimientos (recepciones, ventas, ajustes). Pero si necesitas trazabilidad, almacena movimientos y opcionalmente snapshots periódicos para velocidad de informe.
Para tracking de login, guarda last_login_at como hecho (timestamp de evento). “Está activo en los últimos 30 días?” se calcula.
Usemos una app de tickets de soporte conocida. Iremos de cinco historias a un ER simple (entidades + campos + relaciones), y luego lo comprobamos con un flujo.
De esos sustantivos obtenemos entidades centrales:
Antes (error común): Ticket tiene assignee_id, pero olvidamos asegurar que solo agentes puedan ser asignados.
Después: la IA lo marca y agregas una regla práctica: assignee debe ser un User con role = “agent” (implementado vía validación de aplicación o una restricción/política de base de datos, según tu stack). Esto evita “asignado a cliente” que rompe informes más tarde.
Un esquema está “listo” cuando cada historia puede responderse con datos que puedas almacenar y consultar de forma fiable. La validación más simple es tomar cada historia y preguntar: “¿Podemos responder esto desde la base de datos, de forma fiable, en todos los casos?” Si la respuesta es “quizá”, tu modelo tiene una brecha.
Reescribe cada historia como una o más preguntas de prueba—cosas que esperarías que un informe, pantalla o API pregunte. Ejemplos:
Si no puedes expresar una historia como pregunta clara, la historia no está clara. Si puedes expresarla—pero no puedes responderla con tu esquema—te falta un campo, una relación, un estado/evento o una restricción.
Crea un pequeño dataset (5–20 filas por tabla clave) que incluya casos normales y difíciles (duplicados, valores faltantes, cancelaciones). Luego “juega” las historias con esos datos. Detectarás rápidamente problemas como “no podemos saber qué dirección se usó en el momento de la compra” o “no hay dónde guardar quién aprobó el cambio”.
Pide a la IA que genere preguntas de validación por historia (incluyendo casos límite y escenarios de eliminación), y que liste los datos requeridos para responderlas. Compara esa lista con tu esquema: cualquier desajuste es una acción concreta, no una sensación vaga de que “algo está mal”.
La IA puede acelerar el modelado de datos, pero también aumenta el riesgo de filtrar información sensible o codificar suposiciones malas. Trátala como un asistente muy rápido: útil, pero necesita guardarraíles.
Comparte entradas realistas pero saneadas:
invoice_total: 129.50, status: "paid")Evita cualquier cosa que identifique personas o revele operaciones confidenciales:
Si necesitas realismo, genera muestras sintéticas que respeten formatos y rangos—nunca copies filas de producción.
Los esquemas fallan porque “todos asumieron” cosas distintas. Junto a tu ER (o en el mismo repo), guarda un breve registro de decisiones:
Esto convierte la salida de la IA en conocimiento de equipo en lugar de un artefacto puntual.
Tu esquema evolucionará con nuevas historias. Protégelo así:
Si usas una plataforma como Koder.ai, aprovecha guardarraíles como snapshots y rollback al iterar en esquemas, y exporta el código fuente cuando necesites personalización o una revisión tradicional.
Empieza con las historias y resalta los sustantivos que representan cosas que el sistema debe recordar (p. ej., Ticket, User, Category).
Promociona un sustantivo a entidad cuando:
Mantén una lista corta que puedas justificar apuntando a frases concretas de las historias.
Usa la prueba “atributo vs. entidad”:
customer.phone_number).Una pista rápida: si alguna vez necesitas “muchos de estos”, probablemente necesites otra tabla.
Trata los criterios de aceptación como una lista de verificación de almacenamiento. Si un requisito dice que debes filtrar/ordenar/mostrar/auditar algo, debes almacenarlo (o poder obtenerlo de forma fiable).
Ejemplos:
approved_by, approved_atdelivery_dateReescribe las frases de las historias como oraciones de relación:
customer_id en orders)order_items)Si la relación misma tiene datos (cantidad, precio, rol), esos datos pertenecen a la tabla de unión.
Modela M:N con una tabla de unión que almacene ambas claves foráneas más los campos específicos de la relación.
Patrón típico:
ordersproductsRecorre el flujo de trabajo paso a paso y pregunta: “¿Qué necesitaríamos para probar que esto pasó más adelante?”
Adiciones comunes:
submitted_at, closed_atEmpieza con:
id)orders.customer_id → customers.id)Luego añade índices para las búsquedas más comunes (p. ej., , , ). Deja el indexado especulativo para después, según patrones reales de consulta.
Haz una comprobación rápida de consistencia:
Phone1/Phone2, sepáralos en una tabla hija.\n- Si el mismo dato aparece en varias tablas, elige una fuente de la verdad y referencia esa tabla.\n- Si una columna describe algo que no es la entidad principal de la tabla, muévela.Desnormaliza más tarde solo con una razón clara (rendimiento, informes, snapshots de auditoría) y documenta qué es la fuente autorizada.
Almacena hechos que no puedas recrear con fiabilidad; calcula todo lo demás.
Bueno almacenar:
Bueno calcular:
Si almacenas valores derivados (como ), decide cómo se mantienen sincronizados y prueba los casos límite (reembolsos, ediciones, envíos parciales).
Usa la IA para borradores, luego verifica con tus artefactos.
Prácticos prompts:
Guardas:
emailorder_items con order_id, product_id, quantity, unit_priceEvita almacenar “una lista de IDs” en una sola columna: consultar, actualizar y aplicar integridad se vuelve doloroso.
created_by, assigned_to, closed_byrejection_reasonSi necesitas “quién cambió qué y cuándo”, añade una tabla de eventos/auditoría en lugar de sobrescribir un único campo.
emailcustomer_idstatus + created_atorder_total