Multi-channel social operations platform: Signal → Trend → Draft → Govern → Publish → Moderate.
Deploy: See DEPLOY.md for pushing to GitHub and publishing the frontend on Vercel (plus backend options).
- Monorepo: pnpm workspaces
- Frontend: Next.js 15 (apps/web)
- Backend: Express (apps/api)
- Worker: BullMQ (apps/worker)
- DB: Postgres, Queue: Redis
- Packages: shared, db, ingest, rank, generate, linkedin, image-gen (post images with drafts)
- LLM: Anthropic Claude (via
@anthropic-ai/sdk)
- Worker is off by default:
.env.examplesetsASTRA_WORKER_DISABLED=1. No auto ingest/schedule/publish until you turn it on. - Post and test manually via the app (Schedule → “Post now”, or approve drafts and schedule one at a time). Understand impact before enabling the worker.
- Clear schedule backlog: If you had runaway scheduled/failed jobs, run once from repo root:
npm run stop-schedule
This cancels all queued jobs and clears schedule + attempt history so the dashboard shows 0 Scheduled / 0 Recent failures.
- Copy
.env.exampleto.envand set at leastDATABASE_URL,REDIS_URL,ENCRYPTION_KEY(see Environment variables). Worker stays disabled until you setASTRA_WORKER_DISABLED=0. - Start Postgres and Redis:
docker compose up -d(Postgres on host port 5433, Redis on 6379). - From repo root:
npm installthennpm run db:migratethennode --import tsx scripts/seed.ts. If using Docker ports:DATABASE_URL=postgresql://astra:astra@localhost:5433/astra node --import tsx scripts/migrate.tsand same for seed. - Start API and web (two terminals from repo root):
- Terminal 1:
npm run dev:api→ API at http://localhost:4000 - Terminal 2:
npm run dev:web→ App at http://localhost:3000 Optionally run./scripts/dev-start.sh allto kill stale processes and start web + API + worker together.
- Terminal 1:
- Open http://localhost:3000 — select workspace, go to Dashboard. Run pipeline to ingest; generate posts from the Trends from feed section (each draft gets an auto-generated image when the worker runs). Do not run
npm run dev:workeruntil you want automation.
- All workspace
package.jsonfiles use recent stable versions (Next 14, React 18, TypeScript 5.6, etc.). - After pulling changes or editing dependencies, run from repo root:
pnpm install— install/update packages.pnpm audit— list vulnerabilities.pnpm run audit:fix— apply fixes where possible (may add overrides).
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | Postgres connection string |
REDIS_URL |
Yes | Redis connection string |
ENCRYPTION_KEY |
Yes | AES key for LinkedIn token encryption |
ANTHROPIC_API_KEY |
For real LLM | Anthropic API key (falls back to mock if unset) |
LINKEDIN_CLIENT_ID |
For LinkedIn | LinkedIn OAuth app client ID |
LINKEDIN_CLIENT_SECRET |
For LinkedIn | LinkedIn OAuth app client secret |
LINKEDIN_CALLBACK_URL |
For LinkedIn | OAuth callback URL |
NEWSAPI_KEY |
Optional | NewsAPI key for news source adapter |
NEXT_PUBLIC_API_URL |
Optional | API URL for the web app (default http://localhost:4000) |
- Start infra:
docker-compose up -d - Migrate + seed:
npm run db:migrate && node --import tsx scripts/seed.ts - Set env: In
.env, setDATABASE_URL,REDIS_URL,ENCRYPTION_KEY,ANTHROPIC_API_KEY. OptionallyLINKEDIN_CLIENT_ID/SECRET/CALLBACK_URLfor real LinkedIn posting. - Start services:
npm run dev:api,npm run dev:worker,npm run dev:web(3 terminals) - Open app: http://localhost:3000 -- enter token (dev token pre-filled) -- dashboard loads with "Default" workspace
- Add source: Sources page -- add an RSS feed URL (e.g.
https://hnrss.org/frontpage) - Ingest: Dashboard -- click "Ingest now" -- worker fetches RSS items
- Generate: Via API:
curl -X POST http://localhost:4000/workspaces/<wid>/drafts/generate -H "Authorization: Bearer <token>" -H "Content-Type: application/json" -d '{"post_type":"insight"}'-- worker calls Claude -- draft appears in Drafts page - Approve: Drafts page -- click Approve on a pending draft
- Schedule: Schedule page -- select the approved post, pick a future time, click Schedule
- Publish: If LinkedIn is connected, the worker picks up the job and posts. Without LinkedIn credentials, the job fails (visible in Logs).
Send Authorization: Bearer <user_id> (UUID of a user in users table). The web app stores it in localStorage. The AuthGate on the dashboard prompts for it if missing.
Browsers use project path .playwright-browsers (see playwright.config.ts). Install once: npm run playwright:install (or PLAYWRIGHT_BROWSERS_PATH=.playwright-browsers npx playwright install). Run with API and web up: API_URL=http://localhost:4000 WEB_URL=http://localhost:3000 E2E_TOKEN=00000000-0000-0000-0000-000000000001 E2E_WORKSPACE_ID=00000000-0000-0000-0000-000000000002 npm run test:e2e. Full setup: docker compose up -d → DATABASE_URL=postgresql://astra:astra@localhost:5433/astra node --import tsx scripts/migrate.ts → node --import tsx scripts/seed.ts → start API and web → run test:e2e as above.
See execution plan in .cursor/plans/ for API contracts, data model, and task backlog.