Media Buyer
Internal command center for tracking Meta ads and GoHighLevel performance across clients.
Media Buyer
📘 Operator SOP — docs/SOP.md
If you're using this tool, start here. The SOP covers first-time onboarding plus daily, weekly, and monthly routines in plain English. The rest of this README is the developer reference (env vars, storage adapters, API routes).
This is a Next.js project bootstrapped with create-next-app.
Getting Started
First, run the development server:
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
Open http://localhost:3000 with your browser to see the result.
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 to automatically optimize and load Geist, a new font family for Vercel.
Meta Command Center
Internal tool for tracking Meta ads performance across all clients.
Pages
/meta/overview— All clients, KPIs, health status, anomalies/meta/clients/[clientId]— Client detail with charts and trends/meta/anomalies— Red/yellow accounts with reasons/meta/settings— Client mapping, connection status, mock data generation
Enabling
Add to your .env:
META_ENABLED=true # Enable/disable (default: true)
STORAGE_ADAPTER=local # local | memory | postgres (default: local)
If META_ENABLED=false, all Meta pages show a "Meta not connected" empty state.
Seeding Mock Data
- Start the dev server:
npm run dev - Navigate to
/meta/settings - Click "Generate Mock Data" — this creates 10 clients with 60 days of snapshots
- Or call the API directly:
curl -X POST http://localhost:3000/api/meta/seed
Connecting the Meta API
The Meta API integration is stubbed in src/meta/services/metaService.ts. To connect:
- Set
META_ACCESS_TOKENin your.env - Implement
fetchMetaInsights()insrc/meta/services/metaService.ts - The function should call the Meta Marketing API
/insightsendpoint and returnMetaDailySnapshot[] - Call
storage.bulkUpsertSnapshots()to persist the data
Switching Storage Adapters
The storage layer uses an adapter pattern (src/meta/storage/StorageAdapter.ts):
local(default) — Persists to/data/*.jsonfiles. Falls back to in-memory if filesystem is read-only.memory— In-memory only. Data lost on restart.postgres— Skeleton only. To implement:- Install a Postgres client (
@vercel/postgres,pg, Drizzle, or Prisma) - Create the tables (schemas documented in
src/meta/storage/PostgresAdapter.ts) - Implement the adapter methods
- Set
STORAGE_ADAPTER=postgresandDATABASE_URLin.env
- Install a Postgres client (
Recommended upgrade path: Supabase Postgres (free tier) or SQLite via better-sqlite3 for local dev.
API Routes
| Method | Route | Description |
|---|---|---|
| GET | /api/meta/overview?range=7d | Overview KPIs + client table |
| GET | /api/meta/client/[clientId]?range=30d | Client detail + snapshots |
| POST | /api/meta/health/evaluate | Re-evaluate health (all or one) |
| POST | /api/meta/seed | Generate mock data (dev only) |
| PATCH | /api/meta/clients/[clientId] | Update client fields |
GHL Command Center
Internal tool for tracking GoHighLevel leads, appointments, and pipeline across all locations (sub-accounts).
Pages
/ghl/overview— All locations, KPIs (leads, appointments, show rate, booking rate, pipeline)/ghl/locations/[locationId]— Location detail with 6 charts (leads, booked, showed, show rate, opps won, pipeline)/ghl/anomalies— Red/yellow locations with reasons/ghl/settings— OAuth connection status, location mapping, mock data generation
Enabling
Add to your .env:
GHL_ENABLED=true # Enable/disable (default: true)
GHL_CLIENT_ID=xxx # From your GHL Marketplace app
GHL_CLIENT_SECRET=xxx
GHL_ACCESS_TOKEN=xxx # Obtained via OAuth flow
Seeding Mock Data
- Start the dev server:
npm run dev - Navigate to
/ghl/settings - Click "Generate Mock Data" — creates 10 locations with 60 days of data
- Or:
curl -X POST http://localhost:3000/api/ghl/seed
Connecting the GHL API
The GHL API integration is stubbed in src/ghl/services/ghlService.ts. To connect:
- Create a Marketplace app at
https://marketplace.gohighlevel.com/ - Implement OAuth 2.0 flow to get access tokens per location
- Implement
fetchGhlContacts(),fetchGhlAppointments(),fetchGhlOpportunities()in the service file - API base:
https://services.leadconnectorhq.com
Health Rules
Compares last 7 days to previous 7 days:
- RED: 0 leads in 7d, show rate < 30%, 0 appointments despite having leads
- YELLOW: Leads down 25%+, show rate < 50%, booking rate down 20%+
- GREEN: Everything else
GHL API Routes
| Method | Route | Description |
|---|---|---|
| GET | /api/ghl/overview?range=7d | Overview KPIs + location table |
| GET | /api/ghl/location/[locationId]?range=30d | Location detail + snapshots |
| POST | /api/ghl/health/evaluate | Re-evaluate health (all or one) |
| POST | /api/ghl/seed | Generate mock data (dev only) |
| PATCH | /api/ghl/locations/[locationId] | Update location fields |
Learn More
To learn more about Next.js, take a look at the following resources:
- Next.js Documentation - learn about Next.js features and API.
- Learn Next.js - an interactive Next.js tutorial.
You can check out the Next.js GitHub repository - your feedback and contributions are welcome!
Deploy on Vercel
The easiest way to deploy your Next.js app is to use the Vercel Platform from the creators of Next.js.
Check out our Next.js deployment documentation for more details.