# Admin Panel Guide

The admin panel lives at `/admin/` and is restricted to users whose email is in `ADMIN_EMAILS`.
Dev shortcut: `GET /auth/dev-login?email=<admin-email>` (DEBUG mode only).

Sidebar navigation (left to right in layout):
**Dashboard → Marketplace → Leads → Suppliers → Flags → Feedback → Emails → pSEO → SEO**

CMS sections (Templates, Scenarios, Articles) are linked from the sidebar too.

---

## Dashboard `/admin/`

Quick-glance overview: user count, lead funnel summary, recent tasks, and credit economy totals. Entry point for everything else.

---

## Marketplace `/admin/marketplace`

Single-screen health view for the two-sided market. Useful for daily ops check and spotting stalled leads or low supplier engagement.

**Lead Funnel** (top cards)
| Card | Meaning |
|------|---------|
| Total Leads | All quote-type leads ever submitted |
| Verified New | Verified leads with status `new` — ready to be unlocked by a supplier |
| Unlocked | Distinct leads that have at least one `lead_forward` record |
| Won | Leads with status `closed_won` |
| Conversion Rate | Won ÷ Total |

**Credit Economy**
| Card | Meaning |
|------|---------|
| Issued | Sum of all positive credit ledger entries (purchases + refills) |
| Consumed | Credits spent on lead unlocks (absolute value of `lead_unlock` entries) |
| Outstanding | Current `credit_balance` sum across all paid-tier suppliers |
| 30-day Burn | Credits consumed in the last 30 days |

**Supplier Engagement**
| Card | Meaning |
|------|---------|
| Active | Paid-tier suppliers with `credit_balance > 0` |
| Avg Unlocks | Average lead forwards per active supplier |
| Response Rate | Forwards where `status != 'sent'` ÷ total forwards |

**Feature Flags** — `lead_unlock` and `supplier_signup` toggles are inline on this page. Clicking saves immediately and refreshes (no full-page reload). Also accessible at `/admin/flags`.

**Activity Stream** — HTMX partial loaded on page open, showing the last 50 events across three tables: new leads, lead unlocks, credit ledger entries. Three dot colours: blue = lead created, green = unlock, amber = credit event.

---

## Leads `/admin/leads`

**List view** (`/admin/leads`)

Summary cards at top: total leads / new+unverified / hot pipeline credits / forward rate.

Filters (HTMX live — updates table without page reload):
- **Search** — matches `contact_name`, `contact_email`, `contact_company`
- **Status** — new / pending_verification / contacted / forwarded / closed_won / closed_lost
- **Heat** — hot / warm / cool
- **Country** — ISO country code
- **Period** pills — Today / 7d / 30d / All

**Detail view** (`/admin/leads/<id>`)

Full lead record including all extended quote fields (build context, glass type, lighting, location status, financing, services needed, notes).

Inline HTMX actions (no full-page reload):
- **Status change** — dropdown + save button → swaps the status badge in place
- **Forward to supplier** — select supplier + send → appends row to forward history table

Forward history table shows: supplier name, current forward status, credit cost, sent timestamp.

**Create lead** (`/admin/leads/new`) — manual lead entry for phone/offline enquiries.

**Heat scoring** — set automatically on submission: hot = 35 credits (≥6 courts + confirmed budget + short timeline), warm = 20, cool = 8.

---

## Suppliers `/admin/suppliers`

**List view** — search by name/email, filter by tier (free/basic/growth/pro) and country. Table shows tier badge, credit balance, and listing status.

**Detail view** (`/admin/suppliers/<id>`)
- Adjust credit balance (add or subtract, reason logged to `credit_ledger`)
- Change subscription tier
- View all lead forwards for this supplier with forward statuses
- Impersonate supplier (enter their session to debug dashboard issues)

**Create supplier** (`/admin/suppliers/new`) — manual supplier onboarding.

---

## Feature Flags `/admin/flags`

Toggle on/off without redeploy. Current flags:

| Flag | Controls |
|------|---------|
| `markets` | Market score pages visible to public |
| `payments` | Paddle checkout enabled |
| `planner_export` | PDF export tab visible in planner |
| `supplier_signup` | Supplier signup wizard accessible |
| `lead_unlock` | Suppliers can unlock leads (spend credits) |

Flags can also be toggled inline on the Marketplace dashboard for the two most-used flags.

---

## Feedback `/admin/feedback`

All submissions from the on-page feedback widget (thumbs up/down + optional text). Filterable by page and rating. Rate-limited to 1 per IP per page per hour.

---

## Emails

### Sent Log `/admin/emails`

Every outgoing email recorded in `email_sent`. Filter by type (magic_link, lead_forward, weekly_digest, etc.), delivery event (delivered/bounced/opened/clicked), or free-text search on recipient/subject.

Clicking a row opens the **detail view** — shows metadata, Resend delivery event timeline, and a sandboxed HTML preview of the message body fetched live from Resend API.

### Inbox `/admin/emails/inbox`

Inbound emails received via Resend inbound routing. Unread count shown as a badge in the sidebar. Detail view renders the HTML body in a sandboxed iframe with an inline reply form.

### Compose `/admin/emails/compose`

Send one-off transactional or plain emails. Select from-address (leads@, hello@, etc.) and optionally wrap in the branded email shell.

### Audiences `/admin/emails/audiences`

Lists all Resend audiences (waitlist, planner nurture, etc.) with contact counts. Drill into an audience to view contacts and remove individuals.

---

## pSEO Engine `/admin/pseo`

Operational visibility for the programmatic SEO content pipeline. Four sub-tabs:

**Content Gaps** — for each template, shows DuckDB serving rows that have no matching article in the requested language. Use this to prioritise what to generate next.

**Health Checks** — per-article sanity checks:
- hreflang orphans (EN article exists, DE missing)
- missing HTML build files on disk
- broken `[scenario:slug]` references in article markdown

**Freshness** — compares `_serving_meta.json` export timestamp vs `MAX(updated_at)` across articles per template. Status: 🟢 Fresh / 🟡 Stale / 🟣 No articles / ⚫ No data.

**Jobs** — live generation job monitor. Progress bars poll every 2s while jobs run. Error drilldown via `<details>` on failed jobs.

Generation is triggered from the **Templates** section (see below) — pSEO Engine is read-only observability.

---

## SEO Hub `/admin/seo`

Aggregated SEO metrics from Google Search Console, Bing Webmaster Tools, and Umami. Three tabs:

- **Search** — keyword performance (impressions, clicks, CTR, position) synced daily
- **Funnel** — Umami pageview → planner → quote conversion funnel
- **Scorecard** — per-article GSC impressions/clicks overlay on article metadata

**Sync** button triggers an immediate background sync of all configured sources (otherwise syncs daily via scheduler).

Requires `GSC_CLIENT_SECRETS_JSON`, `GSC_PROPERTY_URL`, `BING_API_KEY`, and `UMAMI_*` env vars.

---

## CMS

### Templates `/admin/templates`

Each template = a Jinja2 Markdown template file + a DuckDB data source query. Templates produce articles at scale.

Actions per template:
- **Edit** — modify template body, data query, or metadata
- **Preview** — render a single row through the template without saving
- **Generate** — bulk generate articles for all (or specific) data rows; runs as background task; progress visible in pSEO Engine → Jobs

### Scenarios `/admin/scenarios`

Public scenario cards shown on the landing page (e.g. "6-court indoor club in Munich"). Each has a name, description, financial state blob (pre-fills the planner), and a live PDF preview.

### Articles `/admin/articles`

Generated article records. Filter by template, language, country, published status.

Per-article actions: **Edit** markdown inline, **Publish/Unpublish** (HTMX, no page reload), **Rebuild HTML** (re-runs Markdown → HTML without re-generating content), **Delete**.

**Rebuild All** button at top re-processes every published article's Markdown into HTML — use after template or CSS changes.

---

## Tasks `/admin/tasks`

Worker queue state. Shows pending / running / failed tasks with payload and error log. Actions: **Retry** (re-enqueues), **Delete** (removes from queue).

Failed tasks do not auto-retry — manual retry is intentional so you can inspect the error first.

---

## Users `/admin/users`

List all users (search by email/name). Detail view shows role, subscription state, scenarios, and recent activity. **Impersonate** button logs you in as that user — "Stop impersonating" in the top bar returns you to your admin session.
