Files
ClaudeMarketing/docs/plans/2026-03-23-marketing-command-center.md
T

1013 lines
28 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Marketing Command Center Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Build a self-hosted Next.js dashboard that orchestrates a 7-agent AI marketing pipeline, previews generated assets, integrates with Claude Code (Max plan) for feedback, and publishes to Instagram/TikTok via Postiz and Nextdoor via direct API.
**Architecture:** Next.js 15 App Router with SQLite (Prisma), NextAuth credentials auth, Server-Sent Events for realtime, Claude Code subprocess spawning (Max plan OAuth, no API key), Postiz for media hosting + social publishing. Everything in Docker Compose.
**Tech Stack:** Next.js 15, TypeScript, Tailwind CSS, shadcn/ui, Prisma + SQLite, NextAuth v5, @postiz/node, Docker Compose, Remotion, Playwright, Tavily AI SDK
**Reference docs (read before starting any task):**
- `FRONTEND_ARCHITECTURE.md` — full technical architecture, DB schema, code samples
- `THE_COMPLETE_PICTURE.md` — system overview, data flow, user journey
- `AUTONOMOUS_MARKETING_PLAN.md` — 7-agent pipeline design, creative frameworks
- `PLATFORM_SPECS.md` — Instagram/TikTok/Nextdoor API specs and dimensions
- `BEST_PRACTICES_GUIDE.md` — Anthropic skill authoring guidelines, knowledge file templates
---
## Phase 1: Project Scaffold + Docker
### Task 1: Initialize Next.js Project
**Files:**
- Create: `package.json`
- Create: `tsconfig.json`
- Create: `next.config.ts`
- Create: `tailwind.config.ts`
- Create: `postcss.config.mjs`
- Create: `.gitignore`
- Create: `app/layout.tsx`
- Create: `app/page.tsx`
**Step 1: Create the Next.js project**
Run:
```bash
cd ~/Desktop/code/claude_marketing
npx create-next-app@latest . --typescript --tailwind --eslint --app --src-dir=false --import-alias="@/*" --turbopack
```
Expected: Project scaffold created, `package.json` exists
**Step 2: Verify it runs**
Run: `npm run dev`
Expected: Server starts at http://localhost:3000
**Step 3: Commit**
```bash
git init
git add -A
git commit -m "feat: scaffold Next.js 15 project with TypeScript and Tailwind"
```
---
### Task 2: Add shadcn/ui
**Files:**
- Modify: `package.json` (new deps)
- Create: `components/ui/` (component files)
- Create: `lib/utils.ts`
- Modify: `tailwind.config.ts` (shadcn theme)
**Step 1: Initialize shadcn/ui**
Run:
```bash
npx shadcn@latest init -d
```
Expected: `components.json` created, `lib/utils.ts` created
**Step 2: Add core components we'll need**
Run:
```bash
npx shadcn@latest add button card input label badge dialog tabs table textarea separator avatar dropdown-menu sheet sidebar toast
```
Expected: Components installed in `components/ui/`
**Step 3: Commit**
```bash
git add -A
git commit -m "feat: add shadcn/ui with core components"
```
---
### Task 3: Set Up Prisma + SQLite Database
**Files:**
- Create: `prisma/schema.prisma`
- Create: `lib/prisma.ts`
**Step 1: Install Prisma**
Run:
```bash
npm install prisma @prisma/client
npx prisma init --datasource-provider sqlite
```
Expected: `prisma/schema.prisma` created with SQLite datasource
**Step 2: Write the full schema**
Replace `prisma/schema.prisma` with the complete schema from `FRONTEND_ARCHITECTURE.md` lines 68-156. Models: User, Campaign, AgentRun, Asset, ClaudeSession, TrendReport.
**Step 3: Create the Prisma client singleton**
Create `lib/prisma.ts`:
```typescript
import { PrismaClient } from "@prisma/client";
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };
export const prisma = globalForPrisma.prisma || new PrismaClient();
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
```
**Step 4: Push schema to database**
Run: `npx prisma db push`
Expected: SQLite file created at `prisma/data/marketing.db`
**Step 5: Commit**
```bash
git add -A
git commit -m "feat: add Prisma with SQLite schema — campaigns, assets, agent runs"
```
---
### Task 4: Set Up NextAuth Authentication
**Files:**
- Create: `lib/auth.ts`
- Create: `app/api/auth/[...nextauth]/route.ts`
- Create: `prisma/seed.ts`
- Create: `middleware.ts`
- Modify: `package.json` (add deps)
**Step 1: Install auth dependencies**
Run: `npm install next-auth@beta @auth/prisma-adapter bcryptjs && npm install -D @types/bcryptjs`
**Step 2: Create auth config**
Create `lib/auth.ts` with NextAuth Credentials provider from `FRONTEND_ARCHITECTURE.md` lines 170-201. JWT session strategy, bcrypt password comparison.
**Step 3: Create the API route**
Create `app/api/auth/[...nextauth]/route.ts`:
```typescript
import { handlers } from "@/lib/auth";
export const { GET, POST } = handlers;
```
**Step 4: Create auth middleware**
Create `middleware.ts` that protects all routes except `/login` and `/api/auth`.
**Step 5: Create seed script**
Create `prisma/seed.ts` from `FRONTEND_ARCHITECTURE.md` lines 206-222. Reads `ADMIN_EMAIL` and `ADMIN_PASSWORD` from env, bcrypt hashes, upserts user.
Add to `package.json`:
```json
"prisma": { "seed": "npx tsx prisma/seed.ts" }
```
**Step 6: Create .env.local**
Create `.env.local`:
```
NEXTAUTH_SECRET=dev-secret-change-in-production-32chars
NEXTAUTH_URL=http://localhost:3000
ADMIN_EMAIL=admin@localhost
ADMIN_PASSWORD=admin123
```
**Step 7: Seed the database**
Run: `npx prisma db seed`
Expected: Admin user created
**Step 8: Commit**
```bash
git add -A
git commit -m "feat: add NextAuth credentials auth with admin seed"
```
---
### Task 5: Create Login Page
**Files:**
- Create: `app/(auth)/login/page.tsx`
- Create: `app/(auth)/layout.tsx`
**Step 1: Create auth layout**
Centered layout, no sidebar. Just a card in the middle of the screen.
**Step 2: Create login page**
Form with email + password inputs, submit button, error state. Uses `signIn("credentials", { ... })` from next-auth. Redirects to `/` on success.
**Step 3: Test login flow**
Run: `npm run dev`
Navigate to http://localhost:3000 → should redirect to `/login`
Log in with admin@localhost / admin123 → should redirect to dashboard
**Step 4: Commit**
```bash
git add -A
git commit -m "feat: add login page with credentials auth"
```
---
### Task 6: Create Dashboard Layout Shell
**Files:**
- Create: `app/(dashboard)/layout.tsx`
- Create: `app/(dashboard)/page.tsx`
- Create: `components/app-sidebar.tsx`
- Create: `components/header.tsx`
**Step 1: Create sidebar navigation**
Using shadcn Sidebar component. Navigation items:
- Dashboard (home icon)
- Campaigns (megaphone icon)
- Assets (image icon)
- Trends (trending-up icon)
- Queue (calendar icon)
**Step 2: Create header bar**
Shows current page title, user avatar dropdown with sign out.
**Step 3: Create dashboard home page**
Placeholder cards: "Active Campaigns", "Pending Review", "Published This Week", plus a "New Campaign" button.
**Step 4: Verify layout**
Run: `npm run dev`, log in, verify sidebar + header + content area render correctly.
**Step 5: Commit**
```bash
git add -A
git commit -m "feat: add dashboard layout with sidebar navigation"
```
---
### Task 7: Docker Compose Setup
**Files:**
- Create: `Dockerfile`
- Create: `docker-compose.yml`
- Create: `.env.example`
- Create: `.dockerignore`
**Step 1: Create Dockerfile**
Multi-stage build from `FRONTEND_ARCHITECTURE.md` lines 478-499. Stages: base (node:20-alpine + Claude CLI + Playwright), deps, builder, runner. Output: standalone Next.js.
**Step 2: Create docker-compose.yml**
4 services from `FRONTEND_ARCHITECTURE.md` lines 516-557: app, postiz, postiz-db, redis. 7 named volumes. App mounts pipeline-outputs and pipeline-knowledge.
**Step 3: Create .env.example**
```bash
TAVILY_API_KEY=tvly-your-key
POSTIZ_URL=http://postiz:5000
POSTIZ_API_KEY=your-postiz-key
POSTGRES_PASSWORD=secure-password
NEXTDOOR_API_TOKEN=your-token
NEXTDOOR_ADVERTISER_ID=your-id
NEXTAUTH_SECRET=generate-random-32-char-string
ADMIN_EMAIL=you@yourdomain.com
ADMIN_PASSWORD=your-password
```
**Step 4: Create .dockerignore**
```
node_modules
.next
prisma/data
.env.local
```
**Step 5: Test Docker build**
Run: `docker compose build app`
Expected: Image builds successfully
**Step 6: Commit**
```bash
git add -A
git commit -m "feat: add Docker Compose with Postiz, Postgres, Redis"
```
---
## Phase 2: Pipeline Integration
### Task 8: Create Pipeline Directory Structure
**Files:**
- Create: `pipeline/CLAUDE.md`
- Create: `pipeline/knowledge/brand_identity.md`
- Create: `pipeline/knowledge/platform_guidelines.md`
- Create: `pipeline/knowledge/product_campaign.md`
- Create: `pipeline/assets/.gitkeep`
- Create: `pipeline/outputs/.gitkeep`
- Create: `pipeline/package.json`
**Step 1: Create CLAUDE.md**
Write the project source-of-truth file following the template in `BEST_PRACTICES_GUIDE.md` Section 2. Declares all 7 agents, folder structure, pipeline execution order, output conventions, safety rules.
**Step 2: Create knowledge file templates**
Use the templates from `BEST_PRACTICES_GUIDE.md` Section 3. Placeholder content for each — user fills in their actual brand details.
**Step 3: Create pipeline package.json**
```json
{
"name": "marketing-pipeline",
"private": true,
"dependencies": {
"@tavily/core": "^0.7.2"
}
}
```
**Step 4: Install pipeline deps**
Run: `cd pipeline && npm install`
**Step 5: Commit**
```bash
git add -A
git commit -m "feat: add pipeline directory with CLAUDE.md and knowledge templates"
```
---
### Task 9: Create the 7 Agent Skills
**Files:**
- Create: `pipeline/skills/trend-scout/SKILL.md`
- Create: `pipeline/skills/marketing-research-agent/SKILL.md`
- Create: `pipeline/skills/script-writer/SKILL.md`
- Create: `pipeline/skills/ad-creative-designer/SKILL.md`
- Create: `pipeline/skills/video-ad-producer/SKILL.md`
- Create: `pipeline/skills/copywriter-agent/SKILL.md`
- Create: `pipeline/skills/distribution-agent/SKILL.md`
**Step 1: Write each SKILL.md**
Follow the template from `BEST_PRACTICES_GUIDE.md` Section 4. Each skill needs:
- YAML frontmatter (name, description with trigger phrases, ≤1024 chars)
- CRITICAL: Read Knowledge Files section
- Step-by-step workflow
- Output convention: `outputs/{task_name}_{date}/{subfolder}/`
- Troubleshooting + Quality Checklist
Use the agent specs from `AUTONOMOUS_MARKETING_PLAN.md` for each agent's purpose, inputs, outputs, and tools. Use platform dimensions from `PLATFORM_SPECS.md`.
Key details per agent:
- **trend-scout**: Tavily queries for trending hooks, competitor ads, viral formats. Outputs `trend_report.json`.
- **marketing-research-agent**: 5 Tavily queries (trends, competitors, pain points, hooks, viral). Outputs `research_results.json` + `research_brief.md` + `interactive_report.html`.
- **script-writer**: Reads research → writes 5 hook variations × 3 platform styles. Outputs to `scripts/` folder.
- **ad-creative-designer**: NanoBanana MCP → HTML/CSS layout → Playwright screenshot. Configs for IG 1080x1080, IG Stories 1080x1920, Nextdoor 1200x1200, Nextdoor 1200x628.
- **video-ad-producer**: Remotion compositions. Style param: polished (IG), authentic (TikTok), local (Nextdoor). Auto-render to MP4.
- **copywriter-agent**: Platform-tuned captions. Outputs `instagram_captions.json`, `tiktok_captions.json`, `nextdoor_posts.json`.
- **distribution-agent**: Assembles publish manifest. Gate-protected. Outputs `Publish_{campaign}_{date}.md`.
**Step 2: Verify skills are discoverable**
Run from `pipeline/` directory:
```bash
claude -p "What skills are available?" --allowedTools "Read,Grep,Glob"
```
Expected: All 7 skills listed
**Step 3: Commit**
```bash
git add -A
git commit -m "feat: add 7 agent skills — trend scout through distribution"
```
---
### Task 10: Set Up Remotion Video Project
**Files:**
- Create: `pipeline/remotion-ad/` (full Remotion project)
**Step 1: Initialize Remotion**
Run:
```bash
cd pipeline
npx create-video@latest remotion-ad --template blank
```
Expected: Remotion project created in `pipeline/remotion-ad/`
**Step 2: Install Remotion deps**
Run:
```bash
cd pipeline/remotion-ad
npm install @remotion/google-fonts
```
**Step 3: Verify Remotion renders**
Run: `npx remotion render src/index.ts MyComp --output out.mp4`
Expected: MP4 file created
**Step 4: Commit**
```bash
git add -A
git commit -m "feat: add Remotion video project for ad generation"
```
---
### Task 11: Claude Subprocess Spawner (lib/claude.ts)
**Files:**
- Create: `lib/claude.ts`
**Step 1: Write the failing test**
Create `__tests__/lib/claude.test.ts`:
```typescript
import { runAgentStep, buildCampaignPrompt } from "@/lib/claude";
describe("buildCampaignPrompt", () => {
it("builds a prompt from campaign config", () => {
const config = {
name: "test",
platforms: ["instagram", "tiktok"],
goal: "app downloads",
keyMessage: "test message",
};
const prompt = buildCampaignPrompt(config);
expect(prompt).toContain("instagram");
expect(prompt).toContain("tiktok");
expect(prompt).toContain("app downloads");
});
});
```
**Step 2: Run test to verify it fails**
Run: `npx jest __tests__/lib/claude.test.ts`
Expected: FAIL
**Step 3: Implement lib/claude.ts**
Create `lib/claude.ts` with:
- `buildCampaignPrompt(config)` — turns campaign form data into the prompt string
- `runAgentStep(agentName, prompt, cwd)` — spawns `claude -p` as subprocess, returns `{ sessionId, output }`
- `launchPipeline(campaignId, prompt, cwd)` — runs all agent steps sequentially, emits SSE events
- `pipelineEvents` — EventEmitter for SSE broadcasting
- `sendChatMessage(sessionId, message, cwd)` — for the Claude feedback chat
Follow the code from `FRONTEND_ARCHITECTURE.md` lines 290-365. Key: each agent runs as its own short `claude -p` call (not one long session) to avoid the Max plan SIGTERM timeout issue.
**Step 4: Run test to verify it passes**
Run: `npx jest __tests__/lib/claude.test.ts`
Expected: PASS (at least buildCampaignPrompt — subprocess tests need integration test)
**Step 5: Commit**
```bash
git add -A
git commit -m "feat: add Claude subprocess spawner with per-agent-step execution"
```
---
### Task 12: Postiz Client (lib/postiz.ts)
**Files:**
- Create: `lib/postiz.ts`
**Step 1: Install Postiz SDK**
Run: `npm install @postiz/node`
**Step 2: Write lib/postiz.ts**
Implement from `FRONTEND_ARCHITECTURE.md` lines 371-424:
- `uploadToPostiz(filePath)` — multipart upload, returns `{ mediaId, publicUrl }`
- `pushToPostiz(asset, scheduledAt)` — uploads media + creates scheduled post
- `getPostizIntegrations()` — lists connected channels
**Step 3: Commit**
```bash
git add -A
git commit -m "feat: add Postiz client for media upload and scheduling"
```
---
### Task 13: File Serving API Route
**Files:**
- Create: `app/api/files/[...path]/route.ts`
**Step 1: Implement file server**
From `FRONTEND_ARCHITECTURE.md` lines 433-466. Auth-gated, path-traversal protected, serves images/videos/JSON/HTML/markdown from the pipeline outputs directory.
**Step 2: Test manually**
Place a test image in `pipeline/outputs/test.png`, run dev server, navigate to `/api/files/outputs/test.png` → should see image (after login).
**Step 3: Commit**
```bash
git add -A
git commit -m "feat: add authenticated file serving for pipeline outputs"
```
---
## Phase 3: Campaign CRUD + Pipeline UI
### Task 14: Campaign List Page
**Files:**
- Create: `app/(dashboard)/campaigns/page.tsx`
- Create: `app/api/campaigns/route.ts`
**Step 1: Create API route**
`GET /api/campaigns` — returns all campaigns ordered by createdAt desc.
`POST /api/campaigns` — creates a new campaign (name, platforms, config).
**Step 2: Create the campaigns list page**
Table or card grid showing: campaign name, status badge, platforms, created date, "View" button. Plus a "New Campaign" link.
**Step 3: Commit**
```bash
git add -A
git commit -m "feat: add campaign list page with CRUD API"
```
---
### Task 15: New Campaign Form
**Files:**
- Create: `app/(dashboard)/campaigns/new/page.tsx`
- Create: `components/campaign-form.tsx`
**Step 1: Build the campaign form component**
Fields:
- Campaign name (text input)
- Platforms (checkboxes: Instagram, TikTok, Nextdoor)
- Campaign goal (select: app downloads, brand awareness, engagement)
- Key message (textarea)
- Social proof (textarea)
- Variations per platform (number input, default 5)
- Use latest trend report (checkbox)
Submit → POST to `/api/campaigns` → redirect to campaign detail page.
**Step 2: Commit**
```bash
git add -A
git commit -m "feat: add new campaign form"
```
---
### Task 16: Campaign Detail Page — Pipeline Progress Tab
**Files:**
- Create: `app/(dashboard)/campaigns/[id]/page.tsx`
- Create: `app/(dashboard)/campaigns/[id]/layout.tsx`
- Create: `app/api/campaigns/[id]/route.ts`
- Create: `app/api/campaigns/[id]/launch/route.ts`
- Create: `app/api/campaigns/[id]/stream/route.ts`
- Create: `components/pipeline-progress.tsx`
- Create: `hooks/usePipelineProgress.ts`
**Step 1: Create campaign detail layout**
Tab navigation: Pipeline | Assets | Claude Chat. Shows campaign name + status badge in header. "Launch Pipeline" button (only when status is draft).
**Step 2: Create launch API route**
`POST /api/campaigns/[id]/launch` — calls `launchPipeline()` from `lib/claude.ts`. Creates output directory, builds prompt from campaign config, spawns Claude subprocess. Returns immediately (pipeline runs async).
**Step 3: Create SSE stream route**
`GET /api/campaigns/[id]/stream` — SSE endpoint from `FRONTEND_ARCHITECTURE.md` lines 231-266. Subscribes to `pipelineEvents` for this campaign ID.
**Step 4: Create usePipelineProgress hook**
From `FRONTEND_ARCHITECTURE.md` lines 270-285. Connects to SSE endpoint, updates agent status in real-time.
**Step 5: Create pipeline progress component**
Shows the 7 agent steps as a vertical list. Each step shows: status icon (pending/running/completed/failed), agent name, duration, output summary. Uses the SSE hook for live updates.
**Step 6: Wire it all together**
Campaign detail page shows pipeline progress. "Launch Pipeline" button triggers launch API → SSE updates flow to UI.
**Step 7: Commit**
```bash
git add -A
git commit -m "feat: add campaign pipeline progress with real-time SSE updates"
```
---
### Task 17: Campaign Detail — Asset Gallery Tab
**Files:**
- Create: `app/(dashboard)/campaigns/[id]/assets/page.tsx`
- Create: `app/api/assets/route.ts`
- Create: `app/api/assets/[id]/route.ts`
- Create: `components/asset-gallery.tsx`
- Create: `components/asset-card.tsx`
**Step 1: Create assets API routes**
`GET /api/assets?campaignId=X&type=image&platform=instagram` — filtered asset list.
`PATCH /api/assets/[id]` — update status (approve/reject), update metadata.
**Step 2: Create asset card component**
Shows: thumbnail preview (images inline, video with play button), platform badge, dimensions badge, status badge, hook text preview, caption preview. Approve (green check) and Reject (red X) buttons.
Images served via `/api/files/...` route.
Videos served via `<video>` element with same route.
**Step 3: Create asset gallery component**
Grid layout. Filter bar: platform dropdown, type dropdown (image/video/copy/all), status dropdown. Bulk select with "Approve Selected" / "Reject Selected" buttons.
**Step 4: Commit**
```bash
git add -A
git commit -m "feat: add asset gallery with filtering and approve/reject"
```
---
### Task 18: Campaign Detail — Claude Chat Tab
**Files:**
- Create: `app/(dashboard)/campaigns/[id]/chat/page.tsx`
- Create: `app/api/claude/route.ts`
- Create: `components/claude-chat.tsx`
- Create: `hooks/useClaudeChat.ts`
**Step 1: Create Claude chat API route**
`POST /api/claude` — accepts `{ message, sessionId, campaignPath }`. Spawns `claude -p` with `--resume` if sessionId exists. Streams response via `stream-json` format. Saves/updates ClaudeSession in DB.
**Step 2: Create useClaudeChat hook**
Manages message list, streaming state, session ID persistence. Sends messages to API, parses streaming response, appends text deltas to UI in real-time.
**Step 3: Create Claude chat component**
Chat interface: message list (user bubbles right, Claude bubbles left), text input with send button, streaming indicator. Session ID stored in ClaudeSession table for `--resume` across page navigations.
**Step 4: Commit**
```bash
git add -A
git commit -m "feat: add Claude chat panel with streaming and session persistence"
```
---
## Phase 4: Publishing Integration
### Task 19: Push to Postiz Flow
**Files:**
- Create: `app/api/postiz/route.ts`
- Create: `components/postiz-push-modal.tsx`
**Step 1: Create Postiz API route**
`POST /api/postiz` — accepts `{ assetIds, scheduledAt }`. For each asset: uploads media to Postiz, creates scheduled post, updates asset record with postizPostId and status = "published".
`GET /api/postiz/integrations` — returns connected Postiz channels (so UI knows which platforms are available).
**Step 2: Create push modal component**
Triggered by "Push to Postiz" button in asset gallery. Shows:
- Selected assets with previews
- Platform for each asset
- Caption preview (editable)
- Schedule date/time picker (defaults to recommended time)
- Confirm / Cancel buttons
On confirm → calls POST `/api/postiz` → closes modal → updates asset cards with "Scheduled" badge.
**Step 3: Add "Push to Postiz" button to asset gallery**
Appears when 1+ assets are approved and selected. Opens the push modal.
**Step 4: Commit**
```bash
git add -A
git commit -m "feat: add Push to Postiz flow with scheduling modal"
```
---
### Task 20: Postiz Queue Page
**Files:**
- Create: `app/(dashboard)/queue/page.tsx`
**Step 1: Create the queue page**
Lists all assets with `postizPostId` set. Shows: asset thumbnail, platform, caption preview, scheduled time, status (scheduled/published/failed). Sorted by scheduled time.
Optional: iframe embed of Postiz dashboard at `POSTIZ_URL` for the visual calendar.
**Step 2: Commit**
```bash
git add -A
git commit -m "feat: add Postiz publishing queue page"
```
---
### Task 21: Nextdoor Direct API Integration
**Files:**
- Create: `lib/nextdoor.ts`
- Create: `app/api/nextdoor/route.ts`
**Step 1: Create Nextdoor client**
GraphQL client for Nextdoor Ads API. Functions:
- `createNextdoorCampaign(name, budget, schedule)`
- `createNextdoorAdGroup(campaignId, targeting)`
- `uploadNextdoorCreative(filePath)`
- `createNextdoorAd(adGroupId, creativeId, copy)`
**Step 2: Create API route**
`POST /api/nextdoor` — accepts asset IDs, creates campaign + ad group + creative + ad in Nextdoor. Updates asset status.
**Step 3: Add Nextdoor option to push modal**
When asset platform is "nextdoor", show "Push to Nextdoor" instead of "Push to Postiz".
**Step 4: Commit**
```bash
git add -A
git commit -m "feat: add Nextdoor Ads API direct integration"
```
---
## Phase 5: Supporting Pages + Polish
### Task 22: Global Asset Library Page
**Files:**
- Create: `app/(dashboard)/assets/page.tsx`
**Step 1: Build the page**
Same asset gallery component as campaign detail, but fetches all assets across all campaigns. Adds campaign name column/badge. Search input for filtering by caption/hook text.
**Step 2: Commit**
```bash
git add -A
git commit -m "feat: add global asset library page"
```
---
### Task 23: Trend Reports Page
**Files:**
- Create: `app/(dashboard)/trends/page.tsx`
- Create: `components/trend-report-viewer.tsx`
**Step 1: Build the page**
Lists TrendReport records. Each shows name, date, summary. Click → expands to show the HTML report in an iframe (served via `/api/files/...`). "Create Campaign from This" button → navigates to `/campaigns/new` with trend report pre-selected.
**Step 2: Commit**
```bash
git add -A
git commit -m "feat: add trend reports page with HTML viewer"
```
---
### Task 24: Dashboard Home — Real Data
**Files:**
- Modify: `app/(dashboard)/page.tsx`
- Create: `app/api/stats/route.ts`
**Step 1: Create stats API route**
`GET /api/stats` — returns:
- Active campaigns count (status = running or review)
- Pending review count (assets with status = draft in review campaigns)
- Published this week count
- Recent campaigns (last 5)
- Latest trend report
**Step 2: Update dashboard home page**
Replace placeholder cards with real data from stats API. Add "New Campaign" button prominently.
**Step 3: Commit**
```bash
git add -A
git commit -m "feat: wire dashboard home to real campaign and asset data"
```
---
### Task 25: Pipeline Output Scanner
**Files:**
- Create: `lib/scanner.ts`
**Step 1: Build the output scanner**
When a pipeline run completes (or on-demand), scan the campaign's output directory and create Asset records for every file found:
- `outputs/{campaign}/ads/*.png` → type: image
- `outputs/{campaign}/video/*.mp4` → type: video
- `outputs/{campaign}/copy/*.json` → type: copy
- `outputs/{campaign}/scripts/*.md` → type: script
- `outputs/{campaign}/*.html` → type: research
- `outputs/{campaign}/*.md` → type: research
Infers platform from filename (instagram_, tiktok_, nextdoor_). Reads dimensions from image metadata. Reads caption/metadata from adjacent JSON files.
**Step 2: Integrate with pipeline completion**
In `lib/claude.ts`, call `scanOutputDirectory(campaignId, outputPath)` when pipeline completes.
**Step 3: Commit**
```bash
git add -A
git commit -m "feat: add pipeline output scanner to auto-populate asset database"
```
---
## Phase 6: Docker Finalization + Testing
### Task 26: Final Docker Configuration
**Files:**
- Modify: `Dockerfile` (finalize)
- Modify: `docker-compose.yml` (finalize)
- Create: `scripts/setup.sh`
**Step 1: Finalize Dockerfile**
Ensure it handles:
- Claude Code CLI installation
- Playwright Chromium installation
- Prisma generation
- Pipeline directory copy
- Remotion project copy with node_modules
**Step 2: Create setup script**
```bash
#!/bin/bash
# scripts/setup.sh — first-time setup
docker compose up -d
docker compose exec app npx prisma db push
docker compose exec app npx prisma db seed
echo "Dashboard: http://localhost:3000"
echo "Postiz: http://localhost:5000"
echo "Connect your Instagram + TikTok accounts in Postiz"
```
**Step 3: Test full Docker build and startup**
Run:
```bash
docker compose build
docker compose up -d
bash scripts/setup.sh
```
Expected: Dashboard at :3000, Postiz at :5000, login works, pages load.
**Step 4: Commit**
```bash
git add -A
git commit -m "feat: finalize Docker setup with one-command startup script"
```
---
### Task 27: End-to-End Smoke Test
**Step 1: Start the full stack**
```bash
docker compose up -d
```
**Step 2: Log in**
Navigate to http://localhost:3000 → login with admin credentials.
**Step 3: Create a test campaign**
Click "New Campaign" → fill in test data → submit.
**Step 4: Launch pipeline (dry run)**
Click "Launch Pipeline" → watch agent steps execute in real-time via SSE.
**Step 5: Review assets**
Navigate to Assets tab → verify images/videos render in gallery → approve a few.
**Step 6: Test Claude chat**
Navigate to Claude tab → send "make the hook text snarkier" → verify streaming response.
**Step 7: Push to Postiz**
Select approved assets → Push to Postiz → verify post appears in Postiz queue.
**Step 8: Document any issues**
Create `docs/known-issues.md` if anything needs fixing.
**Step 9: Commit**
```bash
git add -A
git commit -m "docs: add smoke test results and known issues"
```
---
## Summary
| Phase | Tasks | What You Get |
|-------|-------|-------------|
| **1: Scaffold** | 1-7 | Next.js + shadcn + Prisma + Auth + Docker Compose |
| **2: Pipeline** | 8-13 | 7 agent skills + Remotion + Claude spawner + Postiz client + file server |
| **3: Campaign UI** | 14-18 | Campaign CRUD + pipeline progress + asset gallery + Claude chat |
| **4: Publishing** | 19-21 | Postiz push flow + queue page + Nextdoor API |
| **5: Polish** | 22-25 | Asset library + trends page + dashboard stats + output scanner |
| **6: Docker** | 26-27 | Final Docker config + setup script + smoke test |
**Total: 27 tasks across 6 phases.**