feat: outreach follow-up scheduling, activity timeline, and pSEO noindex (migration 0025)
Feature A — Outreach follow-up + activity timeline: - follow_up_at column on suppliers (migration 0025) - HTMX date picker on outreach rows, POST /admin/outreach/<id>/follow-up - Amber due-today banner on /admin/outreach with ?follow_up=due filter - get_follow_up_due_count() for dashboard widget - Activity timeline on /admin/suppliers/<id>: merges sent + received emails by contact_email Feature B — pSEO article noindex: - noindex column on articles (migration 0025) - NOINDEX_THRESHOLDS per-template lambdas in content/__init__.py - generate_articles() evaluates threshold and stores noindex=1 for thin-data articles - <meta name="robots" content="noindex, follow"> in article_detail.html - Sitemap excludes noindex articles (AND noindex = 0) - pSEO dashboard noindex count card + article row badge Tests: 49 new tests (29 outreach, 20 noindex), 1377 total, 0 failures Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
19
CHANGELOG.md
19
CHANGELOG.md
@@ -15,6 +15,25 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
- **`analytics.execute_user_query()`** — new function returning `(columns, rows, error, elapsed_ms)` for admin query editor
|
||||
- **`worker.run_extraction` task** — background handler shells out to `uv run extract` from repo root (2h timeout)
|
||||
- 29 new tests covering all routes, data access helpers, security checks, and `execute_user_query()`
|
||||
|
||||
- **Outreach follow-up scheduling + activity timeline** — extends the outreach pipeline (migration 0024):
|
||||
- **Migration 0025** — adds `follow_up_at TEXT DEFAULT NULL` to `suppliers` and `noindex INTEGER NOT NULL DEFAULT 0` to `articles`
|
||||
- **Follow-up date picker** (`POST /admin/outreach/<id>/follow-up`) — HTMX date input on each outreach row; sets/clears `follow_up_at`; returns updated row via outerHTML swap
|
||||
- **Follow-up due banner** on `/admin/outreach` — amber alert banner shows count of overdue follow-ups with "Show them" link (`?follow_up=due` filter)
|
||||
- **`?follow_up=due` / `?follow_up=set` filters** in `get_outreach_suppliers()` — querystring params passed through dashboard and results partial
|
||||
- **`get_follow_up_due_count()`** query function counts suppliers with `follow_up_at <= date('now')`
|
||||
- **Activity timeline** on `/admin/suppliers/<id>` — merges sent outreach emails (`email_log WHERE email_type='outreach'`) and received emails (`inbound_emails`) matched by `contact_email`; sorted by date descending; max 50 entries; empty state shown when no history
|
||||
- 29 new tests (follow-up CRUD, due count, due filter, timeline with sent+received, timeline empty state)
|
||||
|
||||
- **pSEO article noindex** — prevents thin-data articles from diluting crawl budget and index quality:
|
||||
- **`NOINDEX_THRESHOLDS` dict** in `content/__init__.py` — per-template lambda: `city-pricing` (venue_count < 3), `city-cost-de` (data_confidence < 1.0), `country-overview` (total_venues < 5)
|
||||
- **`generate_articles()` upsert** now evaluates the threshold and stores `noindex = 1` for articles that fail it; existing articles are updated on re-generation
|
||||
- **`<meta name="robots" content="noindex, follow">`** injected in `article_detail.html` head block when `article.noindex` is truthy
|
||||
- **Sitemap exclusion** — `sitemap.py` articles query adds `AND noindex = 0`; thin-data articles excluded from `sitemap.xml`
|
||||
- **pSEO dashboard noindex card** — 4th summary card shows count of noindex articles (amber highlight when > 0)
|
||||
- **Article row noindex badge** — amber pill badge on `partials/article_row.html` when `a.noindex`
|
||||
- 20 new tests (threshold unit tests per template, sitemap exclusion, article detail robots meta tag)
|
||||
|
||||
- **Outreach pipeline** — cold B2B supplier outreach isolated from transactional emails:
|
||||
- **Separate sending domain** (`hello.padelnomics.io`) — added `"outreach"` key to `EMAIL_ADDRESSES`; reputation isolated from `notifications.padelnomics.io` magic-link/lead-forward traffic (manual DNS step: add domain in Resend dashboard)
|
||||
- **Migration 0024** — 4 new columns on `suppliers`: `outreach_status`, `outreach_notes`, `last_contacted_at`, `outreach_sequence_step`; `NULL` status = not in pipeline (no backfill needed for existing suppliers)
|
||||
|
||||
Reference in New Issue
Block a user