← back to Ads Dashboard

README.md

30 lines

# ads-dashboard

Host-aware internal **ad-ops command center**. One zero-dependency Node app serves two live hosts:

| Host | Routing | Cert | Brand |
|---|---|---|---|
| `ads.designerwallcoverings.com` | Cloudflare-proxied → Kamatera | CF edge (origin reuses `ads.agentabrams.com` cert, Full mode) | Designer Wallcoverings |
| `ads.agentabrams.com` | DNS-only (grey) → `45.61.58.125` IP-bound `:443` | LE `ads.agentabrams.com` | Agent Abrams |

- **Auth:** Basic-Auth `admin/DW2024!` on everything except `/healthz`. The `401` is the healthy gate.
- **Prod:** Kamatera `pm2 ads-dashboard` on `:9766` (`/root/Projects/ads-dashboard`).
- **Host→brand map:** `BRANDS` in `server.js` (the `PUBLIC_HOSTS` registry — add a hostname there and it just works).

## Endpoints
- `GET /healthz` — open, returns `{ok, service, brand, host}`
- `GET /api/brand` `/api/overview` `/api/spend` `/api/campaigns` `/api/signals` — Basic-Auth gated
- Static SPA at `/`

## Data sources (wired incrementally by /yoloforever)
- `data/campaigns.<brand>.json` — per-brand campaigns (falls back to `campaigns.json`)
- `data/signals.<brand>.json` — competitor ad signals (advertising-signals skill)
- Spend: reads `~/.claude/cost-ledger.jsonl` when present (7-day rollup)

## Deploy
```sh
tar czf - --exclude=.git --exclude=node_modules . | ssh root@45.61.58.125 \
  'tar xzf - -C /root/Projects/ads-dashboard && cd /root/Projects/ads-dashboard && pm2 restart ads-dashboard'
```
nginx vhosts: `/etc/nginx/sites-enabled/ads.{designerwallcoverings,agentabrams}.com`. Both `listen 45.61.58.125:443` (IP-bound — required on this box or the CF-proxied domain 301s to the fleet default).