Skip to content

Creative-Engine ↔ Application-Frontend Integration Guide

This document explains how Creative-Engine and Application-Frontend integrate, including local development setup, block registration, and common workflows.

Full Local Development Setup

Prerequisites

  1. Pull latest version of all repositories from main branch
  2. PostgreSQL Database: Set up local PostgreSQL using Postico 2 with credentials from Backend .env:
    bash
    DB_CONNECTION=pg
    PG_HOST=localhost
    PG_PORT=5432
    PG_USER=nicolay
    PG_PASSWORD=
    PG_DB_NAME=cavai_backend

Package.json Configuration

Set file paths in package.json for local development in all three repositories (Application-Frontend, Creative-Engine, and Application-Backend):

json
{
  "dependencies": {
    "@cavai/creative-engine": "file:../Creative-Engine",
    "@cavai/creative-composer": "file:../Creative-Composer"
  }
}

Important: These local file paths must be set in dependencies for all three repos to ensure correct parsing through the Composer.

Quick Setup with Git Stash

Create a named stash for local development paths:

bash
git stash push -m "local-dev-paths" package.json package-lock.json

Apply local development paths when needed:

bash
git stash apply stash^{/local-dev-paths}

Reset to normal package versions:

bash
git checkout package.json package-lock.json

Git Aliases for Quick Switching

Create aliases (one-time setup):

bash
git config --global alias.local-dev '!git stash apply stash^{/local-dev-paths}'
git config --global alias.reset-deps '!git checkout package.json package-lock.json'

Quick switching:

bash
git local-dev    # Activate local paths
git reset-deps   # Reset to normal package versions

Startup Sequence

After setting up local package paths:

  1. Install Creative-Composer locally in Creative-Engine and Application-Frontend:

    bash
    npm i ../Creative-Composer
  2. Start Creative-Engine with hot reload:

    bash
    npm run watch
  3. Start Application-Backend:

    bash
    npm run dev
  4. Start Application-Frontend:

    bash
    npm run dev

Troubleshooting Local Development

When Application-Backend doesn't work:

bash
npx @cavai/creative-composer ci -e ../Creative-Engine

This reloads dependencies and is especially needed after publishing/deleting creatives.

Overview

  • Blocks vs Operators: Builder Visuals uses blocks (e.g., textProperties, sliderProperties, formProperties) rendered by CE and configured in AF. Conversation flow uses operators (Composer), which is separate.
  • Glue: CC compresses/remaps creative data and produces build artifacts consumed by AB (stub.js, creative-engine.js). AF is the authoring UI; CE is the renderer.
  1. Reload Composer deps when Backend acts up
    • From Application-Backend/: npx @cavai/creative-composer ci -e ../Creative-Engine
    • This refreshes CC’s view of CE after changes or creative deletions.

Implementing/Updating Blocks

To add or change blocks, you must touch both AF and CE.

  1. Register Block Types

    • AF: src/pages/Chatbots/components/BuilderVisuals/constants/blocks.ts
    • CE: src/utils/constants.ts (include in BLOCKS)
  2. Visual Elements vs Specialized Blocks

    • Visual Elements (Text/Graphic/HTML/Button): rendered via CreativeVisualElements.vue and must be in VISUAL_ELEMENTS.
    • Specialized Blocks (Video/Slider/Conversation/Form): dedicated CE components imported in CreativeBody.vue; do NOT add to VISUAL_ELEMENTS.
  3. AF Tasks

    • Defaults: Blocks/data/defaults.ts
    • Types: Blocks/data/types.ts
    • Config UI: Configuration/configs/<Block>Configuration.vue
    • Add option in AddBlockTool.vue
    • i18n entries in assets/i18n/en.js
  4. CE Tasks

    • Interfaces: src/payload-v2/index.ts and update CreativeBlocks interface
    • Rendering component: e.g., src/components/creative/Creative<YourBlock>/...
    • For specialized blocks: subblock handling via utils (see below)
    • Build CE after changes: npm run build:library
  5. Subblock Handling Pattern

    • Create a utility in CE (e.g., blockUtils.ts) to extract subblocks from the parent block and sort by order (e.g., getFormInputBlocks, similar to slider).
    • Ensure subblocks have: blockName, blockType, parent, order, displayName, isSubBlock: true.
    • For duplication/uniqueness, mirror slider’s approach to avoid name collisions.

Build Pipeline and Artifacts

CC drives builds; AB stores outputs.

  • Artifacts locationApplication-Backend/tmp/creatives/assets/creatives/[creative-id]/

    • built/assets/creative-engine.js — entire CE bundle
    • built/assets/stub.js — main compiled creative entry
    • creative.json — full creative data
    • log.txt — composer build logs
    • tag.html — embedding tag
  • Debugging order

    1. Inspect creative-engine.js (components registered?)
    2. Inspect stub.js
    3. Read log.txt for CC messages
    4. Check creative.json structure
    5. Verify tag.html

Common Pitfalls

  • Forgetting CE build: After CE code changes, run npm run build:library before testing in AF/AB.
  • Incorrect block registration: Missing entries in AF/CE block constants cause invisible/non-rendered blocks.
  • Wrong blockName: Visual elements’ blockName must contain a VISUAL_ELEMENTS string; specialized blocks use static keys (e.g., formProperties).
  • Missing i18n: Hardcoded strings — ensure everything goes into en.js.
  • Composer cache/staleness: If AB builds don’t reflect changes, run npx @cavai/creative-composer ci -e ../Creative-Engine from AB.

Workflow Cheatsheet

  1. Implement/modify block in AF and CE
  2. Build CE: npm run build:library
  3. In CC/AB environment, refresh deps: npx @cavai/creative-composer ci -e ../Creative-Engine
  4. Publish creative and verify artifacts in AB tmp/creatives/...
  5. If issues, diff structure against a working block (e.g., slider) and check subblock utilities

Troubleshooting

  • Preview mismatch (local vs full): Validate that all style properties exist and are applied consistently; compare to slider rendering.
  • Serialization errors: Ensure subblock uniqueness and proper references (avoid duplicate definitions; store references by blockName arrays when appropriate).
  • Missing context menu options: Add block type to isDeletable in AF utils.ts.
  • Backend not updating: Clear old creative under AB tmp/creatives/... and republish if needed.

Preview fails due to component <style> blocks (scoped)

  • Symptom: Published preview fails to render the Form block; inspecting shows selectors like form-block-wrap[... (Vue adds attribute selectors for scoped styles).
  • Cause: A <style> (especially with scoped) at the bottom of a CE component (e.g., CreativeFormBlock.vue) conflicted with the engine’s injected CSS. CE already injects CSS via StyleAndClassNameGenerationMixin; an extra <style> can override or break selectors in the built preview.
  • Fix: Remove the component <style> block (or at least remove scoped and conflicting rules). Prefer relying on the mixin-injected CSS from styles.
  • Debug path used:
    1. Saw selector with [ in DevTools (Vue scoped attribute).
    2. Removed scoped → same issue.
    3. Removed the entire <style> block → preview started working.

Real-time Updates Limitation

Architecture Issue

Application-Frontend and Creative-Engine run in separate contexts:

  • Application-Frontend: Main window with Vue/Vuex store
  • Creative-Engine: Runs inside iframe with isolated DataStore

Current Behavior

  • Configuration changes in Application-Frontend are saved correctly
  • Changes don't reflect in real-time in Creative-Engine preview
  • Preview updates require iframe reload or creative republish

Root Cause

Creative-Engine's DataStore.creativeSettings is isolated from Application-Frontend's Vuex store. The iframe boundary prevents automatic reactivity between the two systems.

Communication Methods

Data passes between contexts via:

  • postMessage API (seen in PreviewIframe.vue)
  • iframe src URL parameters
  • Creative republishing process

Workaround

For immediate preview updates, manually reload the preview iframe or republish the creative. Configuration changes are always saved correctly in the backend.

Future Solution

Implementing real-time cross-iframe communication would require:

  1. postMessage listeners in Creative-Engine
  2. Change detection in Application-Frontend
  3. Selective data synchronization mechanism

Reference Files

  • AF: AddBlockTool.vue, CreativeBody.vue, CreativeVisualElements.vue, Blocks/data/defaults.ts, Blocks/data/types.ts, assets/i18n/en.js
  • CE: src/components/creative/**, src/utils/constants.ts, src/payload-v2/index.ts, blockUtils.ts
  • CC: src/bin/composer.ts (debug entry), src/remapper/*
  • AB: tmp/creatives/assets/creatives/[id]/*

Internal documentation