add programmatic SEO content engine with article generation pipeline and tests

Adds a complete content generation system for producing SEO articles
at scale with embedded financial scenario widgets. Includes DB schema
(published_scenarios, article_templates, template_data, articles with
FTS5), bulk generation pipeline with staggered publish dates, admin CRUD
for templates/scenarios/articles, public markets hub with HTMX filtering,
catch-all article serving from pre-rendered static HTML, sitemap
integration, and 94 pytest tests covering the full stack.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Deeman
2026-02-18 16:40:11 +01:00
parent 0b218f35ca
commit 61bf855103
33 changed files with 3733 additions and 3 deletions

View File

@@ -6,6 +6,60 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [Unreleased]
### Added — Programmatic SEO: Content Generation Engine
- **Database migration 0010** — `published_scenarios`, `article_templates`,
`template_data`, `articles` tables with FTS5 full-text search on articles;
content-sync triggers for INSERT/UPDATE/DELETE
- **Article template system** — parameterized content recipes with
`input_schema` (JSON field definitions), `url_pattern`, `title_pattern`,
`body_template` (Markdown + Jinja2); supports multiple content types
(only `calculator` built now)
- **Template data rows** — per-city/region input data that feeds the
generation pipeline; manual add or bulk CSV upload
- **Bulk generation pipeline** — `POST /admin/templates/<id>/generate`
computes financial scenarios from data rows via `validate_state()` +
`calc()`, renders Markdown with baked scenario cards, writes static HTML
to `data/content/_build/`, creates articles with staggered publish dates
- **Published scenarios** — standalone financial widgets with pre-computed
`calc_json`; embeddable in articles via `[scenario:slug]` markers with
section variants (`:capex`, `:operating`, `:cashflow`, `:returns`, `:full`)
- **Scenario widget templates** — 6 partial templates (summary, CAPEX
breakdown, revenue & OPEX, 5-year projection, returns & financing,
full combined) with dark navy header bar, Commit Mono numbers, responsive
metric grids, and "Try with your own numbers" CTA
- **Static file rendering** — articles rendered to `data/content/_build/`
as pre-baked HTML; DB stores metadata only, no body content in DB
- **Content blueprint** — catch-all route serves published articles by
`url_path`; registered last to avoid path collisions
- **Markets hub** (`/markets`) — public search + country/region filter page
for discovering articles; HTMX live filtering via FTS5 queries
- **Admin template CRUD** — list, create, edit, delete article templates;
view/add/upload/delete data rows; bulk generation form with start date
and articles-per-day controls
- **Admin scenario CRUD** — list, create (with curated calculator form),
edit + recalculate, delete, preview all widget sections
- **Admin article management** — list with status badges (draft/published/
scheduled), create manual articles (Markdown textarea), edit, delete,
publish/unpublish toggle, rebuild single or all articles
- **Rebuild system** — `POST /admin/articles/<id>/rebuild` and
`/admin/rebuild-all` re-render article HTML from source (template+data
or markdown file) with fresh scenario `calc_json`
- **Article detail page** — SEO meta tags (description, og:title,
og:description, og:type=article, og:image, canonical), article
typography styles, bottom CTA linking to planner
- **Scenario widget CSS** — `.scenario-widget` component styles in
`input.css` with responsive table scroll and metric grid collapse;
`.article-body` typography for headings, paragraphs, lists, blockquotes,
tables, code blocks
- **`slugify()` utility** — added to `core.py` for URL-safe slug generation
- **`mistune` dependency** — Markdown → HTML rendering for articles
- **Sitemap** — `/markets` and all published articles added to
`/sitemap.xml` (only articles with `published_at <= now`)
- **Footer** — "Markets" link added to Product column
- **Admin dashboard** — Templates, Scenarios, Articles quick-link buttons
- **Path collision prevention** — `RESERVED_PREFIXES` validation rejects
article `url_path` values that conflict with existing routes
### Added
- **Dev setup script** (`scripts/dev_setup.sh`) — interactive bootstrap that
checks prerequisites, installs deps, creates `.env` with auto-generated