Files
padelnomics/CHANGELOG.md
Deeman fc410920d8 add supplier tiers, directory redesign, CTA cleanup, and ROI fix
Phase 0 features: ungate planner, lead qualifier with heat scoring,
quote form (migrations 0002-0003), supplier directory with FTS5 search
(migration 0004), landing page redesign with ROI calculator and FAQ.

Phase 1 improvements: supplier tier system with Growth/Pro paid plans
(migration 0005), HTMX live directory search, three-tier card design,
Zillow-style sticky nav, "Get Matched" → "Get Quotes" CTA rename,
remove "Free" messaging site-wide, realistic ROI calculator defaults
(~3.9yr payback / ~26% ROI), mandatory form validation with 422 errors,
supplier pricing page with boost add-ons.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 14:11:35 +01:00

13 KiB

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog.

[Unreleased]

Added

  • Supplier tier system — Migration 0005 adds tier (free/growth/pro), logo_url, is_verified, highlight, sticky_until, sticky_country columns to suppliers table for paid listing support
  • HTMX live search — directory search input and filters update results via hx-get with 300ms debounce; new /directory/results endpoint returns swappable partial
  • Directory card tiers — three-tier card design: Pro (green border, logo, verified badge, website), Growth (description, blue badge), Free (muted, unverified, "Is this your company?" CTA); sticky/featured suppliers pinned to top with blue border
  • Supplier pricing page/suppliers/ now shows Growth (€149/mo) and Pro (€399/mo) plan cards with feature lists, boost add-ons grid (Logo, Highlight, Verified Badge, Sticky Top, Newsletter Feature), updated FAQ
  • Mandatory form fields — country, timeline, and stakeholder_type now required on quote request form with server-side 422 validation
  • Validation testtest_quote_validation_rejects_missing_fields verifies server returns 422 JSON errors for missing mandatory fields

Changed

  • Nav redesign — Zillow-style sticky nav with backdrop-blur: demand-side links (Planner, Directory) left, supply-side (For Suppliers, Help) after separator, Sign In right; removed "Get Started Free" button
  • CTA text sweep — "Get Matched" → "Get Quotes" across planner, landing, and lead forms; removed all "Free" qualifiers from CTAs and badges
  • ROI calculator fix — realistic cost model: €35K/court (was €25K), staff costs, €8/sqm rent (was €4); payback and ROI now based on total investment (was equity only); defaults: €40/hr rate, 35% utilization; shows ~3.9yr payback, ~26% ROI (was 0.1yr/1255%)
  • Directory route refactor — shared _build_directory_query() helper with tier-based SQL ordering (sticky → pro → growth → free → alphabetical)

Added

  • Supplier directory — public searchable directory at /directory/ with 279 padel court suppliers across 31 countries; FTS5 full-text search, country and category filters, pagination, category-colored badges, unclaimed listing model
  • Supplier landing page/suppliers/ marketing page for suppliers: hero, how-it-works steps, example lead preview, FAQ, "Claim Your Listing" CTAs
  • Migration 0004 — creates suppliers table with FTS5 virtual table, content-sync triggers, and seeds 279 suppliers from PadelDirectory.md
  • Quick ROI calculator — landing page now features an interactive 3-slider calculator (courts, rate, utilization) showing investment, monthly cash flow, payback period, and annual ROI in real time
  • Supplier matching section — landing page "Find the Right Suppliers" section with 3-step flow and link to directory
  • FAQ accordion — landing page FAQ covering planner features, signup requirements, supplier matching, directory pricing, and projection accuracy

Changed

  • Visual refresh — adopted React prototype color palette and aesthetic site-wide: royal blue primary (#1D4ED8), green (#16A34A), gold (#D97706); elevated cards with soft shadows, rounder corners (rounded-2xl cards, rounded-xl buttons/inputs), frosted-glass planner nav, highlighted CTA regions with blue-tinted backgrounds, pill-shaped toggle/filter controls, polished buttons with colored shadows, stronger hover lift on directory cards
  • Landing hero redesigned — two-column layout with headline + CTAs on left and interactive Quick ROI calculator on right (matching React prototype); green badge pill, feature check bullets, "Open Full Planner" CTA inside calculator card; responsive single-column on mobile
  • Landing page redesigned — replaced screenshot card with Quick ROI calculator; added supplier matching section, FAQ, and live supplier stats; CTAs renamed "Open the Planner — Free"; Build journey card updated with live supplier/country counts
  • Navbar — Planner and Directory links now visible for all users (not just logged-in); footer updated with Directory and For Suppliers links
  • Planner CTAs — removed sticky "Get Builder Quotes" footer bar; CAPEX and Returns tab CTAs now navigate to wizard step 5 (integrated lead qualifier) instead of redirecting to standalone /leads/quote form
  • Sitemap — added /planner/, /directory/, and /suppliers/ URLs

Changed

  • Planner wizard — Assumptions tab reorganized into 5 guided steps (Your Venue → Pricing → Costs → Finance → Get Matched) with live preview bar and step navigation; reduces cognitive load from 60 sliders to ~6-15 per step
  • Integrated lead qualifier — Step 5 "Get Matched" embeds the supplier quote form directly in the planner; auto-fills venue, courts, glass, lighting, country, budget from planner state; submits inline via fetch
  • JSON quote endpointPOST /leads/quote now accepts application/json and returns {"ok": true, "heat": "..."} for inline planner submissions; standalone HTML form unchanged

Added — Phase 0 Round 2: Polish & Country-Specific Calculator

  • Country-specific calculatorcountry selector (DE/ES/IT/FR/NL/SE/UK/Other) and permitsCompliance CAPEX item for Indoor Rent and Outdoor scenarios; country presets auto-adjust permit costs
  • Permits & Compliance — new CAPEX line item for building permits, noise studies, and regulatory compliance (default €12K for Germany); excluded from Indoor Buy where Planning + Permits already covers this
  • Quote form redesign — elevated white card on gradient background, green gradient CTA buttons, progress labels (Project/Details/Contact), privacy info box, mandatory consent checkbox
  • Project phase (replaces location_status options) — 7-stage progression: still searching → location found → converting existing → lease signed → permit not filed → permit pending → permit granted; updated heat scoring
  • Stakeholder type field — "You are..." selector (Entrepreneur, Tennis Club, Municipality, Developer, Operator, Architect) with stakeholder_type DB column (migration 0003)
  • Build context — added "Need Help Finding a Venue / Land" (venue_search) option
  • Quote submitted page redesign — "You're matched!" flow with next-steps timeline, email confirmation box, and signup CTA for guests
  • Migration 0003 — adds stakeholder_type TEXT column to lead_requests

Changed

  • Landing page — replaced teaser calculator with planner screenshot in browser-frame card + "Start Planning — Free" CTA; all CTAs now point to /planner/ (no signup gate)
  • Heat score — updated calculate_heat_score() for new project phase values (permit_granted +4, lease_signed/permit_pending +3, converting_existing/permit_not_filed +2, location_found +1)
  • Quote URL — planner now passes country parameter to quote form prefill
  • Admin email — includes stakeholder type and updated field labels

Added — Phase 0: Ungate & Validate

  • Guest mode planner — removed auth gate from /planner/ and /planner/calculate; scenarios still require login
  • New calculator variablesbudgetTarget (budget vs CAPEX comparison), glassType (standard/panoramic, 1.4x multiplier), lightingType (LED standard/competition/natural, 1.5x/0x multipliers)
  • Pill select UI component — reusable pillSelect() helper in planner.js with matching .pill-btn CSS for multi-option inputs
  • Budget indicator card — shows over/under budget with variance amount and percentage on the Investment tab
  • 3-step "Get Builder Quotes" flow/leads/quote with project specs, details, and contact steps; no login required
  • Lead heat scoringcalculate_heat_score() rates leads as hot/warm/cool based on timeline, financing, location readiness, and budget signals
  • PDF export CTA — "Export Business Plan (PDF) — €99" wired to Paddle checkout (business_plan price in PADDLE_PRICES)
  • SEO meta tags<meta> description, og:title, og:description, og:image on planner page
  • Migration 0002 — expands lead_requests with 17 new columns for quote qualification flow; makes user_id nullable for guest leads
  • Phase 0 test suite (tests/test_phase0.py) — 47 tests covering guest mode, glass/lighting/budget variables, heat scoring, quote submission, schema validation
  • Updated Hypothesis strategy in test_calculator.py with budgetTarget, glassType, lightingType

Changed

  • Planner CTA links now point to /leads/quote with pre-filled calculator state params (venue, courts, glass, lighting, budget)
  • Sticky footer bar updated: "Get Builder Quotes" + "Export Business Plan (PDF)" replace old supplier/financing links

Changed

  • Landing page journey section: renamed "From Idea to Operating Hall" → "Your Journey", expanded from 4 cards to 5 (Explore → Plan → Finance → Build → Grow) with "Coming Soon" badges on unreleased stages
  • Added .grid-5 CSS helper for 5-column grid layout

Changed

  • Pico CSS → Tailwind CSS v4 — full design system migration across all templates (except planner, which keeps its own CSS)
    • Standalone Tailwind CLI binary (no Node.js) with make css-build / make css-watch
    • Court Tech brand theme: navy/charcoal/electric/accent color palette
    • Component classes (.btn, .card, .form-input, .table, .badge, .flash, etc.) in input.css for consistent styling
    • Self-hosted Commit Mono font (replaces JetBrains Mono) for monospace data display
    • Docker multi-stage build: CSS compiled in dedicated stage before Python build
  • Landing page teaser calculator restyled with Tailwind utilities and brand colors

Removed

  • Pico CSS CDN dependency
  • custom.css (replaced by Tailwind input.css with @layer components)
  • JetBrains Mono font (replaced by self-hosted Commit Mono)

Fixed

  • Empty env vars (e.g. SECRET_KEY=) now fall back to defaults instead of silently using "" — fixes 500 on every request when .env has blank values

Added

  • Comprehensive migration test suite (tests/test_migrations.py — 20 tests) covering fresh DB, existing DB, up-to-date DB, idempotent migration, version discovery, _is_fresh_db, migration 0001 correctness, and ordering
  • Expanded migrate.py module docstring documenting the 8-step algorithm, protocol for adding migrations, and design decisions
  • Sequential migration system (migrations/migrate.py) — tracks applied versions in _migrations table, auto-detects fresh vs existing DBs, runs pending migrations in order
  • migrations/versions/0001_rename_ls_to_paddle.py — first versioned migration (absorbed from scripts/migrate_to_paddle.py)
  • Server-side financial calculator (planner/calculator.py) — ported JS calc(), pmt(), calcIRR() to Python so the full financial model is no longer exposed in client-side JavaScript
  • POST /planner/calculate endpoint for server-side computation
  • Pre-computed initial data (window.__PADELNOMICS_INITIAL_D__) injected on page load for instant first render
  • Debounced API fetch pattern in planner.js with AbortController for in-flight request cancellation
  • Computing indicator CSS (.planner-app--computing) with subtle "computing..." text
  • Comprehensive test suite for calculator (tests/test_calculator.py — 227 tests) covering all 4 venue/ownership combos, edge cases, and Hypothesis property-based fuzzing
  • Comprehensive billing test suite (371 tests total):
    • tests/conftest.py — shared fixtures (DB, app, clients, subscriptions, webhook helpers)
    • tests/test_billing_helpers.py — unit tests for SQL helpers, feature/limit access, plan determination (60+ tests + parameterized + Hypothesis)
    • tests/test_billing_webhooks.py — integration tests for LemonSqueezy webhooks (signature verification, all lifecycle events, Hypothesis fuzzing)
    • tests/test_billing_routes.py — route tests (pricing, checkout, manage, cancel, resume, subscription_required decorator)
    • Added hypothesis>=6.100.0 and respx>=0.22.0 to dev dependencies for property-based testing and httpx mocking
    • Factored into Copier template — all billing tests now generate as .jinja templates with provider-specific conditionals for Stripe, Paddle, and LemonSqueezy
  • GitLab CI/CD pipeline (.gitlab-ci.yml) — runs pytest + ruff on master/MRs, auto-deploys on master
  • Blue-green deployment with Docker Compose profiles (docker-compose.prod.yml, deploy.sh)
    • nginx router on port 5000 proxies to active blue/green slot
    • Zero-downtime: new slot health-checked before traffic switch
    • Automatic rollback on failed health check

Removed

  • scripts/migrate_to_paddle.py — superseded by versions/0001_rename_ls_to_paddle.py

Changed

  • planner.js no longer contains calc(), pmt(), or calcIRR() functions — computation moved server-side
  • render() split into render() (tab switching + schedule calc) and renderWith(d) (DOM updates from data)
  • Tab switching now renders from _lastD cache (instant, no API call)
  • Slider input triggers 200ms debounced server call instead of synchronous client-side calc