7.0 KiB
| project | type | status | tags | created | updated | path | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| content-hub-database-schema | project-plan | active |
|
2026-03-20 | 2026-03-20 | 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
projectstable 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_automationdatabase) pbs_recipestable — 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_poststable 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_recipesalready exists in MySQL — no migration neededprojectsreplaces local SQLitevideo_projects— SQLAlchemy model update + data migrationplatform_postsreplaces n8n internalinsta_reeldata table — data migration from n8n to MySQLproject_typesis new — seed with initial values (reel, youtube)- All new tables go in the
pbs_automationdatabase (or newpbs_content_hubdatabase — TBD, still an open question)
Project: Plant Based Southerner Content Hub Planning Session: March 20, 2026 Participants: Travis & Claude