Tutorial · 45 min

Construye tu primera aplicación

Al final de este tutorial tendrás un pequeño CRM con tres tablas (company, contact, deal), una página de lista-y-detalle para cada una, un Business Event que sella automáticamente el updated_at del deal, y un Script Module que recalcula el valor total de oportunidades abiertas de la empresa cada vez que cambia una deal. Cada concepto de Conceptos esenciales aparece al menos una vez.

Asume que has terminado Primeros pasos y tienes un entorno Archestack abierto en otra pestaña. Tiempo total: unos 45 minutos si lees con atención, 25 si lees por encima.

Convenciones usadas aquí: los nombres de tablas y columnas son snake_case (la plataforma sugiere esta convención en el campo "Table name" de Schema Designer). Los ejemplos de código usan la API Db real, consulta Referencia -> APIs invocables desde scripts para la superficie completa.

Paso 1 - Diseña el esquema (10 min)

Abre Schema Designer y añade tres tablas.

Para cada tabla: haz clic en Add Table en la barra de herramientas, escribe el nombre en el campo "Table name" del diálogo, haz clic en Create. La nueva tabla aparece en el lienzo con una clave primaria SERIAL id autogenerada (bloqueada). El panel derecho se abre en la pestaña Columns, añade columnas adicionales desde el cuadro "Add column" con borde discontinuo en la parte inferior. Haz clic en cada columna para expandirla y ajusta los conmutadores (PK / NULL / UQ), Length y Default value.

Tabla: company

  • id · SERIAL, PK (auto)
  • name · VARCHAR(200), obligatorio
  • industry · VARCHAR(80), nullable
  • open_deal_value · DECIMAL, default 0 - se mantiene en sincronía vía el script del Paso 5
  • created_at · TIMESTAMPTZ, default now()

Tabla: contact

  • id · SERIAL, PK (auto)
  • first_name, last_name · VARCHAR(100), obligatorio
  • email · VARCHAR(200), obligatorio, UQ activado
  • company_id · INTEGER, obligatorio - clave foránea, se configura a continuación

Tabla: deal

  • id · SERIAL, PK (auto)
  • company_id · INTEGER, obligatorio - clave foránea, se configura a continuación
  • title · VARCHAR(200), obligatorio
  • stage · VARCHAR(40), obligatorio, default 'New' - valores: New, Qualified, Proposal, Won, Lost
  • amount · DECIMAL, obligatorio, default 0
  • created_at, updated_at · TIMESTAMPTZ, default now()

Claves foráneas

Las claves foráneas viven en la pestaña Relations del panel derecho. Selecciona la tabla contact, cambia a Relations, desplázate a la sección "Add relationship":

  1. FK column (on this table) = company_id
  2. Relation type = One-to-Many
  3. References -> table = company
  4. References -> column = id
  5. Haz clic en Add Relationship.

Repite para la tabla deal (su company_id -> company.id).

Lienzo de Schema Designer con varias tablas conectadas por líneas FK. La barra de herramientas superior tiene pestañas Canvas/JSON, desplegable Packages, búsqueda Find table, controles de zoom, y a la derecha: + (Add Table), Add Group, Add Text, Save, JSON/code, Deploy (cohete verde).
Cómo se ve el lienzo una vez tienes unas cuantas tablas con relaciones. La barra de herramientas (arriba) tiene pestañas Canvas / JSON, un filtro Packages, una búsqueda Find-table, controles de zoom y, a la derecha, los botones con icono + (Add Table), Add Group, Add Text, Save, JSON y el cohete verde Deploy. Las columnas FK muestran un icono de eslabón de cadena junto a su tipo, y las relaciones se renderizan como líneas de colores entre tablas. (El ejemplo mostrado usa tablas distintas a las de este tutorial, tu configuración company / contact / deal tendrá la misma forma con dos líneas FK apuntando a company.)

Despliegue

Haz clic en Deploy en la barra de herramientas de Schema Designer. Aterrizas en la página de configuración del despliegue. Cambia a la pestaña Generated SQL, deberías ver tres sentencias CREATE TABLE más las restricciones FK. Haz clic en Deploy arriba a la derecha.

Qué verás si funciona: la fila de despliegue en Database Deployments -> Overview pasa de "Executing" a "Succeeded" en unos pocos segundos. Las tres tablas aparecen en la lista de tablas de Object Browser.

Si el despliegue falla por restricciones FK: el Generated SQL emite las tablas en el orden en que se guardaron. Abre la pestaña SQL y reordena para que company se cree antes de contact y deal, luego vuelve a desplegar. O haz clic en Regenerate tras reordenar manualmente las tablas en el lienzo de Schema Designer.

Paso 2 - Compón las Business Entities (10 min)

Cada página necesita una Business Entity a la que vincularse. Abre Business Entities y haz clic en Create para cada una. Pulsa Run Preview tras cada guardado para confirmar que las columnas vuelven correctamente.

BE: company

Entity Name company, Master Table company, Label Column name. Guarda.

Haz clic en Add Join dos veces para añadir dos joins agregados:

  • Join a contact: From column company.id, To column contact.company_id. Activa Aggregate Mode. Elige la columna id, establece Aggregate Function = COUNT, nómbralo contact_count.
  • Join a deal: From column company.id, To column deal.company_id. Aggregate Mode activado. Elige la columna id, función COUNT, nómbralo open_deal_count. (Filtraremos a deals "abiertas" mediante un Business Event en el Paso 5; por ahora cuenta todas las deals.)

BE: contact

Entity Name contact, Master Table contact, Label Column email. Añade un Join a company vía contact.company_id -> company.id, expón la columna name como company_name. (No actives Aggregate Mode aquí, es un join normal.)

BE: deal

Entity Name deal, Master Table deal, Label Column title. Añade un Join a company vía deal.company_id -> company.id, expón la columna name como company_name.

Verifica: en cada BE, haz clic en Run Preview. Verás una rejilla vacía (aún sin datos) con las cabeceras de columna que definiste. Si falta la cabecera de una columna unida, probablemente olvidaste marcar la columna en el selector de columnas del join. Vuelve a abrir el join, marca la columna, guarda, vuelve a ejecutar la vista previa.

Paso 3 - Construye las páginas (10 min)

Abre Page Editor. Para cada Business Entity, haz clic en Create:

  1. Companies - Page Name Companies, Page Route /companies, Business Entity company. La pestaña Visual autogenera una lista y un formulario de detalle. En el formulario de detalle, haz clic en Add Tab dos veces para añadir las pestañas Contacts y Deals. En cada pestaña, añade una sección RelatedGrid vinculada a la BE contact / deal con el filtro de join establecido a company.id = id del registro actual.
  2. Contacts - Page Name Contacts, Page Route /contacts, Business Entity contact. El campo company_id del formulario de detalle autogenerado aparecerá como un número, cambia su Type a Select y establece el autocompletado Entity a company para que los usuarios elijan una empresa por nombre.
  3. Deals - Page Name Deals, Page Route /deals, Business Entity deal. Mismo tratamiento para company_id (Type Select, Entity company). Para stage, deja Type como Text por ahora, los valores pueden forzarse vía un evento Validate más adelante si quieres.

Para cada página, cambia el conmutador Published en la cabecera superior a ON. Las páginas aparecen en la barra lateral bajo una sección APPLICATION (agrupadas por categoría). Añade una Company, luego un Contact vinculado a esa Company, luego una Deal, confirma que las relaciones se renderizan correctamente. La página Companies debería mostrar ahora 1 en contact_count.

Página de usuario final publicada con migas de pan (Home / Customers / Record #9), un botón Edit arriba a la derecha, varias pestañas (Details, Vehicles, Address & Contact, Open service orders, Closed Service orders), un formulario Properties con lápices de edición en línea por campo, y una rejilla de datos relacionados (Vehicles) debajo del formulario.
Cómo se ve una página publicada en tiempo de ejecución. El ejemplo aquí es una página Customer de un dominio distinto (DMS), pero la forma es exactamente lo que producirá tu página company. Nota: la sección APPLICATION de la barra lateral aparece en cuanto publicas, las páginas se agrupan bajo una cabecera de categoría (aquí: CUSTOMER PORTAL). El panel de detalle renderiza migas de pan, un botón Edit (arriba a la derecha), iconos de lápiz por campo para ediciones en línea, pestañas adicionales en la parte superior (Details / Vehicles / etc.) y debajo del formulario una sección de rejilla relacionada que extrae filas de otra BE filtrada por el registro actual. La insignia de la campana ("1") muestra que hay un fallo de Event Log no leído.
Si algo se ve vacío: la causa más común es olvidar cambiar el conmutador Published, si está OFF, navegar a /companies en la barra lateral no muestra nada. Cámbialo a ON y refresca.

Paso 4 - Limpia un campo al guardar con un Business Event (5 min)

Los Business Events ejecutan un poco de lógica en cuanto se escribe un registro. El más pequeño y útil: recortar los espacios sobrantes del title de un deal en cada guardado, para que " Acme renewal " quede como "Acme renewal". Vamos a montarlo.

Nunca necesitas una regla para created_at / updated_at / created_by / updated_by. Archestack añade esas cuatro columnas de auditoría a cada tabla y las sella en cada insert y update automáticamente, así que un trigger de "sellar updated_at" solo duplicaría el trabajo que la plataforma ya hace.
  1. Abre Business Events -> Create.
  2. Rule Name: Normalize deal.title. Activa Enabled.
  3. Business Entity: deal. Triggers: marca Before Update.
  4. Sin condiciones, se dispara en cada update.
  5. Añade una acción: elige Execute Script. El cuerpo del script de la acción:
    string title = Entity.title;
    Entity.title = title?.Trim();
  6. Haz clic en la pestaña Simulate -> elige cualquier Deal existente -> haz clic en Run Simulation. El panel de salida muestra que el script se ejecutó correctamente y a qué se estableció Entity.title. (No ocurre ninguna escritura real, la simulación se ejecuta en una transacción revertida.)
  7. Guarda. Prueba editando un Deal cuyo título tenga espacios al principio o al final, el título debería volver recortado en cada guardado.
¿Por qué Before Update + Execute Script en lugar de una acción que "establezca un campo"? Archestack no tiene una acción discreta "Set field". La forma de mutar un registro desde un trigger es asignar a Entity.column_name dentro de un Execute Script en un momento Before*. La plataforma persiste el Entity modificado como parte de la escritura en curso, sin consulta extra, sin riesgo de recursión.

Paso 5 - Recalcula company.open_deal_value con un Script Module (10 min)

Un total computado como "valor de deal abierta por empresa" es demasiado dinámico para que una columna almacenada permanezca exacta a mano. Lo mantendremos en sincronía con un pequeño script que se vuelve a ejecutar cada vez que cualquier deal de una empresa se inserta, actualiza o elimina.

Escribe el script

Abre Script Modules -> Create. Nómbralo RecalcCompanyOpenDealValue.

Cambia a la pestaña Parameters. Haz clic en Add. Name company_id, Type int, Required marcado.

Vuelve a la pestaña Edit. Cuerpo:

var openDeals = await Db.From("deal")
    .Where("company_id", "=", company_id)
    .Where("stage", "!=", "Won")
    .Where("stage", "!=", "Lost")
    .ToListAsync();

decimal total = 0;
foreach (var d in openDeals) total += (decimal)(d.amount ?? 0);

await Db.UpdateAsync("company", company_id, new { open_deal_value = total });

return total;

Cambia a la pestaña Test. Escribe un company_id real de tu página Companies en el campo de parámetro, haz clic en Run. La salida muestra el valor de retorno (el total) y un indicador de éxito. Recarga la página Companies, open_deal_value en esa empresa ya está sincronizado.

Tropiezos comunes:
  • Olvidar await en .ToListAsync(), el script compila pero openDeals acaba conteniendo un Task, no las filas. El error en el panel Test mencionará "cannot be enumerated".
  • Usar Db.Query en lugar de Db.From, no existe un método Query. Cíñete a Db.From(table) para consultas encadenadas y Db.GetAsync(table, id) para una sola fila por PK.
  • Probar .SumAsync(...), no existe. Recupera + suma en C#, como arriba.

Conéctalo a un Business Event

  1. Abre Business Events -> Create.
  2. Rule Name: Recalc company.open_deal_value on deal change. Enabled activado.
  3. Business Entity: deal. Triggers: marca After Create, After Update y Before Delete.
  4. Sin condiciones, se dispara en cada cambio.
  5. Añade una acción: Execute Script. Cuerpo:
    var entity = OldEntity != null && OldEntity.company_id != null
        ? OldEntity      // for delete & update, OldEntity has the original company_id
        : Entity;        // for create, only Entity is populated
    
    await Modules.CallAsync("RecalcCompanyOpenDealValue", new Dictionary<string, object?> {
        ["company_id"] = entity.company_id
    });
  6. Guarda. Edita el amount de una Deal y recarga la página Company, el total se mantiene sincronizado.
¿Por qué llamarlo a través de Modules en lugar de inlinear la lógica en el script de este trigger? Dos razones. Primero, el recálculo es reutilizable, también puedes llamarlo desde un Scheduled Event (recuperación nocturna) o directamente desde el front-end. Segundo, aísla la lógica en un único lugar con nombre, más fácil de probar, más fácil de encontrar después.

Paso 6 - Empaquétalo como un package (5 min)

Has construido un mini-CRM real y funcional. Empaquétalo para poder moverlo a otro entorno.

  1. Abre Packages -> Create. Nómbralo MiniCRM v1.
  2. Añade las tres Pages. Abre el panel de elementos enlazados para ver la cascada: el paquete arrastrará las BEs que las páginas referencian, las tablas fuente de las que esas BEs leen, más los dos Business Events y el Script Module que las tocan.
  3. Desmarca lo que prefieras omitir, normalmente lo mantendrías todo para un tutorial como este.
  4. Haz clic en Export -> descarga el ZIP.

Importar el ZIP en un entorno distinto recrea todo (asumiendo que el esquema se ha desplegado primero). Así es como los socios envían configuraciones específicas de un vertical y como promoverías el trabajo de una prueba a un entorno de pago más adelante.

Resumen - lo que acaba de ocurrir

  • Diseñaste un esquema, lo desplegaste como tablas PostgreSQL reales y nunca escribiste SQL a mano.
  • Expusiste esas tablas a través de Business Entities, eligiendo qué exponer, uniendo etiquetas para usabilidad, agregando recuentos de filas relacionadas.
  • Compusiste tres páginas solo a partir de configuración, con pestañas embebidas y búsqueda.
  • Añadiste un comportamiento con un Business Event (auto-sellado) y un cálculo más complejo con un Script Module, ocho líneas de C# que se ejecutan cada vez que los datos cambian.
  • Empaquetaste todo como un Package, portable entre entornos.

El mismo ciclo escala a docenas de tablas y cientos de páginas. La Referencia cubre el resto de la plataforma, branding, sincronización de datos de terceros, andamiaje asistido por IA, pero la habilidad esencial es la que acabas de aprender.

Hacia dónde ir después

  • Genera facturas en PDF - añade una plantilla de factura imprimible a las Deals que acabas de construir. Mismos datos, nuevo canal de salida.
  • Scheduled Events - extiende el script de recálculo con una recuperación nocturna que se ejecute sin acción del usuario.
  • AI Builder - apúntalo a "add support for service appointments, date, customer, vehicle, status" y obsérvalo andamiar una funcionalidad similar.