docs: real README and update Claude auth section in CLAUDE.md
- Replaces the create-next-app boilerplate README with a real one: what the project does, the 8-agent pipeline table, tech stack, local dev, configuration via the Settings UI, multi-tenant App model, Unraid deployment, and repo layout. - CLAUDE.md "Claude Auth in Docker" no longer claims .env is the only way to set the OAuth token — describes the Settings page as primary, .env as bootstrap fallback, mentions the Test button, and notes that Anthropic exposes no UI to list/revoke setup-tokens. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -72,11 +72,14 @@ ssh unraid "cd /mnt/user/appdata/marketing && docker compose down && docker comp
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Claude Auth in Docker
|
### Claude Auth in Docker
|
||||||
Claude Max uses OAuth, tokens stored in macOS Keychain. For headless Docker:
|
Claude Max uses OAuth — tokens stored in macOS Keychain locally, but the headless Docker container has no keychain, so it needs the OAuth access token explicitly. The token is rotated from the **Settings page** (`/settings` → Claude card); the DB value is injected into the spawned `claude` subprocess env at launch time and overrides `CLAUDE_CODE_OAUTH_TOKEN` from the container env. The Test button on the same card validates the token by hitting the Anthropic messages API and surfaces 401s as "Token expired or invalid".
|
||||||
|
|
||||||
|
To mint a token:
|
||||||
1. Run `claude setup-token` locally, open the magic link in browser
|
1. Run `claude setup-token` locally, open the magic link in browser
|
||||||
2. Extract the access token: `security find-generic-password -s "Claude Code-credentials" -a "$(whoami)" -w`
|
2. Extract the access token: `security find-generic-password -s "Claude Code-credentials" -a "$(whoami)" -w | python3 -c 'import sys,json; print(json.load(sys.stdin)["claudeAiOauth"]["accessToken"])'`
|
||||||
3. The JSON has `claudeAiOauth.accessToken` — use just that value
|
3. Paste it into Settings → Claude → Save (no rebuild required)
|
||||||
4. Set `CLAUDE_CODE_OAUTH_TOKEN=<access-token>` in the Unraid `.env`
|
|
||||||
|
`CLAUDE_CODE_OAUTH_TOKEN` in `.env` still works as a bootstrap fallback (used on first boot before any DB value is saved, or if the DB is wiped). There is no Anthropic UI to list or revoke `setup-token` outputs — they live ~1 year. Treat each one like a password.
|
||||||
|
|
||||||
### Volume Permissions
|
### Volume Permissions
|
||||||
Host directories must be owned by UID 1000 (node user in container):
|
Host directories must be owned by UID 1000 (node user in container):
|
||||||
|
|||||||
@@ -1,36 +1,179 @@
|
|||||||
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
# Marketing Command Center
|
||||||
|
|
||||||
## Getting Started
|
A Next.js dashboard that turns the Claude Code CLI into a marketing team.
|
||||||
|
Spawns `claude` as a subprocess to run an 8-agent pipeline that researches
|
||||||
|
trends, writes ad scripts, generates static and video creatives, drafts
|
||||||
|
platform-tuned copy, and prepares a publish manifest — all per campaign,
|
||||||
|
per app, per platform.
|
||||||
|
|
||||||
First, run the development server:
|
Used internally to drive social campaigns for the 88Oak app portfolio
|
||||||
|
(honeyDue, Reflect, etc.). Deployed on an Unraid server at
|
||||||
|
`marketing.88oakapps.com`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What it does
|
||||||
|
|
||||||
|
You create a Campaign in the UI. The web app spawns
|
||||||
|
`claude -p <prompt> --output-format stream-json` once per agent, in order:
|
||||||
|
|
||||||
|
| # | Agent | Output |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | **Trend Scout** | `trend_report.json` — viral hooks, competitor angles, formats (Tavily searches) |
|
||||||
|
| 2 | **Marketing Research** | `research_results.json` + `research_brief.md` (deep Tavily) |
|
||||||
|
| 3 | **Script Writer** | Hook/body/CTA scripts per platform, timed for video |
|
||||||
|
| 4 | **Gemini Ad Designer** | Photo-real static ads via NanoBanana MCP (Google Gemini) |
|
||||||
|
| 5 | **Poster Ad Designer** | "Museum-quality" HTML→PNG posters via Playwright |
|
||||||
|
| 6 | **Video Ad Producer** | Remotion compositions rendered to MP4 (Reels, TikTok) |
|
||||||
|
| 7 | **Copywriter** | Platform-tuned captions with hashtags |
|
||||||
|
| 8 | **Distribution** | `Publish_manifest.md` — never auto-publishes |
|
||||||
|
|
||||||
|
Each agent reads its `pipeline/skills/<name>/SKILL.md` and the campaign's
|
||||||
|
brand/product knowledge files before producing output. Progress streams
|
||||||
|
back to the UI over SSE; completed assets are scanned into the DB and
|
||||||
|
shown in the campaign's asset gallery.
|
||||||
|
|
||||||
|
From there: thumbs-up/down to teach style preferences (fed back into
|
||||||
|
future Gemini prompts as `reference_images`), spawn variations of a
|
||||||
|
winner, repurpose to other dimensions, or push individual assets to
|
||||||
|
[Postiz](https://postiz.com) for scheduling.
|
||||||
|
|
||||||
|
For the agent details and folder conventions, see
|
||||||
|
[`pipeline/CLAUDE.md`](./pipeline/CLAUDE.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tech stack
|
||||||
|
|
||||||
|
- Next.js 16 (App Router) + React 19 + TypeScript 5
|
||||||
|
- Tailwind 4 + shadcn/ui
|
||||||
|
- Prisma 7 over SQLite (`better-sqlite3` adapter)
|
||||||
|
- NextAuth 5 (credentials provider, `trustHost: true` for the reverse proxy)
|
||||||
|
- Playwright (HTML→PNG)
|
||||||
|
- Remotion (video rendering, project at `pipeline/remotion-ad/`)
|
||||||
|
- Claude Code CLI spawned via `child_process.spawn` (NOT the Anthropic SDK)
|
||||||
|
- NanoBanana MCP for Gemini image generation
|
||||||
|
- Tavily for web research
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Local development
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev
|
npm install
|
||||||
# or
|
npx prisma db push
|
||||||
yarn dev
|
npx prisma db seed # creates admin user + honeyDue app
|
||||||
# or
|
npm run dev # http://localhost:3000
|
||||||
pnpm dev
|
|
||||||
# or
|
|
||||||
bun dev
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
Default login: `admin@localhost` / `admin123` (override with `ADMIN_EMAIL`
|
||||||
|
/ `ADMIN_PASSWORD` env vars). The Claude Max OAuth flow on your dev
|
||||||
|
machine handles auth automatically — no token needed locally as long as
|
||||||
|
you've signed into the `claude` CLI once.
|
||||||
|
|
||||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
---
|
||||||
|
|
||||||
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
## Configuration
|
||||||
|
|
||||||
## Learn More
|
Every third-party credential is configured at **Settings** (`/settings`)
|
||||||
|
and stored in the `Setting` DB table. DB values override `.env` at
|
||||||
|
runtime. Each integration card has a **Test** button that hits the real
|
||||||
|
API to verify the credential.
|
||||||
|
|
||||||
To learn more about Next.js, take a look at the following resources:
|
| Integration | What it's for |
|
||||||
|
|---|---|
|
||||||
|
| **Claude** | OAuth access token for the `claude` CLI subprocess. Token expires (~1 year) — refresh here when launches start failing with auth errors. |
|
||||||
|
| **Tavily** | Web research for the Trend Scout and Research agents. |
|
||||||
|
| **Gemini** | Google Gemini powers NanoBanana MCP for static ad generation. |
|
||||||
|
| **Postiz** | Self-hosted social scheduling (Instagram, TikTok). |
|
||||||
|
| **Nextdoor** | Direct Nextdoor Ads API integration. |
|
||||||
|
|
||||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
To mint a Claude Code OAuth token (for headless / Docker use):
|
||||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
|
||||||
|
|
||||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
```bash
|
||||||
|
claude setup-token
|
||||||
|
# extract the access token from your keychain:
|
||||||
|
security find-generic-password -s "Claude Code-credentials" -a "$(whoami)" -w \
|
||||||
|
| python3 -c 'import sys,json; print(json.load(sys.stdin)["claudeAiOauth"]["accessToken"])'
|
||||||
|
```
|
||||||
|
|
||||||
## Deploy on Vercel
|
Paste the result into Settings → Claude → Save. There is no Anthropic UI
|
||||||
|
to list or revoke `setup-token` outputs — treat each one like a password.
|
||||||
|
|
||||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
---
|
||||||
|
|
||||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
## Apps (multi-tenant)
|
||||||
|
|
||||||
|
The same pipeline serves multiple products. Each `App` row in the DB
|
||||||
|
carries its own brand colors, brand identity markdown, product info,
|
||||||
|
platform guidelines, and learned style preferences. At launch time,
|
||||||
|
`launchPipeline` writes the active app's knowledge into
|
||||||
|
`pipeline/_knowledge/` and copies the app's `icon.png` / `phone.png`
|
||||||
|
into Remotion's `public/` directory. Switch active apps from the
|
||||||
|
sidebar.
|
||||||
|
|
||||||
|
Per-app assets live at `pipeline/apps/<slug>/`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Deployment (Unraid)
|
||||||
|
|
||||||
|
The app runs in a single Docker container behind Nginx Proxy Manager at
|
||||||
|
`marketing.88oakapps.com`. Source lives at
|
||||||
|
`/mnt/user/appdata/marketing/` (disposable, rsynced from dev).
|
||||||
|
Persistent data is bind-mounted from `/mnt/user/downloads/marketing/`
|
||||||
|
(`db/`, `outputs/`, `knowledge/`).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Sync source (preserves Unraid-specific .env and docker-compose.yml)
|
||||||
|
rsync -avz \
|
||||||
|
--exclude='node_modules' --exclude='.next' --exclude='prisma/data' \
|
||||||
|
--exclude='pipeline/outputs' --exclude='pipeline/remotion-ad/.next' \
|
||||||
|
--exclude='pipeline/remotion-ad/node_modules' \
|
||||||
|
--exclude='.env' --exclude='.env.local' --exclude='docker-compose.yml' \
|
||||||
|
--delete \
|
||||||
|
./ unraid:/mnt/user/appdata/marketing/
|
||||||
|
|
||||||
|
# Rebuild + restart
|
||||||
|
ssh unraid "cd /mnt/user/appdata/marketing && docker compose down \
|
||||||
|
&& docker compose build app && docker compose up -d"
|
||||||
|
```
|
||||||
|
|
||||||
|
Full deployment notes (`docker-compose.yml` shape, volume permissions,
|
||||||
|
Dockerfile quirks) are in [`CLAUDE.md`](./CLAUDE.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Repo layout
|
||||||
|
|
||||||
|
```
|
||||||
|
app/ Next.js App Router
|
||||||
|
(auth)/ Login
|
||||||
|
(dashboard)/ UI: campaigns, assets, apps, settings, trends
|
||||||
|
api/ REST endpoints (campaigns, assets, settings, files)
|
||||||
|
components/ React components incl. shadcn/ui
|
||||||
|
lib/
|
||||||
|
claude.ts Subprocess orchestration, prompt building
|
||||||
|
scanner.ts Walks pipeline outputs into Asset rows
|
||||||
|
settings.ts DB-backed config + per-integration health checks
|
||||||
|
postiz.ts Postiz publishing
|
||||||
|
variations.ts "More like this" via Gemini
|
||||||
|
repurpose.ts Reformat to other aspect ratios
|
||||||
|
nextdoor.ts Direct Nextdoor Ads API
|
||||||
|
prisma/
|
||||||
|
schema.prisma User, App, Campaign, AgentRun, Asset, ...
|
||||||
|
seed.ts Admin user + default app
|
||||||
|
pipeline/
|
||||||
|
CLAUDE.md Agent pipeline architecture (read this)
|
||||||
|
skills/<agent>/SKILL.md Per-agent instructions the spawned Claude reads
|
||||||
|
apps/<slug>/ Per-app assets (icon, phone frame, screenshots)
|
||||||
|
knowledge/ Default knowledge (overridden per-app at runtime)
|
||||||
|
outputs/<task>_<date>/ Generated campaign deliverables
|
||||||
|
remotion-ad/ Remotion video project
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Private / internal.
|
||||||
|
|||||||
Reference in New Issue
Block a user