diff --git a/PBS/Tech/Projects/content-hub-database-schema.md b/PBS/Tech/Projects/content-hub-database-schema.md new file mode 100644 index 0000000..11b866c --- /dev/null +++ b/PBS/Tech/Projects/content-hub-database-schema.md @@ -0,0 +1,231 @@ +--- +project: content-hub-database-schema +type: project-plan +status: active +tags: + - pbs + - flask + - mysql + - n8n + - instagram + - automation +created: 2026-03-20 +updated: 2026-03-20 +path: PBS/Tech/Projects/ +--- + +# PBS Content Hub — Database Schema & Table Relationships + +## Purpose + +This document defines the database schema and table relationships for the +PBS Content Hub. It supplements the Phase 5 Architecture & Planning +Decisions doc and serves as a handoff for Claude Code implementation. + +--- + +## Three Data Domains Being Unified + +### 1. PBS Video Manager (migrating from local SQLite to MySQL) +- Local app being migrated to the server as part of the Content Hub +- `projects` table stores all project info (name, status, description, etc.) +- Projects are the central concept — a project can be a reel, YouTube +video, or any future content type + +### 2. PBS Recipe App (live on production MySQL) +- Already in MySQL (`pbs_automation` database) +- `pbs_recipes` table — stores WordPress recipe data +- Powers Jenny's admin page and n8n recipe lookups + +### 3. Instagram Reel Workflow (currently in n8n data tables) +- Being migrated from n8n internal storage to MySQL +- Becomes the generic `platform_posts` table to support Instagram now and +YouTube/other platforms later + +--- + +## Relationship Model + +`projects` is the hub that connects everything. It reaches out to both +`pbs_recipes` and `platform_posts`. Neither of those tables needs to +reference back to projects or to each other. + +``` +project_types + id ←─── type_id + \ + projects + / \ + recipe_id ───→ ←─── platform_post_id + pbs_recipes platform_posts +``` + +### Why platform_posts has no FK to projects +The platform table is just platform data. There is no scenario where +platform_posts needs to look up project info. Projects owns the +relationship to both recipes and platform posts. + +### Why pbs_recipes has no FK to projects +Same reasoning. Recipes exist independently in WordPress. Projects link to +them, not the other way around. + +--- + +## Table Definitions + +### `pbs_recipes` (exists in MySQL, no changes) + +| Column | Type | Notes | +|---|---|---| +| post_id | INT, PK | WordPress post ID | +| recipe_title | VARCHAR(255) | | +| recipe_url | VARCHAR(255) | | +| keyword | VARCHAR(100), nullable | Trigger word for automation | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | auto-update | + +CRUD: Yes — existing Jenny admin page migrates into Content Hub. + +### `project_types` (new) + +| Column | Type | Notes | +|---|---|---| +| id | INT, PK, auto increment | | +| name | VARCHAR(50) | reel, youtube, etc. | +| created_at | TIMESTAMP | | + +CRUD: Yes — managed in Settings tab. Allows adding new content types +without code changes. + +### `projects` (new — replaces local SQLite video_projects) + +| Column | Type | Notes | +|---|---|---| +| id | INT, PK, auto increment | | +| title | VARCHAR(255) | Working title | +| type_id | INT, FK → project_types.id | | +| status | VARCHAR(50) | draft, ready, live-matched, live-needs-review. +Kept as VARCHAR for now — will become a lookup table when Trello +integration is built | +| recipe_id | INT, FK → pbs_recipes.post_id, nullable | Linked recipe | +| platform_post_id | INT, FK → platform_posts.id, nullable | Linked +platform post | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | auto-update | + +CRUD: Yes — this is the main workspace in the Content Hub. + +Note: Additional columns from the existing SQLite video_projects schema +(description, file paths, checklist data, etc.) will be added separately. +This doc focuses on the connecting fields. + +### `platform_posts` (new — replaces n8n insta_reel table) + +| Column | Type | Notes | +|---|---|---| +| id | INT, PK, auto increment | Internal ID | +| platform | VARCHAR(50) | instagram, youtube, tiktok, etc. | +| platform_post_id | VARCHAR(50) | Native ID from the platform. VARCHAR +because Instagram IDs overflow JavaScript integer limits | +| url | VARCHAR(255), nullable | Link to the post on the platform | +| published_at | TIMESTAMP, nullable | When it went live | +| created_at | TIMESTAMP | When we recorded it | +| updated_at | TIMESTAMP | auto-update | + +CRUD: Yes — view/manage platform data in the Content Hub. + +--- + +## n8n Lookup Path (Comment Reply Automation) + +When n8n receives a comment on an Instagram reel and needs the keyword + +recipe URL: + +``` +platform_posts (match on platform_post_id = reel ID from webhook) + → projects (WHERE platform_post_id = platform_posts.id) + → pbs_recipes (WHERE post_id = projects.recipe_id) + → return keyword + recipe_url for the reply +``` + +If any join in the chain returns null, n8n triggers the existing error +notification to Travis. + +--- + +## Auto-Match Routine + +Triggered by n8n ping to `POST /api/match/run` after new `platform_posts` +insert. + +``` +For each project in "Ready" status with no platform_post_id: + → Look in platform_posts for unmatched rows (no project pointing at +them) where: + - Matching criteria (post_id via recipe link, keyword, or other +heuristics) + → Single confident match → update projects.platform_post_id, status → +"live-matched" + → Multiple matches → status → "live-needs-review" + → No match → leave as-is +``` + +Manual match UI is the fallback — Jenny selects from unmatched +platform_posts to link to a project. + +--- + +## Error Checking / Healthcheck (Real-Time) + +No separate table needed. The Status Dashboard computes checks on page load +by querying the four tables: + +- Platform posts with no project linked (unmatched) +- Projects in "ready" status with no platform_post_id for X days +- Projects linked to a recipe that has no keyword +- Broken join chains (project → recipe or project → platform_post returns +null) + +Displayed as green/yellow/red indicators per project and per system on the +Status tab. + +--- + +## CRUD Summary + +| Table | CRUD Location | Primary User | +|---|---|---| +| pbs_recipes | Reels tab (migrated admin page) | Jenny | +| project_types | Settings tab | Travis | +| projects | Projects + Reels tabs | Both | +| platform_posts | Status tab / Reels tab | Both | + +--- + +## Existing Tables to Keep (n8n automation logging) + +These tables remain in `pbs_automation` and are not part of the Content Hub +schema, but n8n continues to use them: + +- `instagram_posts_processed` — tracks processed Instagram posts (prevents +duplicate processing) +- `instagram_replies` — comment reply log for debugging/analytics + +--- + +## Migration Notes + +- `pbs_recipes` already exists in MySQL — no migration needed +- `projects` replaces local SQLite `video_projects` — SQLAlchemy model +update + data migration +- `platform_posts` replaces n8n internal `insta_reel` data table — data +migration from n8n to MySQL +- `project_types` is new — seed with initial values (reel, youtube) +- All new tables go in the `pbs_automation` database (or new +`pbs_content_hub` database — TBD, still an open question) + +--- + +*Project: Plant Based Southerner Content Hub* +*Planning Session: March 20, 2026* +*Participants: Travis & Claude* \ No newline at end of file