docs: add ADMIN.md — comprehensive admin panel guide
Covers all 10 admin sections: Dashboard, Marketplace (new), Leads, Suppliers, Flags, Feedback, Emails (sent log, inbox, compose, audiences), pSEO Engine, SEO Hub, CMS (Templates, Scenarios, Articles), Tasks, Users. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
208
docs/ADMIN.md
Normal file
208
docs/ADMIN.md
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
# 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.
|
||||||
Reference in New Issue
Block a user