Campaign Manager - How It Works
Part 2 of 5 - Deep technical processes for advanced users
1. Data Model
Campaign Hierarchy
erDiagram
Company ||--o{ Campaign : "owns"
Company ||--o| CompanyMicrosite : "has"
Campaign ||--o{ Phase : "contains"
Campaign ||--o{ EnvItem : "has environment"
Campaign ||--o{ CampaignLabel : "has translations"
Campaign }o--o| AIModelConfig : "default AI model"
Campaign }o--o| Application : "belongs to"
Phase ||--o{ Step : "contains"
Step ||--o{ CCItem : "has variables"
Step ||--o{ Asset : "produces"
Step }o--o| DocumentTemplate : "renders with"
CompanyMicrosite ||--o{ MicrositeUser : "SFTP users"
CC Item Types
| Type | What it does | AI? | Execution |
|---|---|---|---|
| string | Simple text value | No | Synchronous (lightweight) |
| json / xml | Structured data | No | Synchronous |
| prompt | Text generated by AI from a prompt template | AI | Async (own thread) |
| json_prompt | Structured JSON from AI with schema validation | AI | Async |
| image_prompt / dalle | Image generated by AI (DALL-E, etc.) | AI | Async |
| session_prompt | Multi-turn conversation with memory | AI | Async |
| function | JavaScript function that computes a value | No | Synchronous |
| web_scraper | Fetches content from a URL | No | Synchronous |
| asset | Generates a deployable file from a document template | No | Synchronous |
| asset_key / file_content | References an asset or file in storage | No | Synchronous |
Lightweight vs. Async Execution
Lightweight variable types (string, function, asset, web_scraper, file_content) execute synchronously in the parent thread to reduce overhead. AI-powered types (prompt, json_prompt, image_prompt, session_prompt) each get their own thread from a dynamic thread pool (up to 30 threads per campaign, 150 total).
Variable Computation States
stateDiagram-v2
[*] --> Created : variable added
Created --> WaitingComputation : computation queued
WaitingComputation --> Processing : engine picks it up
Processing --> Computed : success
Processing --> Error : failed
Error --> Created : reset for retry
Computed --> Created : reset for recomputation
Environment Variable Types
Campaign-level variables that serve as shared configuration across all steps:
| Type | Purpose |
|---|---|
| string | Simple configuration value |
| json / xml | Structured configuration data |
| prompt | Prompt template with placeholders (e.g., Write a headline for {product} targeting {audience}) |
| function | JavaScript function available to all steps |
| js_lib | JavaScript library code loaded before any function execution |
Gotcha: Environment variables are campaign-scoped
They belong to a single campaign, not shared across campaigns. To reuse prompt templates across campaigns, include them in your campaign template before publishing, or use export/import.
Document Template Types and Engines
| State | Meaning |
|---|---|
| Draft | Editable, not available for use in campaigns |
| System | Built-in template, cannot be edited |
| Published | Available for assignment to campaign steps |
Template Rendering Pipeline
- The system loads the template assigned to the step
- It collects context: all CC items in the current step + computed items from previous steps
- Templates are matched to steps by class tags - template classes must match step classes
- Key coverage is calculated: how many of the template's required keys are available in the step data
- The template engine (XSL, FreeMarker, or static) renders the final output
Tip: Template Package Import
You can import an HTML template as a ZIP package. The system extracts the HTML, automatically converts it to XSLT format, and stores related resources (images, CSS) in template storage. This is the "HTML-to-XSLT conversion" feature.
Engine Core - separate document
The Computation Engine, Override & Precedence System, and Scripting Engine are documented in detail in Engine Core.
2. Import, Export & Migration
ZIP Package Format
Campaigns can be exported as ZIP files containing:
campaign.json- campaign metadataphase.json- phase datastep.json- step data with CC itemsstorage/- phase-level asset filesstepStorage/- step-level asset files
Import levels: entire campaign, single phase into existing campaign, or single step into existing phase. On import, if a campaign name conflicts, it's auto-prefixed with a timestamp: [Imported 1234567890] Name.
Git/MCT Integration (Smart Merge)
Campaign templates can be synchronized with Git repositories:
- Push to Git - exports campaign structure as directory tree:
/phase_name/step_name/with JSON files - Pull from Git - imports and smart-merges: detects renamed phases by checking both name and sequence, creates new items, updates existing ones
- New Branch - creates a Git branch for the campaign template
Smart Merge on Git Pull
When pulling from Git, the system doesn't just overwrite. It finds phases by name first, then by sequence number. If a phase was renamed, it detects this and renames (moves) rather than creating a duplicate. Steps are matched the same way. This supports incremental template updates without data loss.
flowchart LR
MCT["Published Template
(MCT in DB)"] -->|"Git Push"| Repo["Git Repository
(directory structure)"]
Repo -->|"Git Pull"| MCT
MCT -->|"Start Campaign"| Live["Live Campaign
(independent clone)"]
Repo -->|"Branch"| V2["New version branch"]
V2 -->|"Merge + Pull"| MCT
Migration Workflow
Migration allows transferring data from a source campaign to a target campaign using a mapping file. The workflow follows four stages:
- Analyze - system matches source and target structures by name, reports unmatched items
- Map - a tab-delimited mapping file defines which source field maps to which target field
- Validate - can run in validation mode (preview without persisting)
- Execute - data transferred according to the mapping, with options to copy: state, result, overrides, patches
Reusable Migration Mappings
The CampaignMigrationMapping entity stores reusable mappings between MCT versions:
sourceMctId->targetMctId: which template versions this mapping connectsmappingContent: the actual field-level mapping rulestitle: human-readable description
This allows repeatable migrations when updating multiple campaigns from the same template update.
migration_carryover
Tip: Migration Carryover
Variables tagged with the migration_carryover class keep their target value instead of being overwritten by the source. This is useful for variables that should be manually adjusted in each new campaign rather than copied from the source.
3. Business Rules
Uniqueness Constraints
| Entity | Must be unique within | What happens on duplicate |
|---|---|---|
| Campaign name | Company | Error: "Campaign with name X already exist!" |
| Phase name | Campaign | Error: "The phase 'X' already in use. Refresh the page." |
| Step name | Phase | Error: "Step name already exists" |
| CC Item key | Step | Rejected at database level |
| Env Item key | Campaign | Rejected at database level |
Cascading Operations
| Action | Cascade effect |
|---|---|
| Delete campaign | Deletes all phases -> steps -> CC items -> i18n -> env items. Deletes storage folders. Unpublishes microsite assets. |
| Delete phase | Deletes all steps -> CC items in that phase |
| Delete step | Deletes all CC items in that step |
| Rename phase | Updates all CC item references that used the old phase name in their path |
| Rename step | Updates all CC item references that used the old step name in their path |
| Delete dictionary class | Removes the class from all steps and document templates that used it |
Sequence Management
Phases within a campaign and steps within a phase are ordered by sequence numbers. The system uses 1000-unit spacing between items. When a reorder causes a collision, all sequences in the parent are automatically rebuilt with even spacing.
Concurrency Protection
- Active computation blocking - you cannot change company, update with rebuild, or start migration while a computation is running. Error: "Computation campaign X in progress. Please try later."
- Optimistic locking - CC item updates use Hibernate optimistic locking. On deadlock, the system retries up to 5 times with 1-second backoff.
- Async rebuilds - when changing a campaign's company, asset rebuilds happen asynchronously after the transaction commits, so the UI responds immediately.
Soft Deletes
Campaigns, users, and companies use soft delete (marked as "deleted" but not physically removed). Data can be recovered by an admin.
4. Lifecycle & Status Flows
Document Template Lifecycle
| State | Meaning |
|---|---|
| Draft | Editable, not available for use in campaigns |
| System | Built-in template, cannot be edited |
| Published | Available for assignment to campaign steps |
Microsite States
stateDiagram-v2
[*] --> Initial : configured
Initial --> Created : S3 bucket + DNS provisioned
Initial --> Error : provisioning failed
Error --> Initial : retry
Created --> Created : assets deployed/updated
LLM API Key Pool States
stateDiagram-v2
[*] --> InPool : key added
InPool --> Disabled : admin disables
InPool --> TempDisabled : rate limit hit
TempDisabled --> InPool : auto-recovery (60s check)
Disabled --> InPool : admin re-enables