Campaign Manager - Administration Guide
Part 3 of 5 - Roles, permissions, configuration, infrastructure, audit, and power-user tips
1. Roles & Permissions
Permission Model
flowchart TD
Check["Does user have permission X for company Y?"]
Check --> Super{"Super User?"}
Super -->|Yes| Allow["ALLOWED"]
Super -->|No| DenyOvr{"DENY override for this company?"}
DenyOvr -->|Yes| Block["BLOCKED"]
DenyOvr -->|No| AllowOvr{"ALLOW override for this company?"}
AllowOvr -->|Yes| Allow
AllowOvr -->|No| Group{"Permission group for this company?"}
Group -->|Has it| Allow
Group -->|No| Global{"Global permission?"}
Global -->|Has it| Allow
Global -->|No| Block
Three-tier model: (1) Permission Groups = collections of permissions assigned to users per company, (2) Overrides = individual Allow/Deny per user per company (Deny always wins), (3) Super User = flag that grants all permissions automatically.
Permission Groups
A Permission Group is a named set of permissions that can be assigned to users on a per-company basis. Think of it as a role - for example, "Campaign Editor", "Reviewer", "Admin". Users can belong to different groups in different companies, enabling fine-grained access control across the multi-tenant platform.
Permission Overrides (ALLOW / DENY)
Overrides are per-user, per-company exceptions to group-based permissions. Two types:
- ALLOW override - grants a specific permission to a user in a specific company, regardless of their group membership.
- DENY override - blocks a specific permission for a user in a specific company, even if their group grants it. DENY always wins over ALLOW.
Super User
A boolean flag on the user record. When enabled, the user has all permissions in all companies automatically. No group membership or overrides are checked - the system short-circuits to "allowed" immediately. Use sparingly - typically reserved for system administrators.
Permission Scopes
| Scope | Description | Example |
|---|---|---|
| Global | Applies across all companies the user belongs to | A global "Campaign List" permission lets the user list campaigns in every company |
| Company | Applies only within a specific company context | A company-level "Campaign Delete" permission only works for that company's campaigns |
Authentication
| Method | Session Duration | Use Case |
|---|---|---|
| OAuth2 / OIDC | 24 hours | Interactive web login |
| API Key | 5 minutes | Programmatic access (scripts, automation) |
Company Isolation (Multi-Tenancy)
Automatic Data Isolation
All database queries are automatically filtered by company context. When you're working within a company, you can only see that company's data. This is enforced at the database level via Hibernate filters - there's no way to accidentally access another company's data.
Permission Categories (170+ permissions)
Campaign & Content Operations
Campaign: List, Create, Read, Update, Delete, Clone, Archive, Publish, Unpublish, Migrate, Start, Change Company, Export, Import, Microsite Deploy
Phase: List, Create, Update, Delete, Move, Clone, Deploy, Copy, Export, Import, Show Hidden
Step: List, Create, Update, Delete, Move, Clone, Deploy, Copy, Export, Import, Show Hidden, Show Doc View, Template Preview
CC Items: List, Create, Read, Update, Delete, Clone, Rename, Override, Swap, Update State, Graph
Env Items: List, Create, Read, Update, Delete, Rename, Lookup, Export, Import
Computation: Execute, Stop
Assets, Storage & Media
Assets: List, Create, Read, Update, Delete, Approve, Deploy, Get Public AWS Link
Imaging: Enabled (AI image generation)
Storage (6 scopes: Global Public/Private, Company Public/Private, Microsite, Template): List, Upload, Copy, Read, Delete, Edit
Users, Companies & Security
Users: List, Create, Read, Update, Delete, Enable, Disable, Login As, Logout, Companies Read/Assign/Unassign
Companies: List, Create, Read, Update, Delete, Users Read/Assign/Unassign/Enable/Disable, Microsite Read/Create/Update/Delete
Permission Groups: List, Create, Read, Update, Delete, Clone
Permission Overrides: List, Create, Delete (global + company level)
AI, Chat & Collaboration
AI Model Config: List, Create, Read, Update, Delete, Set Default, Manager
Chat: List, Create, Update, Delete; Messages: List, Create, Update; Overrides: List, Create, Update, Delete
Comments: Read, Create, Modify, Approve, Delete
Document Templates: List, Create, Read, Update, Delete, Import, HTML-to-XSL
Dictionary: Search, Create, Delete
I18N: Campaign and Global labels management
Feature Toggles (permission-based)
| Feature | Permission |
|---|---|
| AI Image Generation | Imaging Enabled |
| Audit Trail | Audit Enabled |
| Customer Support Chat | Intercom Enabled |
| Beta Features | Preview Feature Enabled |
| Debug Tools | Event Debug |
2. Permission Override Precedence
The system evaluates permissions in a strict 5-layer order. Understanding this precedence is critical for managing access correctly.
flowchart TD
Check["Check permission X
for user in company Y"]
Check --> S{"Super User?"}
S -->|Yes| A["ALLOWED
(all permissions, always)"]
S -->|No| D{"DENY override
for this company?"}
D -->|Yes| B["BLOCKED
(DENY always wins)"]
D -->|No| AO{"ALLOW override
for this company?"}
AO -->|Yes| A
AO -->|No| G{"Permission group
for this company?"}
G -->|Has it| A
G -->|No| GL{"Global
permission?"}
GL -->|Has it| A
GL -->|No| B
style A fill:#F2FCF3,stroke:#00BC19
style B fill:#FFF2F2,stroke:#DC2626
| Layer | Priority | Effect | Scope |
|---|---|---|---|
| Super User | 1 (highest) | Grants ALL permissions | Global |
| DENY override | 2 | Blocks specific permission even if group allows it | Per user + company |
| ALLOW override | 3 | Grants specific permission regardless of group | Per user + company |
| Company group | 4 | Group-based permissions for this company | Per company |
| Global permissions | 5 (lowest) | Fallback if nothing matches above | System-wide |
DENY always wins over ALLOW
If a user has both a DENY override and an ALLOW override for the same permission in the same company, DENY wins. This is by design for compliance - explicit blocks cannot be overridden by group changes.
3. Configuration & Settings
Company Settings
| Setting | Where | Effect |
|---|---|---|
| Audit retention | Company -> Audit Config | By timeout, by record count, or disabled |
| Microsite | Company -> Microsite | Subdomain, HTTPS, site context, origin path |
| Logo & branding | Company -> Details | Company name, website, logo |
Campaign Settings
| Setting | Effect | Impact |
|---|---|---|
| Default AI Model | Used for prompts that don't specify a model | All prompt/chat variables without their own model use this one. If not set, falls back to system default. If no system default exists, prompt computation fails. |
| Application ID | Which Customer App configuration this campaign uses | Links campaign to a Customer App version. Controls which handlers/UI the Customer App uses. If changed, existing Customer App users may be redirected to a different version. |
| MCT ID | Git template identifier | Read-only reference to source template. Used for lineage tracking and metrics grouping. Can be cleared but not changed. |
| Microsite Context Folder | Where assets are published on the microsite | Defines the URL path prefix for assets on the microsite. Supports variable placeholders. Changing this after deployment means old URLs break. |
User Preferences (Per-User!)
| Preference | Effect | PO Concern |
|---|---|---|
| Update Downstream Dependencies = Enabled | Editing a variable auto-resets all dependents. More predictable but slower for iterative editing. | Different users may have different settings, leading to inconsistent behavior in same campaign. |
| Update Downstream Dependencies = Disabled | Editing a variable only changes that variable. Dependents keep old values until manually reset. | Users may not realize downstream values are stale. |
| Default Application ID | On login, user redirected to their preferred Customer App version. | If set to a removed app version, user may get errors on login. |
The per-user downstream preference is a hidden UX trap
Two users editing the same campaign will see different behavior depending on their personal preference. User A edits a variable and sees all dependents reset. User B edits the same variable and nothing else changes. This is a known source of confusion in team workflows.
AI Model Configuration Impact
| Setting | Business Impact |
|---|---|
| Temperature 0.0 | Deterministic output - same input always produces same output. Best for structured data. |
| Temperature 1.0+ | Creative/varied output. Each run produces different content. Best for marketing copy. |
| Max Tokens low (256) | Short outputs - may cut off mid-sentence. Cheap but risky for long content. |
| Max Tokens high (4096) | Full-length outputs. Higher cost per call but content won't be truncated. |
| RPM low (10) | Only 10 AI calls per minute per model. Large campaigns will be very slow. |
| RPM high (1000) | High throughput but may exceed provider's actual limit -> 429 errors. |
| "System Default" flag | All campaigns/chats without explicit model use this. Changing it affects ALL users immediately. |
| "Use in Chat" flag | Makes model available in chat dropdown. Disabling removes it from all chat sessions. |
Feature Flags (Permission-Based)
Feature flags in Campaign Manager are implemented as permissions, not separate toggles. To enable or disable a feature for a user, add or remove the corresponding permission from their permission group.
| Feature | Permission | Effect When Disabled |
|---|---|---|
| AI Image Generation | Imaging Enabled | Image features hidden in UI |
| Audit Trail | Audit Enabled | Audit tab not visible |
| Customer Support Chat | Intercom Enabled | Intercom widget not loaded |
| Beta Features | Preview Feature Enabled | Beta UI elements hidden |
| Debug Tools | Event Debug | Debug panel not available |
4. Infrastructure & Background Processes
File Storage Architecture
| Storage | Backend | Access | Use |
|---|---|---|---|
| Public Company | S3 bucket | World-readable URLs | Uploaded assets, generated documents |
| Private Company | S3 bucket | Authenticated users only | Sensitive generated assets |
| Microsite | S3 bucket per company | Public HTTP/HTTPS | Published assets only |
| Template | S3 bucket | Template editors | Document template resources |
File organization: /{companies}/{companyName}/{campaignFolder}/{phaseFolder}/{stepFolder}/{fileName}
Scheduled Background Jobs
The system runs 8 background schedulers. Some maintain system health, others directly affect what users see.
| Job | Schedule | What it does | Business impact |
|---|---|---|---|
| Audit Cleanup | Daily (cron) | Deletes old audit records per company retention policy (by timeout or record count) | If retention is set too aggressively (e.g., 7 days), users lose access to version history permanently. Restore from audit becomes impossible for deleted records. |
| CloudFront Cleanup | Weekly (cron) | Finds and deletes unused CloudFront Origin Access Identities and disabled distributions | Prevents AWS cost accumulation from orphaned resources. If a microsite was deleted but its CloudFront distribution wasn't cleaned up, this job handles it. |
| Application Cache Cleanup | Every 10 min | Clears expired entries from the Customer App file cache (10-hour TTL, 100 MB max) | Ensures Customer App serves fresh content. If cache is stale, users may see old versions of application files. After deploying a new app version, wait up to 10 minutes for cache to refresh. |
| LLM API Key Pool Refresh | Every 60 sec | Reloads API keys from DB. Keys added/removed in the UI take effect within 60 seconds. | When you add a new API key in the UI, it won't be used for AI calls until the next refresh cycle (up to 60 seconds). Same delay when revoking a key. |
| LLM Provider Pool Refresh | Every 60 sec | Synchronizes active/passive/disabled provider instances with DB state. Re-enables temporarily disabled keys (rate-limited). Removes keys deleted from DB. | This is the auto-recovery mechanism for rate-limited keys. When a key hits the provider's quota limit, it's passivated. This job checks every 60 seconds if it can be reactivated. Also: if you disable a key in the UI, the provider stops using it within 60 seconds. |
| OpenAI Key Pool Refresh | Every 60 sec | Same as above but specifically for the legacy OpenAI key pool (separate from the generic LLM pool) | Maintains backward compatibility with the older OpenAI-specific key management system. |
| WebSocket Event Batcher | Every 100 ms | Flushes accumulated WebSocket events to connected clients. Events are batched per campaign with a 500ms timeout or 10-event threshold. Messages > 20KB are GZIP-compressed. | This is why computation progress updates appear in near-real-time. The 100ms polling + 500ms batching means users see updates within ~600ms of an event occurring. If this job stops, users see no progress during computation - it appears frozen. |
| Computation State Checker | Every 1 sec (per active graph) | Polls each active computation graph for ready-to-execute nodes, submits them to thread pool, detects completion, triggers post-computation actions (auto-deploy, status update). | This is the computation engine's heartbeat. It's created per campaign computation and destroyed when computation completes. Detects when all items are done and triggers auto-publishing. Also redistributes thread pool sizes across campaigns every 5 seconds. |
Startup behavior
On system startup, two things happen automatically: (1) all temporarily-disabled LLM API keys are reset to "in pool" state, and (2) all "in-progress" computation items are reset to "created". This means the system self-heals after a restart, but users need to re-trigger any computations that were interrupted.
Key delays to know about
- API key changes: up to 60 seconds to take effect (pool refresh cycle)
- Rate limit recovery: up to 60 seconds for a passivated key to be re-checked
- App cache: up to 10 minutes for Customer App file changes to appear
- WebSocket updates: ~600ms delay from event to user seeing it
- Audit cleanup: runs once daily, not immediately after retention policy change
Intercom Integration
If enabled, the system provides HMAC and JWT tokens for secure Intercom widget embedding. This enables in-app customer support chat.
Dictionary System
Maintains a controlled vocabulary (currently for CSS classes). When a dictionary entry is deleted, it cascades: the class is removed from all steps and document templates that reference it.
5. Audit Trail
What's Tracked
Every change to these entities is recorded with who, when, and what changed:
- Campaigns, Phases, Steps
- All CC Items (computation variables)
- Environment variables
- Document templates
- Campaign i18n labels
- Permission groups and overrides
- AI model configurations
- LLM API keys
Can You Restore Previous Versions?
Yes, partially. The system can restore specific CC items to a previous state from the audit history. You select a business transaction (a grouped set of changes) and the keys to restore. The current items are deleted and replaced with the audit snapshot. A new snapshot is created after restoration for lineage.
Audit cleanup can destroy history
Each company configures its own audit retention policy: keep for N days, keep last N records, or disabled. If set aggressively (e.g., keep 7 days), older history is permanently deleted by the daily cleanup job. Make sure retention policies are appropriate before relying on audit data.
6. Non-Obvious Features & Power-User Tips
Keyboard Shortcuts
Cmd/Ctrl+Enter - save/apply changes in chat and JSON editor. ESC - cancel editing.
"Login As" for Troubleshooting
Admins can impersonate any user to see exactly what they see - invaluable for diagnosing permission issues.
Variable Input Types Control the Customer App UI
CC items can be configured with different input types: text, textarea, URL, color picker, image upload, file upload, dropdown, checkbox, number. This means the same computation engine powers both a flexible admin grid and user-friendly forms.
ItemClass for Special Behaviors
Variables can have "classes": intake_rich_text (rich editor), intake_image_upload (image uploader), intake_url_input (URL validation), intake_color_picker (color picker), migration_carryover (preserved during migration). Set via the classes field.
Hidden Phases & Steps
Mark phases/steps as "hidden" to make them invisible to users without the "Show Hidden" permission. Useful for internal/technical steps.
Multiple LLM Keys = Higher Throughput
Add multiple API keys for the same provider to multiply your effective rate limit. The system distributes calls across all active keys with automatic failover.
JSON Schema for Reliable AI Output
Use json_prompt variables with a JSON schema to enforce structured AI output. The system validates and retries on invalid output. Far more reliable than parsing free-form text.
AI Assist in Customer App
Steps can have an "AI Assist" button. When clicked, it opens an embedded chat targeting specific field keys. On close, the step auto-refreshes to capture AI-generated values. Only available for steps where AI Assist parameters are configured.
Application Versioning
The Customer App supports multiple versions running simultaneously. Each campaign tracks which app version created it. If versions differ, the user is redirected to the correct version. This enables A/B testing of different campaign workflows.
CloudFront Cache Invalidation
When you change a microsite's origin path, the system automatically invalidates the CloudFront cache (all paths). Changes may take a few minutes to propagate globally.
SFTP Direct Upload
Microsite users with SFTP credentials can upload files directly to the microsite bucket via AWS Transfer Family, bypassing the web UI entirely.
Gotcha: API Key Sessions Are Short (5 min)
API key authentication sessions expire after 5 minutes of inactivity (vs. 24 hours for web login). Automated scripts must handle re-authentication.
Gotcha: Session Prompts Accumulate Tokens
Each message in a session includes full conversation history. Long sessions may hit context window limits.
Gotcha: Audit Cleanup Is Per-Company
Each company sets its own audit retention: by timeout, by record count, or disabled. Check your company's policy before relying on old audit data.
Gotcha: Only Public Storage Assets Can Be Deployed to Microsites
Private storage files cannot be deployed. You'll get a "Private Asset" error. Move the file to public storage first.