GAEL is a self-hosted marketing operating system. Feed it a campaign brief and it generates, adapts, schedules, publishes, captures leads, and nurtures them — with n8n orchestrating DeepSeek, Listmonk, Mautic, Chatwoot and Umami on a single VM. No Zapier, no Make, no Mailchimp, no HubSpot.
| Template | Duration | Cadence | Use Case |
|---|---|---|---|
| Product Launch | 14 days | Teaser → Reveal → Social proof → Urgency | New product, feature release, course drop |
| Evergreen | Continuous | 3 pins/day, 1 post/day, 2 tweets/day, weekly newsletter | Always-on traffic to landing pages |
| Flash Sale | 24–72 h | All channels, posts every 2–4 h, email blast + reminder | Promo, last-call, inventory clearance |
| Lead Magnet | Continuous | Free value → landing → auto-delivery → nurture | Ebook, checklist, webinar opt-in |
GAEL is structured as a 6-layer pipeline. Every layer is self-hosted on a single Oracle Cloud ARM VM, orchestrated by n8n workflows, and state lives in PostgreSQL. No external SaaS dependencies for the core pipeline — only the channel APIs themselves.
| Workflow | Trigger | What it does |
|---|---|---|
campaign-launcher | Webhook / manual | Receives brief, decides channels, kicks off content generation, starts email sequence |
content-generator | Called by launcher | DeepSeek prompt chain adapts copy per channel (length, tone, hashtags) |
multi-publisher | Cron hourly | Pulls from content_queue, publishes to the right API, marks published |
lead-processor | Mautic webhook | UTM attribution, Listmonk list assignment, nurture kickoff, Chatwoot contact creation |
chatwoot-ai-agent | Chatwoot webhook | Detects language, loads context, DeepSeek reply, escalates hot leads to Telegram |
analytics-loop | Cron nightly | Umami event rollup, DeepSeek scoring, drafts new content ideas, notifies via Telegram |
| Column | Type | Purpose |
|---|---|---|
campaign_id | VARCHAR | Links every post back to the originating brief |
platform | VARCHAR | pinterest / facebook / twitter / instagram / tiktok / email |
content | JSONB | Platform-specific payload (copy, hashtags, media URLs) |
scheduled_at | TIMESTAMP | When the publisher should fire |
status | VARCHAR | pending / published / failed — drives retry logic |
response | JSONB | Raw API response for audit + debugging |
content_queue with the new platform value. The publisher does the rest.Pinterest Board IDs exceed Number.MAX_SAFE_INTEGER (>1018). Any dynamic JS computation silently produces wrong IDs and posts land on the wrong board.
Machine-translated marketing copy sounds robotic and kills engagement. But generating content 3× multiplies LLM cost and drift.
Every platform has different rate limits: Twitter 1500/mo, Listmonk 300/day, Pinterest polite backoff, Facebook burst limits.
Meta restricted API access mid-project, killing direct publishing. A hard blocker for most stacks.
n8n workflows run independently. A lead can trigger lead-processor before chatwoot-ai-agent finishes writing the contact.
Letting a raw LLM answer lead DMs is a legal and brand risk. But scripted bots feel dead.
/campaign, /stats, /queue, /lead) and full docs for handoverI build self-hosted, full-funnel marketing systems — from campaign brief to publish to capture to nurture. One VM, one codebase, zero SaaS lock-in.
💬 Hire Me on Contra ← Back to portfolio