solar/docs/PR_MARKETING_ARCHITECTURE.md

10 KiB
Raw Permalink Blame History

PR Marketing & Campaigns: Architecture & Deep-Dive

This document covers CRUD coverage, workflow (generate → DB → degelas-chrome), optional AI (OpenAI) for content generation, and advanced campaign features (time-of-day, day-of-week, multiple campaigns, templates) so PR/marketing outreach can scale as a source of revenue and attention.

For a full system architecture of the generation workflow grounded in the Solar Production Forecasting product (frontend features, backend APIs, and docs), see GENERATION_WORKFLOW_ARCHITECTURE.md.


1. CRUD & API Summary

Campaigns

Operation Endpoint Status
Create POST /campaigns Body: name, start_date, end_date, max_posts_per_platform_per_day (optional)
Read list GET /campaigns Query: limit
Read one GET /campaigns/{id}
Update PATCH /campaigns/{id} Body: name, start_date, end_date, max_posts_per_platform_per_day (send null to clear override)
Delete DELETE /campaigns/{id} Associated posts are unlinked (campaign_id → null), not deleted
Calendar GET /campaigns/{id}/calendar Returns campaign + posts_by_date (YYYY-MM-DD → list of posts)

Scheduled posts

Operation Endpoint Status
Create POST /scheduled-posts Body: platform, text, scheduled_at (ISO), campaign_id (optional)
Bulk create POST /scheduled-posts/bulk Body: posts[], campaign_id (optional). Validates platform limits and max per day.
Read list GET /scheduled-posts Query: status, platform, campaign_id, from_date, to_date, limit
Read one GET /scheduled-posts/{id}
Update PATCH /scheduled-posts/{id} Pending only. Body: text, scheduled_at, campaign_id (optional).
Cancel DELETE /scheduled-posts/{id} Pending only → status cancelled
Limits GET /scheduled-posts/limits Returns max_length per platform and max_posts_per_platform_per_day

Calendar (aggregate)

  • Global calendar (UI): PR frontend /calendar month grid, fetches GET /scheduled-posts?from_date=&to_date= for the month.
  • Per-campaign calendar: GET /campaigns/{id}/calendar posts grouped by date for that campaign.

Platform rules (enforced in backend)

  • X (Twitter): X_MAX_POST_LENGTH (default 280).
  • Instagram: INSTAGRAM_MAX_CAPTION_LENGTH (default 2200).
  • Max posts per platform per day: MAX_POSTS_PER_PLATFORM_PER_DAY (default 5). Campaign can override via max_posts_per_platform_per_day.

2. Workflow: Generate → DB → degelas-chrome

High-level flow:

  1. Content generation Either:
    • Templates: Fill in variables (e.g. {{product}}, {{date}}) from a template; no AI.
    • AI (OpenAI): Given a brief (campaign goal, tone, platform, constraints), generate copy that respects platform limits.
  2. Validation Apply platform rules (length, posts-per-day, campaign window). Backend already enforces these on create/bulk/update.
  3. Persist POST /scheduled-posts or POST /scheduled-posts/bulk (with optional campaign_id). Database is the source of truth.
  4. Publish Existing scheduler job (e.g. every minute) calls get_due_scheduled_posts, then for each post calls do_browser_post(platform, text) which uses degelas-chrome (CDP) to navigate, type, and submit. Status is updated to posted or failed.

So: workflow = generator (template or AI) → API (create/bulk) → DB → existing job + degelas-chrome. No change to the job or Chrome container for “workflow”; only how posts are created (UI + optional generation service).


3. OpenAI / AI for post generation options

Do you need OpenAI? It depends how you want to create copy.

Approach Pros Cons
Templates only No API cost, deterministic, easy to reason about, fast. Less creative; same structure every time.
OpenAI (or similar) Varied, on-message copy; can follow tone/guidelines; good for many variants. Cost, latency, need prompts and safety.
Hybrid Templates for structure + AI for one-off lines or variants. More moving parts.

Recommendation

  • Start with templates for “advanced” campaigns: time-of-day, day-of-week, multiple campaigns, and rules (e.g. “max 2 X posts per day, 1 Instagram”). You can ship the full workflow (schedule → DB → Chrome) without any AI.
  • Add OpenAI (or similar) later for:
    • “Generate N post ideas for this campaign” (then user picks/edits and schedules).
    • “Generate one post for this slot” from a short brief (campaign name, product, CTA).
  • Backend: Add an optional endpoint, e.g. POST /generate/post or POST /campaigns/{id}/generate-posts, that:
    • Accepts: platform, optional brief/tone, optional template_id, count.
    • Calls OpenAI (or a local model) with system prompt that includes platform limits and rules.
    • Returns suggested text only; the client (or another backend step) then creates rows via existing POST /scheduled-posts or /bulk so all validation and limits still apply.

Important: Generation should output copy, not insert into DB by itself. The existing create/bulk endpoints remain the single place that enforces rules and writes to the DB; generation is “suggest text”, then “create post(s) with that text” so the workflow stays consistent and auditable.


4. Advanced campaigns time-of-day, days-of-week, multiple campaigns

Today a campaign is: name + start_date + end_date + optional max_posts_per_platform_per_day. Scheduling is at exact scheduled_at (datetime) per post. To support “run different campaigns based on hours of the day or on days” in an adjustable way, you need a template/schedule layer that produces concrete scheduled_at + platform + (optionally) text.

4.1 Concepts

  • Campaign (existing): Date range + optional per-day cap. Groups posts for reporting and calendar.
  • Schedule template (new): Defines when and how many posts:
    • Days of week: e.g. MonFri only, or “weekends only”.
    • Hours of day: e.g. “09:00, 12:00, 18:00” or “morning (0710), afternoon (1215)”.
    • Platform split: e.g. “2 X + 1 Instagram per day” (respecting max per platform per day).
  • Content template (new): For each “slot” you need text. Either:
    • Static template: e.g. "New: {{product}} {{url}}" with variables filled from campaign or context.
    • AI-generated: From a brief per campaign or per slot (then feed into the same create/bulk APIs).

4.2 Possible backend model (for later)

  • Campaign schedule template (e.g. new table or JSON on campaign):
    • days_of_week: [06] or “all”.
    • time_slots_utc: ["09:00", "12:00", "18:00"] or similar.
    • platform_slots: e.g. [{"platform": "x", "count": 2}, {"platform": "instagram", "count": 1}] per day.
  • Content template (per campaign or global):
    • Template string with placeholders and/or a “brief” for AI.
    • Optional: link to “generation” endpoint that returns text for a given slot.

Workflow (advanced):

  1. User creates/edits a campaign and attaches a schedule template (e.g. “MonFri, 09:00 and 18:00, 2 X + 1 IG per day”).
  2. Backend (or a separate “expand” endpoint) expands the template into a list of (date, time, platform) slots for the campaigns start_dateend_date, respecting:
    • Campaign date range.
    • max_posts_per_platform_per_day (campaign or global).
    • Days of week and time slots.
  3. For each slot, resolve text: from a content template (variables) or from an AI “generate” call.
  4. Call existing POST /scheduled-posts/bulk with that list (with campaign_id). DB and scheduler + degelas-chrome stay unchanged.

So “adjustable in the template” = schedule template (when) + content template (what). Both are inputs to a generator that produces a list of posts; the list is then pushed through the existing CRUD and job.


5. Implementation order (suggested)

  1. CRUD (done): Campaign and scheduled-post GET one, PATCH, and campaign DELETE are in place. Use them from the PR UI for create/edit/delete and for “verify DB” flows.
  2. Templates (next):
    • Content: Add a simple template model or JSON (e.g. on campaign or global): template string + variables. In the UI, “Generate from template” fills variables and shows preview, then calls create/bulk.
    • Schedule: Add schedule template (days_of_week, time_slots_utc, platform_slots). Add an endpoint or job “expand campaign from schedule template” that produces many (date, time, platform) slots and optionally fills text from content template, then calls bulk create.
  3. UI: Campaign create/edit forms, post create/edit, “generate from template” and “expand schedule” actions. Calendar and posts list already exist; wire them to the new endpoints.
  4. AI (optional): Add a “suggest post” or “generate posts for campaign” endpoint that calls OpenAI, returns text; UI or backend then creates posts via existing APIs so rules and DB stay the single source of truth.
  5. Degelas-chrome: No change. The existing job + do_browser_post already drive the container; workflow only adds more ways to create rows in scheduled_posts.

6. Summary

  • CRUD: Campaigns and scheduled posts have create, read (list + one), update (campaign full, post pending-only), delete (campaign delete + unlink posts; post cancel). Calendar endpoints exist for list and per-campaign.
  • Workflow: Generate content (templates and/or AI) → validate → create/bulk → DB → existing scheduler + degelas-chrome. DB and platform rules stay central.
  • OpenAI: Optional. Use for “suggest copy” or “generate N ideas”; always create posts via existing endpoints so limits and audit stay consistent.
  • Advanced campaigns: Add a schedule template (days + hours + platform split) and content template (or AI brief). An “expand” step turns them into many scheduled posts and feeds bulk create. All posting still goes through the same DB and degelas-chrome path.

This keeps PR/marketing advanced and scalable while reusing the same pipeline and rules everywhere.