# MonoSkin Marketing Automation Engine — Developer Documentation

> **Version:** 1.0 (Phase 1)
> **Audience:** Backend / automation engineers building the engine.
> **Stack assumption:** n8n (self-hosted) as the orchestrator + a small companion service for AI calls and brand/compliance checks.
> **Status:** Build spec. Nothing here is live yet.

---

## 0. Abbreviation index key

New engineers: decode these first.

| Short | Full term | Meaning in this system |
|-------|-----------|------------------------|
| WA | WhatsApp | Outflow + reorder channel |
| M2M | MonoSkin to Micro-pharmacy | The B2B trade scheme (clinic onboarding offers) |
| Rx | Prescription | A doctor prescribing a product |
| SKU | Stock Keeping Unit | One sellable product variant |
| Derma | Dermatologist | Lead database #1 |
| CTA | Call To Action | The "do this" line in a creative |
| Gate | Approval gate | A human checkpoint with a prompt box |
| HITL | Human In The Loop | Any step needing human approval |
| LLM | Large Language Model | The AI doing copy/asset generation |
| WABA | WhatsApp Business API | Meta's official WA messaging API |
| IG | Instagram | Social outflow channel |
| Webhook | — | An HTTP callback that triggers a workflow |
| Idempotency | — | Running the same thing twice = same result, no duplicates |

---

## 1. What this engine does (in one paragraph)

A team member types a **one-line idea** into a brief box. The **Connector** (an LLM-driven planning node) reads it, decides which of four lead databases it targets, and proposes which assets to build. After a human approves (or *corrects via a prompt box*), the engine **builds all assets in parallel**, runs them through an **automated brand + compliance gate**, bundles them into a **concept preview email** to `admin@monoskin.in`, waits for **per-asset founder approval**, routes approved assets to **deployment modules**, holds for a **deployment review**, then **pushes live** across WhatsApp, Email, Instagram, and a video-brief handoff. Performance data (opens, clicks, reorders) loops back to make the Connector smarter.

The design principle: **correction replaces rejection**. At every gate, a human can either approve or type an instruction to fix — the idea is nudged forward, not killed.

---

## 2. High-level architecture

```
[Brief box]
     |
     v
[Connector / brain]  --->  Segment router  +  Tool proposal
     |
     v
[GATE A] approve tools  (prompt box: enhance / correct)
     |
     v
[Parallel build]  copy | whatsapp | email | image | video
     |
     v
[Brand-guard + compliance gate]  (automated, auto-fix)
     |
     v
[Concept email -> admin@monoskin.in]
     |
     v
[GATE B] founders approve each asset  (prompt box)
     |
     v
[Module router]  WA | Email | Social | Video
     |
     v
[GATE C] review deployment  (prompt box)
     |
     v
[Go live]  WhatsApp(reorder+broadcast) | Email | Instagram | Video-brief handoff
     |
     v
[Performance + learning loop]  ----> feeds back to Connector
```

### Component responsibilities

| Component | Responsibility | Implementation |
|-----------|----------------|----------------|
| Brief box | Capture one-line idea | n8n Webhook node OR simple web form |
| Connector | Assess idea, pick segment, propose tools | Companion service `/connector/plan` (LLM call) |
| Segment router | Map idea to one of 4 DBs | Rule + LLM classification |
| Parallel build | Generate assets concurrently | n8n `Split In Batches` / parallel branches |
| Brand-guard + compliance | Auto-check + auto-fix assets | Companion service `/guard/check` |
| Concept email | Bundle + email founders | n8n Email node |
| Gates A/B/C | Human approval + prompt box | n8n `Wait` (resume webhook) |
| Module router | Send assets to channel adapters | n8n Switch node |
| Outflow adapters | Actually publish | WABA / SMTP / IG Graph API |
| Learning loop | Store outcomes, retrain prompts | DB writes + scheduled job |

---

## 3. Data model

All state lives in one `campaigns` record that flows through the engine. Keep it as a single JSON document so any node can read the full context.

```json
{
  "campaign_id": "cmp_2026_0001",
  "created_at": "2026-05-28T10:00:00+05:30",
  "created_by": "team_member_id",
  "status": "draft | tools_proposed | building | guarded | preview_sent | assets_approved | deploying | review | live | failed",
  "brief": "Something around Cetosome penetration depth for the IADVL crowd",
  "segment": "dermatologist | aesthetic | hair | plastic_surgery",
  "segment_confidence": 0.0,
  "proposed_tools": ["copy", "whatsapp", "email", "image", "video"],
  "approved_tools": [],
  "assets": {
    "copy":     { "status": "pending", "content": null, "version": 1 },
    "whatsapp": { "status": "pending", "template": null, "version": 1 },
    "email":    { "status": "pending", "subject": null, "body": null, "version": 1 },
    "image":    { "status": "pending", "prompt": null, "url": null, "version": 1 },
    "video":    { "status": "pending", "brief": null, "version": 1 }
  },
  "guard_report": { "passed": false, "fixes_applied": [], "flags": [] },
  "gate_history": [],
  "deployment": { "channels": [], "scheduled_at": null },
  "metrics": { "sent": 0, "opens": 0, "clicks": 0, "reorders": 0 }
}
```

### Lead database schema (per the 4-DB strategy)

Each of the four databases (Dermatologists / Aesthetic / Hair / Plastic) shares this enriched lead schema:

```json
{
  "lead_id": "lead_00001",
  "doctor_name": "",
  "clinic_name": "",
  "mobile": "",
  "whatsapp": "",
  "email": "",
  "city": "",
  "pincode": "",
  "instagram": "",
  "google_rating": 0.0,
  "review_count": 0,
  "dispenses_products": false,
  "has_pharmacy": false,
  "branch_count": 1,
  "premium_score": 0,
  "conference_participation": [],
  "social_activity": "low | medium | high",
  "segment": "dermatologist | aesthetic | hair | plastic_surgery",
  "consent": { "whatsapp": false, "email": false, "updated_at": null }
}
```

> **Compliance note:** `consent` is mandatory before any WhatsApp or email send. The outflow adapters MUST filter on it. This is not optional for WABA.

---

## 4. The Connector (planning brain)

### Endpoint

```
POST /connector/plan
Content-Type: application/json

{
  "brief": "Something around Cetosome penetration depth for the IADVL crowd",
  "history": []        // optional: past approvals/rejections for this idea
}
```

### Response

```json
{
  "segment": "dermatologist",
  "segment_confidence": 0.91,
  "proposed_tools": ["copy", "whatsapp", "email", "image"],
  "rationale": "IADVL is a dermatology association; Cetosome depth is a clinical Rx message. Video deferred — needs clinical sign-off.",
  "draft_angles": [
    "Question hook: how much of your prescribed actives reach the target layer?",
    "Patent credibility: Cetosome US9084818B2",
    "Peer framing: reserved for those who prescribe with precision"
  ]
}
```

### System prompt (companion service)

Keep the brand truth inside the prompt so the Connector never drifts:

```text
You are the MonoSkin Connector. MonoSkin is a research-led, dermatology-aligned
skincare brand selling DIRECTLY to clinics (micro-pharmacy model). The audience
is dermatologists, aesthetic doctors, trichologists and plastic surgeons — NOT
consumers. Tone: clinical, restrained, credible. Never make cure claims or
absolute promises. Lead with mechanism (Cetosome dermal delivery, US patent
US9084818B2) and peer credibility.

Given a one-line brief, return JSON only:
1. segment  (dermatologist | aesthetic | hair | plastic_surgery)
2. segment_confidence (0-1)
3. proposed_tools (subset of: copy, whatsapp, email, image, video)
4. rationale (one sentence)
5. draft_angles (2-3 short hooks)

Defer "video" to brief-only unless explicitly safe. Never output anything but JSON.
```

---

## 5. Parallel build

n8n pattern: after Gate A, branch into one sub-workflow per approved tool. Run concurrently, then merge.

```javascript
// n8n Function node — fan out approved tools into parallel items
const approved = $json.approved_tools;          // e.g. ["copy","whatsapp","email","image"]
return approved.map(tool => ({
  json: {
    campaign_id: $json.campaign_id,
    tool,
    brief: $json.brief,
    segment: $json.segment,
    angles: $json.draft_angles
  }
}));
```

Each branch calls the LLM with a tool-specific prompt. Example for the WhatsApp builder:

```
POST /build/whatsapp
{
  "campaign_id": "cmp_2026_0001",
  "brief": "...",
  "segment": "dermatologist",
  "angles": ["..."]
}

-> returns a WABA-compliant template object:
{
  "template_name": "monoskin_cetosome_depth_v1",
  "category": "MARKETING",
  "language": "en",
  "body": "Dr {{1}}, how much of your prescribed actives actually reach the target layer? MonoSkin's Cetosome® delivery (US Patent US9084818B2) is built for depth. Reply to know more.",
  "buttons": [{ "type": "QUICK_REPLY", "text": "Tell me more" }]
}
```

> **WABA reality:** marketing templates need Meta pre-approval (typically 24–48h). The engine should **submit the template for approval** at build time and only allow broadcast once Meta returns `APPROVED`. Build conservative timelines around this.

---

## 6. Brand-guard + compliance gate (automated)

This is the highest-leverage node — it removes a full human review cycle. Runs with **no human**, auto-fixes what it can, flags what it can't.

### Endpoint

```
POST /guard/check
{ "campaign_id": "cmp_2026_0001", "assets": { ... } }
```

### What it checks

```javascript
const checks = {
  palette: {
    // only brand hexes allowed in generated creatives
    allowed: ["#091F5B","#344EAD","#B0D6F9","#F9F2E8","#F9F9F9","#E8DFCE","#EFEFEF","#1E1E2E"],
    rule: "Reject off-brand colors. Auto-snap near-matches to nearest brand hex."
  },
  no_dark_proposal_bg: {
    rule: "Proposal/preview surfaces must NOT use dark backgrounds. If dark is intentional, require a contrasting logo variant."
  },
  logo_donts: {
    rule: "No stretch, rotate, recolor, effects, or composition change on the logo."
  },
  fonts: {
    allowed: ["Montserrat","Poppins","Nunito","Inter","Helvetica"],
    rule: "Readable modern print fonts only for any rendered doc."
  },
  claims: {
    banned: ["cure","100%","guaranteed","permanent","miracle","instant results"],
    rule: "Flag medical overclaims. Dermatology brand — keep claims defensible."
  }
};
```

### Response

```json
{
  "passed": true,
  "fixes_applied": ["snapped #3050AA -> #344EAD on image creative"],
  "flags": [],
  "requires_human": false
}
```

If `requires_human` is true (e.g. a banned claim it can't safely rewrite), the asset is held and surfaced in the concept email with the flag attached.

---

## 7. Approval gates (HITL with prompt box)

All three gates use the same mechanism: n8n **Wait** node that pauses until a resume webhook is hit. The difference from a normal approve/reject is the **prompt box** — the human can submit a correction string that re-runs the relevant builder.

### Resume webhook contract

```
POST /gate/resume
{
  "campaign_id": "cmp_2026_0001",
  "gate": "A | B | C",
  "decision": "approve | correct | reject",
  "asset": "whatsapp",                 // for Gate B (per-asset)
  "prompt": "Make it shorter and lead with the patent number"   // only if decision = correct
}
```

### Behaviour by decision

| Decision | Engine action |
|----------|---------------|
| `approve` | Advance to next stage |
| `correct` | Re-run the relevant builder with the prompt appended, bump `version`, loop back to the same gate |
| `reject` | Mark asset/campaign rejected, log reason to learning loop |

```javascript
// n8n Switch on $json.decision
switch ($json.decision) {
  case "approve": return [{ json: { ...state, next: "advance" } }];
  case "correct": return [{ json: { ...state, next: "rebuild", prompt: $json.prompt } }];
  case "reject":  return [{ json: { ...state, next: "halt" } }];
}
```

> **Gate B is per-asset.** Founders approve copy, WhatsApp, email and image independently. One corrected asset re-runs without blocking the others.

---

## 8. Concept preview email

After the guard passes, bundle everything into one email to `admin@monoskin.in` with approve/correct links per asset.

```
POST /concept/send
{ "campaign_id": "cmp_2026_0001" }
```

The email body should:
- Use a **light background** (no dark — per brand rule).
- Show each asset as a card with its rendered preview.
- Carry **one approve link and one correct link per asset**, each pointing to the `/gate/resume` webhook with prefilled `gate=B` and the `asset` name.

Email approve link pattern:

```
https://engine.monoskin.internal/gate/resume?campaign_id=cmp_2026_0001&gate=B&asset=whatsapp&decision=approve&token=SIGNED
```

> Sign the token (HMAC) so links can't be forged or replayed. Expire after 7 days.

---

## 9. Deployment modules + outflow adapters

After Gate B, the **Module router** (n8n Switch) sends each approved asset to its channel adapter. After Gate C, adapters fire live.

### Phase 1 channels

| Channel | Adapter | API | Notes |
|---------|---------|-----|-------|
| WhatsApp (reorder + broadcast) | `adapter_whatsapp` | WhatsApp Business API (WABA) | Template must be Meta-`APPROVED`. Filter on `consent.whatsapp`. |
| Email | `adapter_email` | SMTP / provider API | Filter on `consent.email`. Add unsubscribe. |
| Instagram | `adapter_instagram` | IG Graph API (Content Publishing) | Business account required. Schedule, don't spam. |
| Video brief | `adapter_video` | None — handoff only | **No auto-publish.** Writes brief to a shared folder + notifies team. |

### WhatsApp adapter (illustrative)

```javascript
async function sendWhatsApp(lead, template, campaignId) {
  if (!lead.consent.whatsapp) return { skipped: "no_consent" };

  const res = await fetch(`https://graph.facebook.com/v20.0/${PHONE_ID}/messages`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${WABA_TOKEN}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      messaging_product: "whatsapp",
      to: lead.whatsapp,
      type: "template",
      template: {
        name: template.template_name,
        language: { code: "en" },
        components: [{
          type: "body",
          parameters: [{ type: "text", text: lead.doctor_name }]
        }]
      }
    })
  });
  return res.json();
}
```

### Video brief handoff (no publish)

```javascript
// Writes the brief and pings the team — deliberately does NOT publish.
async function handoffVideoBrief(campaign) {
  await saveToDrive(`/video-briefs/${campaign.campaign_id}.md`, campaign.assets.video.brief);
  await notifyTeam(`New video brief ready for ${campaign.campaign_id}. Manual production required.`);
  return { status: "handed_off", auto_published: false };
}
```

---

## 10. Learning + performance loop

Every send, open, click and reorder writes back to `campaigns.metrics` and an `outcomes` table. A scheduled job summarizes what the founders approved vs corrected vs rejected, and what converted — then that summary is injected into the Connector's `history` on the next plan call.

```
POST /metrics/event
{ "campaign_id": "cmp_2026_0001", "type": "open|click|reorder", "lead_id": "lead_00001", "ts": "..." }
```

```javascript
// Nightly: build a learning digest for the Connector
const digest = {
  best_performing_angle: topByClickRate(outcomes),
  commonly_corrected: mostCorrectedAssetTypes(gateHistory),
  rejected_patterns: rejectionReasons(gateHistory)
};
// Stored and passed into POST /connector/plan { history: [digest] } next time.
```

---

## 11. Reliability rules

- **Idempotency:** every outflow send carries an idempotency key (`campaign_id + lead_id + channel`). Re-running a workflow must never double-send.
- **Rate limits:** respect WABA messaging limits and IG publishing limits. Throttle broadcasts; never blast a full DB in one burst.
- **Token signing:** all gate-resume links are HMAC-signed and expire.
- **Consent first:** adapters hard-filter on `consent`. No consent, no send. No exceptions.
- **Dead-letter:** failed sends go to a retry queue, max 3 attempts, then flagged for human review.
- **Audit log:** append every gate decision, guard fix, and send result to an immutable log.

---

## 12. Conservative build timeline (Phase 1)

> Padded deliberately. These are realistic, not optimistic.

| Milestone | Estimate |
|-----------|----------|
| Data model + 4 lead DBs scaffolded | 1.5 weeks |
| Connector service + segment router | 2 weeks |
| Parallel build (copy/email/image) | 2 weeks |
| WhatsApp builder + WABA template approval flow | 2 weeks (incl. Meta review lag) |
| Brand-guard + compliance gate | 2 weeks |
| Gates A/B/C + concept email | 1.5 weeks |
| Outflow adapters (WA/email/IG) + video handoff | 2.5 weeks |
| Learning loop + dashboards | 1.5 weeks |
| Integration testing + dry runs | 2 weeks |
| **Total (sequential, single small team)** | **~17 weeks (~4 months)** |

Parallelizing across 2–3 engineers can compress this, but keep WABA approval lag and IG review on the critical path — they are external and not controllable.

---

## 13. Environment variables

```bash
# Companion service
LLM_API_KEY=
LLM_MODEL=

# WhatsApp Business API
WABA_TOKEN=
WABA_PHONE_ID=
WABA_BUSINESS_ID=

# Email
SMTP_HOST=
SMTP_USER=
SMTP_PASS=
ADMIN_EMAIL=admin@monoskin.in

# Instagram
IG_ACCESS_TOKEN=
IG_BUSINESS_ACCOUNT_ID=

# Engine
GATE_HMAC_SECRET=
ENGINE_BASE_URL=https://engine.monoskin.internal
DB_URL=
```

---

*End of document. Phase 2 (eCommerce, D2C, ePharmacy outflows) extends the Module router and outflow adapters — the brain, gates and guard stay unchanged.*
