10 KiB
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, fetchesGET /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 viamax_posts_per_platform_per_day.
2. Workflow: Generate → DB → degelas-chrome
High-level flow:
- 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.
- Templates: Fill in variables (e.g.
- Validation – Apply platform rules (length, posts-per-day, campaign window). Backend already enforces these on create/bulk/update.
- Persist –
POST /scheduled-postsorPOST /scheduled-posts/bulk(with optionalcampaign_id). Database is the source of truth. - Publish – Existing scheduler job (e.g. every minute) calls
get_due_scheduled_posts, then for each post callsdo_browser_post(platform, text)which uses degelas-chrome (CDP) to navigate, type, and submit. Status is updated topostedorfailed.
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/postorPOST /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-postsor/bulkso 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. Mon–Fri only, or “weekends only”.
- Hours of day: e.g. “09:00, 12:00, 18:00” or “morning (07–10), afternoon (12–15)”.
- 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).
- Static template: e.g.
4.2 Possible backend model (for later)
- Campaign schedule template (e.g. new table or JSON on campaign):
days_of_week: [0–6] 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):
- User creates/edits a campaign and attaches a schedule template (e.g. “Mon–Fri, 09:00 and 18:00, 2 X + 1 IG per day”).
- Backend (or a separate “expand” endpoint) expands the template into a list of (date, time, platform) slots for the campaign’s start_date–end_date, respecting:
- Campaign date range.
max_posts_per_platform_per_day(campaign or global).- Days of week and time slots.
- For each slot, resolve text: from a content template (variables) or from an AI “generate” call.
- Call existing
POST /scheduled-posts/bulkwith 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)
- 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.
- 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.
- 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.
- 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.
- Degelas-chrome: No change. The existing job +
do_browser_postalready drive the container; workflow only adds more ways to create rows inscheduled_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.