El modelo de datos
Crear la base de datos de la app, las tres tablas del CRM y el modelo con las relaciones que el resto de la plataforma va a usar.
La app Gestión de Clientes existe y está vacía. Esta etapa le da el
cimiento: la base de datos donde viven los registros, las tablas contas,
contactos y oportunidades, y el modelo que lo conecta todo — el
mapa que las APIs, las pantallas y los scripts van a leer de aquí en
adelante.
Al final de esta página tienes datos de verdad: tres tablas creadas, conectadas entre sí, y una consola donde las consultas devuelven filas.
Dos capas, y conviene no confundirlas
Keplin trabaja con datos en dos capas superpuestas. Hacen cosas distintas y se tocan en sitios distintos:
| Capa | Qué es | Dónde se toca |
|---|---|---|
| Datasource | La base de datos en sí — la conexión, las tablas, las columnas, las filas. | Panel Datos ▸ Fuentes de datos |
| Modelo | El retrato de esa base de datos dentro de la plataforma: entidades, campos con nombres amigables y relaciones. | La pestaña del datasource, en el canvas del modelo |
La distinción es práctica. Crear una columna toca la base de datos. Importar una tabla al modelo no toca nada en la base de datos — solo le dice a la plataforma «esta tabla me interesa, y así es como se lee». Es el modelo el que alimenta la API GraphQL de la app, las APIs de tabla y, a través de ellas, las pantallas.
Nota
En esta guía la base de datos se crea desde cero, dentro de la app. Si tu organización ya tiene una base de datos con los clientes dentro, el camino es el mismo a partir del paso «Importar las tablas al modelo» — registra la conexión e importa las tablas que existen. El capítulo Conectar bases de datos trata ese caso.
Crear el datasource Dados CRM
El primer paso es registrar la base de datos de la app. Como no vamos a conectar nada externo, usamos el tipo que la plataforma crea y guarda con la propia app: no pide servidor, puerto, usuario ni contraseña.
En el espacio de trabajo de la app, elige el panel Datos en la base de la barra lateral.
En la sección Fuentes de datos, haz clic en el botón + (Nuevo datasource). Se abre el diálogo Nuevo datasource — «Conecta una base de datos a esta app. Todo se cifra en reposo.»
En Nombre interno, escribe
Dados CRM. Por este nombre — exactamente este — las APIs y los scripts se van a referir a la conexión más adelante en la guía.Abre la lista Tipo. Muestra todos los motores soportados; elige el de la base de datos local, la que se guarda con la app. Fíjate en lo que pasa a continuación: los campos de servidor, puerto, usuario y contraseña desaparecen — no hay nada que conectar.

La lista de tipos de base de datos en el diálogo Nuevo datasource: los seis motores soportados. Queda un campo, Importar base de datos (opcional). Déjalo vacío: «Sin archivo, se crea una base de datos vacía.» Es lo que queremos.
Haz clic en Probar conexión para confirmar — la respuesta es Conexión OK.
Haz clic en Crear. El datasource aparece en el árbol y su pestaña se abre enseguida, con el canvas del modelo — aún vacío.

Atención
El Nombre interno es un identificador, no una etiqueta. Cambiarlo
más tarde obliga a revisar los scripts que llaman a db("Dados CRM") y
los pasos SQL que eligieron la conexión por el nombre antiguo.
Crear la tabla contas
Con el datasource creado, las tablas se hacen sin salir de la plataforma.
- En el árbol, abre el menú ⋯ del datasource Dados CRM y elige Nueva tabla.
- En Nombre de la tabla, escribe
contas. Deja Schema (opcional) en blanco. - En Descripción de la tabla, escribe
Empresas clientes y clientes potenciales. Es opcional, pero es lo que vas a leer dentro de un año. - La lista COLUMNAS ya trae una columna
id, de tipointeger, con Clave primaria (PK) y Autoincremento activados. Déjala como está — es la identidad de cada registro. - Haz clic en el + de COLUMNAS para cada columna nueva y rellena Nombre, Tipo y los interruptores. La tabla de abajo dice qué escribir.
- Confirma en Crear tabla. La tabla nace en la base de datos y pasa a aparecer en el árbol de objetos.

Las columnas de la tabla contas:
| Columna | Tipo | Permite NULL | Para qué sirve |
|---|---|---|---|
id |
integer |
no | Clave primaria, con autoincremento |
nome |
text |
no | El nombre de la empresa |
nif |
text |
sí | Número de identificación fiscal |
sector |
text |
sí | Agroalimentario, Tecnología, Salud… |
cidade |
text |
sí | Dónde está la empresa |
telefone |
text |
sí | Contacto general |
email |
text |
sí | Contacto general |
estado |
text |
no | ativo, prospeto o inativo |
Consejo
Permite NULL desactivado significa obligatorio en la base de datos. Resérvalo para lo que es obligatorio de verdad — el nombre de una empresa, la cuenta a la que pertenece un contacto. Un campo que hoy es opcional y mañana obligatorio se cambia en un instante; lo contrario obliga a limpiar datos.
Crear las tablas contactos y oportunidades
Repite el gesto — menú ⋯ del datasource ▸ Nueva tabla — dos veces más.
contactos (descripción: Personas de contacto de cada cuenta):
| Columna | Tipo | Permite NULL | Para qué sirve |
|---|---|---|---|
id |
integer |
no | Clave primaria, con autoincremento |
nome |
text |
no | Nombre de la persona |
cargo |
text |
sí | Director General, Responsable de Compras… |
email |
text |
sí | |
telefone |
text |
sí | |
conta_id |
integer |
no | La cuenta a la que pertenece la persona |
oportunidades (descripción: Negocios en curso, por fase):
| Columna | Tipo | Permite NULL | Para qué sirve |
|---|---|---|---|
id |
integer |
no | Clave primaria, con autoincremento |
titulo |
text |
no | El nombre del negocio |
conta_id |
integer |
no | La cuenta del negocio |
valor |
real |
sí | Valor en euros — número con decimales |
fase |
text |
no | La fase del negocio (ver abajo) |
data_fecho |
text |
sí | Fecha prevista de cierre, en AAAA-MM-DD |
responsavel |
text |
sí | Quién acompaña el negocio |
La columna fase es una lista cerrada de valores. Se guarda como
texto, y los valores posibles son siempre estos seis:
| Valor guardado | Qué significa |
|---|---|
prospecao |
Aún no hubo conversación en serio |
qualificacao |
Hay interés y estamos entendiendo el encaje |
proposta |
Propuesta entregada |
negociacao |
Discutiendo condiciones |
fechada_ganha |
Negocio cerrado |
fechada_perdida |
Negocio perdido |
Nota
Guardamos el valor «técnico» (fechada_ganha) y mostramos la etiqueta
bonita («Ganada») en pantalla. Esa separación es la que hace funcionar
el tablero kanban de la etapa siguiente: cada columna del tablero es
uno de estos valores, con su etiqueta y su color. Las columnas estado
(de las cuentas) y fase siguen la misma idea.
Revisar y cambiar la estructura de una tabla
Te equivocaste en un tipo, faltó una columna, el nombre no es el mejor. Nada de eso es definitivo:
- En el árbol, abre el menú ⋯ de la tabla y elige Editar estructura.
- El diálogo tiene dos pestañas: Columnas e Índices. Arriba quedan el Nombre en la BD, el Nombre amigable (apps) — el nombre que las pantallas van a mostrar — y la descripción.
- Haz clic en una columna a la izquierda para editarla a la derecha, o usa el + para añadir. Las columnas nuevas quedan marcadas «Columna nueva — se crea al aplicar los cambios»; las columnas eliminadas quedan «Marcada para eliminar (DROP) al aplicar», y la eliminación se anula mientras no apliques.
- Haz clic en Aplicar cambios.

Atención
Eliminar una columna elimina sus datos. La plataforma solo ejecuta el cambio cuando pulsas Aplicar cambios — hasta entonces todo es borrador, y cerrar el diálogo no estropea nada.
Ver y sembrar los datos
El árbol de objetos tiene una consola bajo el modelo, y por ella se espían (o se siembran) los datos:
- Abre el menú ⋯ de una tabla y elige Ver datos. La Consola
SQL se abre abajo, ya con un
selectlisto para esa tabla. - Haz clic en Ejecutar. Los resultados aparecen a la derecha, con el número de filas y un campo Filtrar….
- Para meter las primeras filas, escribe los
insertque quieras en la consola y ejecuta. Es la forma más rápida de tener datos de ejemplo antes de que haya pantallas para crearlos.

Importar las tablas al modelo
Las tablas existen, pero la plataforma aún no sabe que las quiere usar. Eso es lo que hace la importación:
- En el árbol, expande Dados CRM ▸ Tablas. Ahí están las tres.
- Para cada una, abre el menú ⋯ y elige Importar al modelo — o arrastra la tabla del árbol al canvas del modelo, que es lo mismo.
- Cada tabla se convierte en una tarjeta en el canvas: la entidad. La tarjeta muestra los campos, el tipo de cada uno y la marca PK en la clave primaria.

Los nombres de las entidades quedan con mayúscula inicial — contas se
convierte en Contas — porque así es como aparecen en las APIs y en
las pantallas. La tabla en la base de datos sigue llamándose contas.
Nota
Importar no copia datos ni crea nada en la base de datos. Y quitar una entidad del modelo tampoco elimina la tabla — «NO altera la tabla en la base de datos», como dice el propio aviso.
Conectar las entidades — las dos relaciones
Un CRM sin relaciones son tres listas sueltas. Faltan dos conexiones: cada contacto pertenece a una cuenta, cada oportunidad pertenece a una cuenta.
Para crear una relación, arrastra el campo conta_id de la entidad
Contactos al campo id de la entidad Contas — la pista en la
tarjeta lo recuerda: «Arrastra a un campo de otra tabla para
conectar». Se abre el diálogo Nueva relación, ya con las entidades y
las columnas rellenadas:
| Campo | Qué elegir | Por qué |
|---|---|---|
| Cardinalidad | One-to-many (1:N) | Una cuenta tiene muchos contactos; cada contacto tiene una cuenta. |
| Parent (referenciada) | Contas ▸ id |
El lado «uno». |
| Child (tiene la FK) | Contactos ▸ conta_id |
El lado «muchos» — es el que guarda la referencia. |
| Tipo de relación | Física — crea la FK en la base de datos | La base de datos pasa a garantizar que no hay contactos huérfanos. |
| Navigator en Contactos → Contas | conta |
El campo virtual que, a partir de un contacto, da su cuenta. |
| Navigator en Contas → Contactos | contactos |
El campo virtual que, a partir de una cuenta, da sus contactos. |
| Al eliminar el padre (ON DELETE) | Nada (bloquea si hay hijos) | Eliminar una cuenta con contactos pasa a ser rechazado — mejor un error que un agujero. |
Confirma en Crear relación y repite el gesto entre Oportunidades
▸ conta_id y Contas ▸ id, con el navigator inverso
oportunidades.

Los navigators son la parte que más rinde. Son campos que no existen
en la base de datos pero existen en el modelo: con ellos, una consulta de
oportunidades devuelve conta.nome sin que nadie escriba un join. Es
exactamente eso lo que la tabla del dashboard va a hacer en la etapa
siguiente, en la columna Conta.
Consejo
Física crea de verdad la clave foránea en la base de datos; Virtual — solo en el modelo de la plataforma sirve para bases de datos donde no puedes (o no quieres) tocar el esquema. En esta guía la base es nuestra, así que física.
Qué quedó desbloqueado
Con el modelo listo, la app ganó cosas gratis:
- La API GraphQL de la app ya conoce Contas, Contactos y Oportunidades, con las relaciones — ver La API GraphQL del modelo.
- Las APIs de tabla pueden ahora apuntar a una entidad y generar lectura y escritura sin una línea de SQL. Es el primer paso de la etapa siguiente.
- Las pantallas van a leer de estas APIs a través de datastores.
¿Por qué no…?
- ¿Por qué no aparece mi tabla en el árbol? El árbol de objetos se lee de la base de datos — usa Actualizar objetos en el menú ⋯ del datasource después de tocar algo fuera de la plataforma.
- ¿Por qué no consigo crear la relación? Las dos columnas tienen que
ser compatibles: una clave primaria
integerse conecta a uninteger. Si arrastraste al campo equivocado, cancela y repite — el diálogo dice que falta elegir las columnas. - ¿Por qué el campo
contano aparece en mis datos? Los navigators no son columnas: solo existen a través del modelo. Si consultas por la Consola SQL ves las columnas reales; es en las APIs y en las pantallas donde los navigators aparecen. - ¿Por qué la plataforma no me deja eliminar una cuenta? Elegiste Nada (bloquea si hay hijos) en el ON DELETE — y hay contactos u oportunidades apuntando a ella. Elimínalos primero, o cambia la regla de la relación.
El cimiento está hecho. Próxima etapa: las pantallas.