Skip to content

Changelog — What Shipped

The running record of what shipped on the FCR Dashboard platform, newest first. This page is the single home for feature news — the README and architecture docs link here instead of restating it. Add new entries at the top of the current month when a feature ships (one bullet, bold name, ship month, what it does, key files/surfaces).

  • NBA DF-completion re-draft sweep (2026-07-01) — when a Digital Footprint audit finishes for a deal with a pending next-best-action, a sweep auto-completes the draft from the finished report (draft_from_report mode — no re-scan), keyed on the report’s synced_at + score. Route dashboard-nba-draft-completion-run; see Next-Best-Action.
  • PMax spend restored across ads surfaces (2026-06-30 → 07-02) — Google stopped emitting ad_network_type=MIXED for Performance Max (last data 2026-05-19), silently blanking PMax rows. dashboard-ads-mtd, dashboard-ads-stats and dashboard-ads-account-detail now read 2_Ads_Data_view, which buckets PMax by the campaign’s advertising_channel_type (never by campaign name). Brief: docs/DEV_BRIEF_pmax_channel_type_2026-06-30.md.
  • Planning Studio front-end live (2026-07-02) — the Marketing & Planning Studio UI is live on the dashboard over the segment engine (dashboard-segment-build / -crossmatch / -save, dashboard-planning-advise).
  • Next-Best-Action (NBA) engine + sales-editable playbooks (mid-June, precompute live for pilot owners) — the deal book now gets ready-to-review next actions without the rep asking. Deterministic code decides WHAT (playbook: channel frame from deal_source, gates, priority); an autonomous advisor run decides HOW (drafts in the rep’s voice from the deal brief). Two halves: the precompute (pull) side is LIVE — after a brief composes for an open pilot deal, a background run persists a rich deal glance + next-action draft to deal-nba:<id> so the HubSpot card renders both instantly; the sweep (push) side — new-deal detection → HubSpot review task + Roam DM, plus a stall sweep — is built but gated off (NBA_ENABLED=0, dry-run) pending the HubSpot tasks.write scope. Named sales leads edit the natural-language playbooks (frame + forbidden moves, never control flow) on the dashboard’s Playbooks tab — BQ source of truth, KV-rendered prompt block, audit rows. Full page: Next-Best-Action.
  • Ahrefs June enrichment — three plays, ~3M units (2026-06-29) — Play 1: +5,007 prospect-domain overviews (DR + organic traffic) → dim_seo; Play 2: top-50 organic keywords for the thin-but-ranking outreach kit, +142K rows → dim_seo_keywords; Play 3: live IE SERPs for each head keyword landing every ranker’s URL + DR + traffic, 23K rows → dim_seo_serp_competitors (new endpoint dashboard-prospect-serp-competitors). Head-of-SEO deliverable: the competitor-DR explorer at quick.fcrinsights.ie/seo-competitor-dr.
  • SayMore engagement programme + monthly refresh (June) — the SayMore hub (population spine + engagement cohorts reconciled to the 1,945 active-SayMore baseline) is rebuilt monthly from the latest Yext Active Services export via the /saymore-refresh skill and republished on FCR Quick. Full page: SayMore — Engagement & Refresh.
  • Advisor per-AM standing preferences (2026-06-26) — AMs can tell the advisor “always do X” once: durable per-AM prefs in KV (am-prefs:{id}, no TTL) with ask-first save/list/forget and a STANDING PREFERENCES prompt addendum; plus a global em-dash ban in drafts.
  • The 20-Minute Market — opportunity tiers — a measured map of where each FCR web product is the honest recommendation, for every Irish business category in every town. fcr_operations.v_opportunity_tier serves one row per (category × locality) at the category’s class minutes (destination = 20-minute drive-time packs, service-area trades = 30): a competitive verdict (THIN — no established site in the pack, BizSite genuinely wins / CONTESTED — outrank an incumbent, LocalRank-SitePro / SATURATED), a market-depth prize grade (households per competitor: SHALLOW/MID/DEEP), CSO population + purchasing-power context, and confidence/desert/wide-radius flags. Built on 1,601 calibrated Valhalla/OSM drive-time catchments, a 100%-coverage category bridge (4,479 raw labels → 179 canonical markets), and two independent evidence streams: 483 managed clients’ GBP outcomes (no-site clients earn 0.97× peers in THIN markets vs 0.67× in CONTESTED) and 9,094 real Google searches recovered from the SerpAPI archive (serp_grid_results, 109K rows — 88% of visible top-3 rankers have a website; proximity beats authority). All boundaries signed off 2026-06-11/12. Surfaces: docs page /opportunity-tier, Claude Code skill /opportunity-tier, rebuild tooling scripts/opportunity-tier/ (quarterly re-measure runbook), 16-slide deck + full report (Present pack). Next: wiring opportunity-rules.js so the advisor/HubSpot card recommend the honest rung per deal.
  • HubSpot card latency cut (2026-06-10) — the deal brief is injected pre-LLM via _anchorDealId (one model pass, zero tool calls) with parallelised setup and prewarm dedupe.
  • Autonomous DF audit-followup emails (2026-06-10) — audit_followup drafts run single-request with no confirm gates, a disclosure block, and an omit-don’t-guess competitor rule; get_insites_report gained a wait_s param.
  • Advisor context bridging (2026-06-09) — pasting a /proposal or /r link into a new Roam session re-hydrates the saved context cross-user (proposal-meta sidecar + REPORTS KV, lib/artefact-rehydrate.js).
  • Advisor async reports + BQ guardrail (2026-06-06) — heavy Roam reports hand off to ADVISOR_QUEUE and post when ready, with a downloadable .md artifact at /report/{key}; run_bigquery dry-runs block >30 GB scans and steer to rollups.
  • docs.fcrinsights.ie on Starlight (2026-06-04) — the docs site moved to Astro Starlight (docs-starlight/, nav.mjs single source of truth, deploy via scripts/deploy-docs-starlight.sh), replacing the legacy generated micro-site.
  • Post Studio — live Yext publishing (2026-05-31) — first real Google Business Profile post published through Yext (accounts/{subscriberId}/posts), with draft grounding off crawled URLs and structured business/product fields. FB/IG/LinkedIn channels and gallery persistence still pending.
  • Deal Patterns promoted out of spike — the dashboard-deal-patterns handler, dormant on FCR-only since the engagement back-catalogue load, is now live on both CF accounts with the full surface. New advisor tool extract_deal_patterns in Roam, /deal-patterns/{slug} public HTML report (30-day KV TTL, mirrors /proposal/{slug}), closed-only default (outcome ∈ {won, lost} unless include_open: true), top-level shortcut filters (outcome, service_trade, close_year, county, owner_name), and a topK auto-expand that re-queries Vectorize when the matched cohort has fewer than 8 deals with typed engagement bodies. Telemetry wired via SKILL_ROUTES.
  • Hold-spacebar push-to-talk in the HubSpot card voice modal — the /voice-stt iframe now records while the spacebar is held and sends on release, alongside the existing click-to-toggle mic. Cross-origin focus is hard inside HubSpot’s openIframeModal, so the page also shows a “click here first to enable space” hint when focus isn’t on the iframe and forces focus back to body on any pointer interaction. Listeners attach on both window and document (capture phase). Files: worker/src/handlers/stt.js (VOICE_STT_HTML).
  • PROSPECT_LISTINGS continuous Pleper refresh — Cloudflare Worker scheduled() handler (every-minute cron on FCR Media production only) drains stale pids through Pleper one at a time. First scheduled job in the worker codebase — all prior cron jobs live in n8n.
    • Schema: PROSPECT_LISTINGS now carries last_updated (bumped on every successful write), pleper_error + pleper_error_at (last failure message + 7-day back-off timestamp).
    • Staleness signal: pids whose newest GBP_SERVICES row is older than 30 days OR who have never been Pleper-checked. Stale rows are pulled FIFO-by-last_updated.
    • Sentinel rows (option-a) — when Pleper successfully returns 0 services for a pid, the cron writes a single GBP_SERVICES row with service_name=NULL + scrape_status="pleper_zero_sentinel". Subsequent competitor-enrich calls see the sentinel, skip the live Pleper call, and report enrichment_status: "complete" (knowing “there are zero” is information, not “unknown”).
    • enrichment_status on competitor-enrich — every pid gets "complete" | "pending_pleper". UI surfaces (grid-map cards, comparison table, hero chips, peer medians, Claude insights, advisor tool instructions) all branch on it so pids that timed out render “Enriching…” instead of unconfirmed zeros.
    • Files: worker/src/handlers/prospect-pleper-refresh.js (new), worker/src/handlers/competitor-enrich.js, worker/src/handlers/prospect-enrich.js, worker/src/handlers/grid-map-build.js, worker/src/handlers/discovery-insights.js, worker/src/handlers/ai-advisor.js. [env.fcr.triggers] crons = ["* * * * *"] in worker/wrangler.toml. Design notes: prospect-listings-refresh-plan.md.
    • Known gap — subscriber_id backfill job: every LRC’s competitor place_ids quietly grow PROSPECT_LISTINGS via competitor-enrich, but new rows write subscriber_id: NULL and there’s no periodic job linking them to FCR clients via dim_listings_with_subscriber_id / active_clients. Marked as next.
  • AM guides at /guides/{slug} — permanent FCR-styled HTML pages served by the worker. Content is baked into worker/src/handlers/guides.js (no KV TTL); add a new guide by appending to the GUIDES map + redeploy. First guide: /guides/voice-notes — how AMs log HubSpot Calls and save proposals via voice messages in Roam.
  • Roam advisor closes the proposal loop — three-part shipment that takes AI-generated proposals from “copy-paste into HubSpot” to one-click on-deal posting in the AM’s own voice:
    • save_proposal_to_deal advisor tool posts AI-assisted proposals as notes on the resolved HubSpot deal (association type 214). AM line auto-fills from roam_users identity; attribution names the AM (“Posted via Roam by Sharon Orr”).
    • roam_users BQ table maps Ro.am body.sender → person + role + canonical AM name + per-AM template. 45 staff seeded. Working message now greets by first name (“Hi Sharon — analysing…”).
    • am_email_templates table + save_my_email_template / delete_my_email_template tools — AMs save their voice once per context (cold_outreach / audit_followup / winback / …) and the advisor picks the right one based on conversational context. Trigger phrase: “save my email template”.
  • Session facts persistencedeal_id / subscriber_id / company_name harvested from tool results during the loop, persisted to KV alongside chat history, surfaced in the system addendum next turn. Closes the long-running “advisor forgot the deal_id” bug — “post that to the deal” now resolves without re-querying.
  • get_deals live HubSpot fallback — when BQ hubspot_deals returns zero for a company filter, retries via dashboard-hubspot-deals-search with dealNameContains. Closes the gap for fresh creates / just-won deals not yet in the BQ sync.
  • GA4/GSC partition-aware date window — analytics cards anchor on the latest month present in the BigQuery shards via /dashboard-data-freshness, so May 1–7 doesn’t show an empty April column before the 8th-of-month ETL lands.
  • LRC grid map upgrades — multi-circle “Draw to inspect” demographics, plus per-satellite × keyword avg rank, presence %, and a top-3 competitor mini-table on the rankings sidebar. Both build_lrc_grid_map.py and the worker port worker/src/handlers/grid-map-build.js.
  • Discovery (Alpha) — stepped LRC + AI insights + DF compare, baked into a shareable /r/:id map. See worker/src/handlers/discovery-*.js.
  • Multi-grid LRC — home + 2 satellites, SAB centre override, shared + geo keywords. Driven by the /prospect skill.
  • Area Intelligence Map — census + purchasing power + growth + commercial properties at small-area resolution (cathaldev3.fcrweb.ie). Worker handlers: area-map-embed, circle-demographics, meta-reach, meta-reach-batch.
  • Vector searchfcr-site-portfolio (similar prospects) + fcr-company-knowledge (case studies, SayMore + fcrmedia.ie content) indices. Tools find_similar_sites + search_company_knowledge are live in the Roam advisor.
  • Roam AI Advisor (v3) — 73 tools including HubSpot deal-by-id (with inline screenshots + attachments), HubSpot note posting, revenue bridge with DEA installment spreading, prospect intel, area demographics, and keyword intelligence.
  • Worker deploy gatescripts/deploy-worker.sh refuses dirty trees and tags every deploy.
Ask the docsRAG over this site
Ask anything about the FCR Dashboard platform — architecture, BigQuery, the worker routes, billing rules, the LRC stack, scoring… Answers are grounded in this documentation, with source links.
How does the deal-brief refresh work? Which routes are Worker vs n8n? How is account health scored?