--- project: content-hub-phase5-planning type: project-plan status: active tags: - pbs - flask - mysql - n8n - instagram - automation - docker created: 2026-03-19 updated: 2026-03-19 path: PBS/Tech/Projects/ --- # PBS Content Hub — Phase 5 Planning Decisions ## Context Phases 1–4 of the Instagram Automation & Content Hub master plan are complete: - ✅ Phase 1 — MySQL schema with single `instagram_posts` table - ✅ Phase 2 — Reply workflow refactored with error notifications - ✅ Phase 3 — WordPress → MySQL sync via webhook - ✅ Phase 4 — Instagram reel publish webhook capturing reel IDs Phase 5 focuses on building the Content Hub UI layer that gives Jenny and her assistant self-service access to recipe/reel management — removing Travis as the manual middleman for MySQL lookups. --- ## Key Architecture Decisions ### 1. Recipe-to-Reel Linking Strategy **Decision:** Manual selection in Content Hub (Option B) Jenny selects the recipe from a dropdown when creating a reel record in the hub. This auto-populates the post ID, keyword, and URL. No caption parsing, no fragile keyword matching. **Rationale:** Jenny is already in the hub building captions — selecting the recipe is one extra dropdown click. Most reliable approach with zero parsing ambiguity. ### 2. Reel Record Lifecycle (Two-Stage) **Decision:** Local-first, then matched to live data - **Stage 1 (Pre-publish):** Jenny creates a reel record in the Content Hub before anything exists on Instagram. This is a local planning record — working title, linked recipe, keyword, built caption. - **Stage 2 (Post-publish):** After Jenny posts the reel, the Instagram webhook fires, n8n writes the reel ID to `instagram_posts` in MySQL. The hub reads from that table and matches it to the local record. ### 3. n8n Stays Decoupled From the Hub **Decision:** n8n is dumb to the hub - n8n writes to `instagram_posts` in MySQL — that's its job - n8n does NOT call the Content Hub API or know about hub reel records - The Content Hub reads from `instagram_posts` to display what's live - The hub owns the matching logic between its local records and n8n's data **Rationale:** Keeps n8n focused on automation. The hub is the human workflow layer on top. ### 4. Auto-Match Routine **Decision:** Triggered by n8n ping after new insert After n8n writes a new row to `instagram_posts`, it sends a simple ping to the hub (`POST /api/match/run`). The hub then runs the matching logic: ``` For each hub reel record in "Ready" status (no reel ID linked): → Look in instagram_posts for unmatched rows where: - post_id matches (recipe link) OR keyword matches → Single match → auto-link, status → "Live — Matched" ✅ → Multiple matches → flag as "Needs Review" 🟡 → No match → leave as-is ``` Jenny's manual match UI is the fallback for anything the auto-matcher can't confidently link. ### 5. Recipe Dropdown Source **Decision:** MySQL recipes table (not WordPress REST API) The recipe dropdown in the reel creation form pulls from the local MySQL recipes table, which is already kept in sync via the WordPress publish webhook. Faster, no external API calls during form interactions. --- ## UI Structure Decisions ### Reel Detail Page — Tabbed Layout ``` [ Overview ] [ Caption Builder ] ``` **Overview tab:** - Reel Title (free text) - Recipe dropdown (from MySQL) → auto-fills keyword + URL - Keyword (editable — this is the recipe review/confirm step) - Recipe URL (read-only) - Status indicator - Save / Delete **Caption Builder tab:** - Select library blocks (hashtags, links, CTAs, about snippets) - Preview assembled caption - Copy to clipboard ### Reel List View Data points shown per reel (layout TBD — getting Jenny's input on table vs cards): - Reel title - Linked recipe name (or "No Recipe" warning) - Keyword - Status (color dot + label) - Date created or last updated ### Recipe Review UI **Decision:** Not a separate screen. Baked into the reel creation flow — when Jenny selects a recipe from the dropdown, she sees the record (title, URL, keyword) and confirms/edits the keyword right there. ### Manual Match Correction A "Link Reel" button on flagged records in the dashboard. Jenny selects from a list of unmatched `instagram_posts` rows to connect the dots. --- ## Reel Status States (Draft) 1. **Draft** — reel record created, no recipe linked yet 2. **Ready** — recipe linked, keyword confirmed, caption built. Waiting to be posted 3. **Live — Matched** — Instagram webhook received, reel ID attached, auto-reply active 4. **Live — Unmatched / Needs Review** — auto-match couldn't confidently link --- ## Open Questions (Still To Decide) - [ ] Reel list layout: table rows vs cards (get Jenny's feedback) - [ ] Jenny's assistant access: same login or separate user accounts? - [ ] Status Dashboard details: per-reel health indicators + system health panel (next planning session) - [ ] Database schema for hub reel records table (next planning session) - [ ] Define green/yellow/red status thresholds in detail --- ## Target Automation Flow (Full Picture) ``` Jenny creates reel record in hub → selects recipe → builds caption ↓ Jenny posts reel to Instagram ↓ Instagram webhook → n8n → writes reel ID to instagram_posts ↓ n8n pings hub (POST /api/match/run) ↓ Hub auto-match runs: - Finds match → links record → status = Live — Matched ✅ - No confident match → status = Needs Review 🟡 ↓ Comment comes in on Instagram → n8n looks up instagram_posts → sends DM + reply ↓ Dashboard shows green across the board 🟢 ``` --- ## Next Steps - [ ] Define reel status states in detail (green/yellow/red thresholds) - [ ] Sketch Status Dashboard UI - [ ] Define database schema for hub reel records - [ ] Get Jenny's feedback on reel list layout (table vs cards) - [ ] Address assistant access model - [ ] Build once requirements are locked --- *Project: Plant Based Southerner Content Hub* *Planning Session: March 19, 2026* *Participants: Travis & Claude*