docs: CHANGELOG + PROJECT.md for group_key grouping + report PDF
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
12
CHANGELOG.md
12
CHANGELOG.md
@@ -16,6 +16,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|||||||
- **Opportunity Score supply gap ceiling raised 4→8/100k** (`location_opportunity_profile.sql`) — gentler gradient for partially-served markets; accounts for ~87% data undercount vs FIP real-world totals. Documents discovered formula behaviour: DuckDB `LEAST(1.0, NULL)=1.0` means NULL catchment already yields full 15 pts; income PPS saturates for all EU countries; tennis courts data currently empty (formula correct, data pending)
|
- **Opportunity Score supply gap ceiling raised 4→8/100k** (`location_opportunity_profile.sql`) — gentler gradient for partially-served markets; accounts for ~87% data undercount vs FIP real-world totals. Documents discovered formula behaviour: DuckDB `LEAST(1.0, NULL)=1.0` means NULL catchment already yields full 15 pts; income PPS saturates for all EU countries; tennis courts data currently empty (formula correct, data pending)
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
- **group_key static article grouping** — admin articles list now groups EN/DE static cornerstone articles into one row with language chips, matching the existing pSEO grouping behavior:
|
||||||
|
- Migration 0020: `group_key TEXT` column + index on `articles` table
|
||||||
|
- `_sync_static_articles()` auto-upserts `data/content/articles/*.md` on every admin articles page load; reads `cornerstone` frontmatter → `group_key`
|
||||||
|
- `_get_article_list_grouped()` uses `COALESCE(group_key, url_path)` as group key; pSEO articles unchanged (group_key NULL falls back to url_path)
|
||||||
|
- **Email-gated State of Padel Q1 2026 report PDF**:
|
||||||
|
- `data/content/reports/` — new directory for market intelligence reports; state-of-padel .md files moved here from articles/
|
||||||
|
- `reports/` blueprint: `GET/POST /<lang>/reports/<slug>` (email capture gate), `GET /<lang>/reports/<slug>/download` (PDF serve)
|
||||||
|
- Premium WeasyPrint PDF: full-bleed navy cover, Padelnomics wordmark watermark at 3.5% opacity repeated every page via `position:fixed`, gold/teal accents, Georgia headings, running headers/footers via CSS named strings
|
||||||
|
- `make report-pdf` target builds EN + DE PDFs from the .md files
|
||||||
|
- 26 new `report_q1_*` i18n keys in EN + DE (native German via linguistic-mediation)
|
||||||
|
- `/reports` added to `RESERVED_PREFIXES`; `data/content/reports/_build/` gitignored
|
||||||
|
|
||||||
- **Opportunity Score integration** — second scoring dimension (`Marktpotenzial`) now visible in city and country articles:
|
- **Opportunity Score integration** — second scoring dimension (`Marktpotenzial`) now visible in city and country articles:
|
||||||
- **SQL chain**: `dim_cities` now carries `geoname_id` (from the existing GeoNames LEFT JOIN); threaded through `city_market_profile` → `pseo_city_costs_de` which LEFT JOINs `location_opportunity_profile` on `(country_code, geoname_id)`; `pseo_country_overview` gains `avg_opportunity_score`, `top_opportunity_score`, `top_opportunity_slugs`, `top_opportunity_names`
|
- **SQL chain**: `dim_cities` now carries `geoname_id` (from the existing GeoNames LEFT JOIN); threaded through `city_market_profile` → `pseo_city_costs_de` which LEFT JOINs `location_opportunity_profile` on `(country_code, geoname_id)`; `pseo_country_overview` gains `avg_opportunity_score`, `top_opportunity_score`, `top_opportunity_slugs`, `top_opportunity_names`
|
||||||
- **71.4% match rate** — 3,350 of 4,693 cities matched to a GeoNames `geoname_id`; unmatched cities gracefully show no Opportunity Score
|
- **71.4% match rate** — 3,350 of 4,693 cities matched to a GeoNames `geoname_id`; unmatched cities gracefully show no Opportunity Score
|
||||||
|
|||||||
@@ -125,6 +125,8 @@
|
|||||||
- [x] **Outreach pipeline** (`/admin/outreach`) — cold B2B supplier outreach with separate sending domain (`hello.padelnomics.io`), 6-stage pipeline cards, HTMX inline status + note editing, CSV import, bulk add-to-pipeline from supplier list, compose integration (auto-updates pipeline on send); migration 0024 adds 4 outreach columns to suppliers; 44 tests
|
- [x] **Outreach pipeline** (`/admin/outreach`) — cold B2B supplier outreach with separate sending domain (`hello.padelnomics.io`), 6-stage pipeline cards, HTMX inline status + note editing, CSV import, bulk add-to-pipeline from supplier list, compose integration (auto-updates pipeline on send); migration 0024 adds 4 outreach columns to suppliers; 44 tests
|
||||||
- [x] **Outreach follow-up scheduling + activity timeline** — `follow_up_at` date column on suppliers (migration 0025), HTMX date picker on outreach rows, amber "follow-ups due" banner with `?follow_up=due` filter, activity timeline on supplier detail merging sent + received emails by contact email; 29 tests
|
- [x] **Outreach follow-up scheduling + activity timeline** — `follow_up_at` date column on suppliers (migration 0025), HTMX date picker on outreach rows, amber "follow-ups due" banner with `?follow_up=due` filter, activity timeline on supplier detail merging sent + received emails by contact email; 29 tests
|
||||||
- [x] **pSEO article noindex** — `noindex` column on articles (migration 0025), `NOINDEX_THRESHOLDS` per-template lambdas in `content/__init__.py`, robots meta tag in `article_detail.html`, sitemap exclusion, pSEO dashboard count card + article row badge; 20 tests
|
- [x] **pSEO article noindex** — `noindex` column on articles (migration 0025), `NOINDEX_THRESHOLDS` per-template lambdas in `content/__init__.py`, robots meta tag in `article_detail.html`, sitemap exclusion, pSEO dashboard count card + article row badge; 20 tests
|
||||||
|
- [x] **group_key static article grouping** — migration 0020 adds `group_key TEXT` column; `_sync_static_articles()` auto-upserts `data/content/articles/*.md` on admin page load; `_get_article_list_grouped()` groups by `COALESCE(group_key, url_path)` so EN/DE static cornerstones pair into one row
|
||||||
|
- [x] **Email-gated report PDF** — `reports/` blueprint with email capture gate + PDF download; premium WeasyPrint PDF (full-bleed navy cover, Padelnomics wordmark watermark, gold/teal accents); `make report-pdf` target; EN + DE i18n (26 keys, native German); state-of-padel report moved to `data/content/reports/`
|
||||||
|
|
||||||
### SEO & Legal
|
### SEO & Legal
|
||||||
- [x] Sitemap (both language variants, `<lastmod>` on all entries)
|
- [x] Sitemap (both language variants, `<lastmod>` on all entries)
|
||||||
@@ -182,7 +184,7 @@
|
|||||||
|--------|------------|
|
|--------|------------|
|
||||||
| Email nurture sequence (3-email drip for planner users who save scenarios — Resend infra ready, just need content + scheduling) | 30–50 supplier outreach emails |
|
| Email nurture sequence (3-email drip for planner users who save scenarios — Resend infra ready, just need content + scheduling) | 30–50 supplier outreach emails |
|
||||||
| | 2–3 founding member deals (free leads for 3 months) |
|
| | 2–3 founding member deals (free leads for 3 months) |
|
||||||
| | "State of Padel Q1 2026" report written + published |
|
| | "State of Padel Q1 2026" report — landing page live at `/en/reports/q1-2026`, email gate captures leads, PDF built with `make report-pdf` |
|
||||||
| | First 3 priority SEO articles (see `docs/MARKETING.md` for titles) |
|
| | First 3 priority SEO articles (see `docs/MARKETING.md` for titles) |
|
||||||
| | LinkedIn: 5 posts published |
|
| | LinkedIn: 5 posts published |
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user