# 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=` (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/`) 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/`) - 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 `
` 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.