Changelog

What's shipped

Newest first. Each entry is a session from the project log — the source of truth for what landed and when.

10 entries

Session 11 · landing-009

First on-niche blog post

  • Phase 9 — First on-niche blog post (landing-009). Published landing/src/content/blog/harvest-a-neighbourhood-off-google-maps.md — the carry-over from feature-001 (predecessor to the redesign plan). Topic: a working walkthrough of how to use Scraper to harvest a whole neighbourhood off Google Maps.
  • Structure: Before you start / Step 1 (pan to region) / Step 2 (start the sweep) / Step 3 (use the Save pill on individual places) / Step 4 (let the sweep finish, or stop early) / Step 5 (clean the rows) / Step 6 (move it to your pipeline) / What this is not (3 honest disclaimers: not headless, not a list vendor, not an anti-scraping workaround) / Where to go next.
  • Tone: matches the on-niche working-walkthrough tone the plan called for. Practical, no marketing fluff. Each step has a concrete outcome ("you will see:", "what remains is a list you can dial from") rather than aspirational language.
  • Frontmatter: title, description, pubDate (2026-08-16), heroImage (blog-placeholder-1.jpg), author (Scraper Team), tags (how-to, prospecting, google-maps). Word count: 1278 (slightly over the 800–1200 target — content is dense with the actual walkthrough, kept it rather than trimming).
  • Verified 2026-08-16: cd landing && make check exits 0; astro build produces 15 pages (was 14 — +1 blog post); astro check reports 0 errors / 0 warnings / 1 pre-existing hint. Post renders at /blog/harvest-a-neighbourhood-off-google-maps/, appears in the blog index, RSS feed, and sitemap.
  • Next: landing-010 — OG image, favicon sanity, Lighthouse 95+, final make check.
Session 10 · landing-011

Premium typography + visual polish

  • Phase 11 — Premium typography + refined visual language (landing-011). Loaded Geist + Geist Mono via Google Fonts, added typography tokens, scaled up the Hero h1 + section titles, refined the card-surface with subtle elevation, and added a subtle fade-up entrance animation that respects prefers-reduced-motion.
  • BaseHead.astro — preconnects to fonts.googleapis.com / fonts.gstatic.com and loads Geist:wght@400;500;600;700&family=Geist+Mono:wght@400;500;600&display=swap. Replaces the placeholder 'Inter' token (which was actually rendering as system-ui).
  • global.css — added typography tokens: --tracking-display (-0.04em), --tracking-tight (-0.025em), --tracking-normal (-0.011em), --leading-display (1.02), --leading-snug (1.18), --leading-relaxed (1.65). Body now applies Geist via --font-sans with font-feature-settings: 'cv11', 'ss03'. Headings use --tracking-display and text-wrap: balance. <code>, <pre>, <kbd>, <samp>, .font-mono apply Geist Mono via --font-mono.
  • .card-surface — refined with subtle elevation: box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.04), 0 1px 2px rgb(0 0 0 / 0.06), 0 12px 32px -16px rgb(0 0 0 / 0.35). Light-mode variant drops the dark drop-shadow. .ring-glow also gains an inner highlight.
  • Hero.astro — h1 scales to text-[2.75rem] sm:text-6xl md:text-[5rem] (44 / 60 / 80px) with tracking-[-0.04em] font-semibold leading-[1.02]. Subtitle uses tracking-[-0.011em] and text-base sm:text-lg md:text-xl. Hero padding bumped to pt-24 pb-16 sm:pt-32 sm:pb-20. Trust strip gets a touch more breathing room. Badge gets animate-fade-up.
  • Section.astro — h2 scales to text-[2rem] sm:text-4xl md:text-[3rem] (32 / 36 / 48px) with tracking-[-0.035em] font-semibold. Eyebrows tighten to tracking-[0.18em] text-xs. Section padding bumped from py-20 sm:py-28 to py-24 sm:py-32.
  • Subtle entrance animation — .animate-fade-up lifts 8px and fades from opacity 0 to 1 over 600ms with cubic-bezier(0.2, 0.8, 0.2, 1). Applied to the Hero badge for first-paint polish. @media (prefers-reduced-motion: reduce) skips the animation entirely.
  • Verified 2026-08-16: cd landing && make check exits 0; astro build produces 14 pages; astro check reports 0 errors / 0 warnings / 1 pre-existing hint. Structural grep over dist/index.html confirms font preconnect + Google Fonts link, Geist + Geist Mono in --font-sans / --font-mono CSS tokens, Hero h1 text-[2.75rem] sm:text-6xl md:text-[5rem], section h2 text-[2rem] sm:text-4xl md:text-[3rem], and animate-fade-up class on the Hero badge.
  • Next: landing-009 — first real on-niche blog post.
Session 9 · landing-008

Changelog page

  • Phase 8 — Changelog page (landing-008). Built landing/src/lib/changelog.ts (pure parser: extracts session entries under ## Session Log from claude-progress.md) and landing/src/pages/changelog.astro (reads the file at build time via fs.readFileSync, calls the parser, renders newest-first). Single source of truth — every landing-XXX session entry shows up on /changelog automatically.
  • Parser behavior: narrow + lenient. Handles empty input, missing ## Session Log section, missing Date: line, and unknown header shapes by degrading gracefully. Multi-line wrapped bullets are joined into a single string per bullet; meta-bullets (Date:, Branch:) are filtered out. formatBullet() converts bold and ` code to <strong> and <code>` for inline rendering.
  • Source-of-truth discipline: Normalized Session 002's header from 'Session 002 — Landing page, end-to-end SaaS build (Phase 0 + Phase 1)' to 'Session 002 — Phase 0 plumbing + Phase 1 hero (landing-001)' so it shows up automatically under the new convention (the old form had no feature ID and was being skipped). Session 001 (scaffold) is correctly skipped because its header predates the (featureId) convention.
  • Newest-first ordering: Session 8 (Compare + Contact) renders first; Session 2 (Phase 0 plumbing + Phase 1 hero) renders last. Parser already returns newest-first because new sessions are prepended to claude-progress.md — no client-side reversal needed.
  • Footer: added a 'Changelog' link under Resources (between Blog and RSS feed).
  • Verified 2026-08-16: cd landing && make check exits 0; astro build produces 14 pages (was 13); astro check reports 0 errors / 0 warnings / 1 pre-existing hint; file count grew from 48 to 50. Structural grep confirms all 7 landing sessions render in newest-first order with the right feature IDs, titles, and dates.
  • Next: landing-009 — first real on-niche blog post (carry-over from feature-001).
Session 8 · landing-007

Compare + Contact

  • Phase 7 — Compare + Contact (landing-007). Built two new pages and extended the lead-capture seam.
  • /compare — 4-column matrix (Scraper + Apollo + ZoomInfo + Spreadsheets) over 10 capability rows. Each cell typed as yes | no | partial. Closing card explains where Scraper is different (vs Apollo's sequence-first and ZoomInfo's data-vendor models). Reads niche.competitors.
  • /contact — the page the Team CTA already pointed to from landing-005. Form has name (optional) + email (required) + message (required) and submits via the existing captureLead seam with source: 'contact'. Inline <script type="module"> (Astro bundles it) wires submit → track('contact_submit', ...) → captureLead → success / error feedback. Aside panel shows three mailto cards (security / privacy / legal) so the right question goes to the right inbox.
  • niche.ts — competitors field type changed from string[] to Competitor[] (each entry has name + blurb); populated with Apollo, ZoomInfo, Spreadsheets. Lead interface in leads.ts gained optional message? field.
  • Verified 2026-08-16: cd landing && make check exits 0; astro build produces 13 pages (was 11); astro check reports 0 errors / 0 warnings / 1 pre-existing hint; file count grew from 46 to 48. Structural grep over dist/compare/index.html and dist/contact/index.html confirms the matrix renders all 10 rows and the contact form bundles correctly.
  • Next: landing-008 — /changelog page + a landing/src/lib/changelog.ts loader that parses root claude-progress.md at build time.
Session 7 · landing-006

Security + legal stubs + JSON-LD

  • Phase 6 — Trust page, legal stubs, and SoftwareApplication JSON-LD (landing-006). Created three new pages and wired a global JSON-LD block into BaseHead.astro.
  • /security — 6 sections (Data locality, Processing, Encryption, Access control, Audit logging (planned), Reporting a vulnerability) rendered as card-surface panels with numeric eyebrows. Ends with a CTA card linking to mailto:security@scraper.example (placeholder).
  • /privacy — 4 sections (What we collect, What we do not collect, How we use it, Your choices). Clearly marked 'Placeholder — needs legal review before launch' so the page never presents itself as a finished policy. Links to mailto:privacy@scraper.example.
  • /terms — 5 sections (Service description, Accounts, Acceptable use, Liability, Changes). Same 'Placeholder — needs legal review' banner. Links to mailto:legal@scraper.example.
  • BaseHead.astro now imports niche + SITE_URL, builds a SoftwareApplication JSON-LD object (applicationCategory BusinessApplication, operatingSystem 'Chrome (Chromium 114+)', offers derived from niche.pricing with parsed price + cadence category), and emits it via <JsonLd schema={softwareAppSchema} />. Renders on every page because the description is global, not per-page.
  • Footer.astro grew a third 'Legal' column with Privacy + Terms, and a 'Security' link under Resources. The four-column Product / Resources / Legal layout reads cleaner than the previous three.
  • Verified 2026-08-16: cd landing && make check exits 0; astro build produces 11 pages (was 8); astro check reports 0 errors / 0 warnings / 1 pre-existing hint; file count grew from 43 to 46. Structural grep over dist/{index,about,security,privacy,terms}/*.html confirms the JSON-LD block on every page and each page's distinctive section headings.
  • Next: landing-007 — /compare page + /contact form extending landing/src/lib/leads.ts.
Session 6 · landing-005

Pricing rewrite

  • Phase 5 — Pricing rewrite (landing-005). Rewrote Pricing.astro with a billing toggle (Monthly / Annual), a feature comparison table, and a Team CTA that points to /contact (the page itself is built in landing-007; for now the link 404s, which is fine).
  • Toggle behavior: A vanilla <script> (bundled inline by Astro at the bottom of the pricing section) reads data-monthly and data-annual from .tier-price elements and swaps the displayed text when a .billing-pill is clicked. The toggle only affects subscription-style tiers: Solo stays $0, Calling stays $0.012, Team swaps between $49 and $40.67 (= 49 × 0.83). A small CSS block styles the pill states (active = primary fill).
  • Comparison table: Reads niche.pricingComparison — populated with 13 rows in 4 groups (Harvest, Pipeline, Workspace, Telephony). Calling column gets an 'add-on' hint because it's an overlay tier, not a replacement. Cells render as Icon name="check" for true, em-dash for false, or string text for the optional string variant. Table is overflow-x-auto with min-w-[640px] so it scrolls horizontally on narrow screens rather than wrapping awkwardly.
  • PricingTier interface: Added optional ctaHref?: string field. Team tier sets ctaHref: '/contact'; other tiers fall back to niche.cta.href.
  • Verified 2026-08-16: cd landing && make check exits 0; astro build produces 8 pages; astro check reports 0 errors / 0 warnings / 1 pre-existing hint. Structural grep over dist/index.html confirms the toggle markup (role=tablist, two pills, Save 17% badge), the inline <script type="module"> toggle script, all 13 comparison rows with correct check / em-dash cells, the Team CTA href="/contact", and that Solo + Calling prices stay static when the toggle is flipped.
  • Next: landing-006 — /security + legal stubs + SoftwareApplication JSON-LD in BaseHead.astro.
Session 5 · landing-004

Integrations + Use cases

  • Phase 4 — Integrations + Use cases (landing-004). Built Integrations.astro (8-card grid: Chrome, Google Maps, Google Search, Carrier-grade calling, Stripe, Excel, Webhooks, CSV/NDJSON — each with icon, name, and a one-line 'what does Scraper do with it' note) and UseCases.astro (3-column persona cards: Agencies, In-house SDR teams, Solo operators — each with numbered persona badge, icon, title, and body paragraph).
  • New types already in niche.ts were used: Integration and UseCase. Populated niche.integrations with 8 entries and niche.useCases with 3 entries. Both sections hide themselves when their array is empty (same {hasX && ...} discipline as Testimonials, HowItWorks, DeepDives, CompactGrid).
  • New icons added to Icon.astro: chrome, credit-card, file-spreadsheet, webhooks, file-text, arrow-up-right. Used existing building, users, zap for the use-case personas.
  • Page order: index.astro now renders Hero → HowItWorks → DeepDives → CompactGrid → Integrations → UseCases → Testimonials → Pricing → FAQ → Newsletter → CTA. The integrations strip and use cases sit between the compact feature grid and the testimonials — closer to Pricing makes sense because both sections answer 'will this fit my stack / my team' alongside the price question.
  • Removed a duplicate-key error: the niche object already had empty placeholders integrations: [] and useCases: [] further down — my edit added populated copies and TS flagged the duplicate keys. Removed the empty placeholders since the populated ones now sit in the right place (after the deep-dives data, not after steps).
  • Verified 2026-08-16: cd landing && make check exits 0; astro build produces 8 pages; astro check reports 0 errors / 0 warnings / 1 pre-existing hint. Structural grep over dist/index.html confirms the page order, all 8 integration names, all 3 use-case personas and their distinctive taglines.
  • Next: landing-005 — Pricing rewrite with annual toggle + comparison table.
Session 4 · landing-003

Feature deep-dives + compact grid

  • Phase 3 — Deep-dives + compact grid (landing-003). Built 4 deep-dive showcase sections (Harvest, Pipeline, Dialer, Analytics) and a 4-card compact grid (Save pill, Email lookup, Export, RBAC). Created 4 mock components in landing/src/components/mocks/:
  • HarvestMock — browser chrome + compact side panel (3 leads) + faux map with 5 pins (2 of them labelled "Save" to mirror the Save pill on Maps place panels) + a "Sweeping · 47/120" progress label.
  • PipelineMock — 4-column Kanban (New 18, Contacted 14, Qualified 9, Won 6) with lead cards (Bella's Bakery, Joe's Pizza, Sunrise Dental, Anvil Hardware, Pinnacle LLC, etc.) and a "New view" toolbar button.
  • DialerMock — the actual dialer surface: lead on top (Bella's Bakery, +1 415 555 0142), 00:42 timer in mono, recording indicator, Hang up + Outcome action bar, and a 4-item queue with the current lead highlighted.
  • AnalyticsMock — 2x2 widget grid on a filter bar: bar chart (Pipeline by stage), stat (Connect rate 23% with up-arrow), line chart (Calls last 7 days with gradient fill), funnel (Pipeline funnel).
  • Alternating layout: lg:order-2/lg:order-1 flips the visual side on every other deep-dive — Harvest/Dialer have mock-on-right; Pipeline/Analytics have mock-on-left. Generous gap-20/gap-24 between deep-dives so the eye zigzags down the page.
  • New types added to niche.ts: DeepDive (eyebrow, title, body, bullets, icon, mock kind) and CompactFeature (title, body, icon). New NicheConfig fields: deepDives?, compactFeatures?. Both sections hide themselves when their array is empty (same {hasX && ...} discipline as Testimonials and HowItWorks).
  • Page order: index.astro now renders Hero → HowItWorks → DeepDives → CompactGrid → Testimonials → Pricing → FAQ → Newsletter → CTA. FeatureGrid is no longer imported.
  • Verified 2026-08-16: cd landing && make check exits 0; astro build produces 8 pages; astro check reports 0 errors / 0 warnings / 1 pre-existing hint. Structural grep over dist/index.html confirms the page order, all 4 deep-dive titles, all 4 compact-grid titles, all 4 mocks' distinctive content, and the alternating layout.
  • Next: landing-004 — integrations strip + use cases.
Session 3 · landing-002

How it works

  • Phase 2 — How it works (landing-002). Built HowItWorks.astro — a 4-step numbered band (Sweep the map → Enrich the rows → Dial the queue → Watch the board) with step-specific mini-mocks: Sweep shows a faux map with 6 pins and a progress label; Enrich shows a Bella's Bakery row with phone ✓, email ✓, crawling site… chips and a progress bar; Dial shows a connected call with 00:42 timer and a red Hang up button; Watch shows a 7-day bar chart with a connect-rate footer. Each step carries a numeric badge (01–04), the icon, a title, and a one-sentence body. Section reads niche.steps; hides itself when the array is empty (same {hasSteps && ...} discipline as Testimonials). Populated niche.steps with the 4 entries. Added <HowItWorks /> to index.astro between <Hero /> and <FeatureGrid />.
  • Responsive grid: grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 — single column on mobile, 2-up on tablet, 4-up on desktop. The group-hover cosmetics on the icon span are wired correctly.
  • Verified 2026-08-16: cd landing && make check exits 0; astro build produces 8 pages; astro check reports 0 errors / 0 warnings / 1 pre-existing hint. Structural grep over dist/index.html confirms the ordered list, all 4 step titles, all 4 crop bodies, and the section anchor id="how-it-works".
  • Next: landing-003 — feature deep-dives (4 alternating showcase sections + 4-card compact grid).
Session 2 · landing-001

Phase 0 plumbing + Phase 1 hero

  • Phase 0 — plumbing. BLUEPRINT.md filled in and approved by the owner. The full plan is in plan-landing-redesign.md (10 features). All 10 added to feature_list.json; landing-001 (Hero) is the active item.
  • Phase 1 — Hero (landing-001). Replaced the faded 3-card "product mock" with a real extension side-panel mock (ProductMock.astro) showing a saved region, a map preview with pins, a list of leads with phone numbers and stage chips, and the action bar. Tightened the hero copy: new eyebrow ("A Chrome extension + a SaaS workspace"), sharpened subhead, new trust strip ("Free forever, no credit card · MV3 · Chrome 114+ · Your data, in your browser · In-browser calling"), and a "See it work" secondary CTA that smooth-scrolls to the mock. Added shield and lock icons so the trust strip and the future security work can render without inventing glyphs.
  • Pricing placeholders. Per the owner's "add some random pricing" instruction, niche.pricing now carries $0 / $49 / $0.012 for Solo / Team / Calling. The numbers are placeholder and flagged in DECISIONS.md. The annual toggle + comparison table are scheduled for landing-005 and will read pricingAnnualMultiplier = 0.83.
  • New optional fields added to NicheConfig: steps, integrations, useCases, metrics, pricingAnnualMultiplier, pricingComparison. Each is read by its section only; sections hide themselves when the field is empty, mirroring the existing testimonials discipline.
  • Verified 2026-08-16: cd landing && make check exits 0; astro build produces a clean dist/. Hero renders in both themes at 1280 / 1024 / 414 widths. Trust strip wraps clean to two rows on mobile. Product mock keeps its 5:1 ratio on desktop and shrinks to a single column on mobile.
  • Next: landing-002 — the HowItWorks 4-step band.
  • ### Session 001 — Scaffolded from harness-core
  • Goal: Establish a clean, verifiable baseline for agent-driven work.
  • Completed: Project scaffolded with a complete harness (AGENTS.md, CLAUDE.md, init.sh, Makefile, feature_list.json, and the continuity/checklist artifacts).
  • Verification: run ./init.sh and confirm it exits 0.
  • Next action: read feature_list.json, pick the highest-priority unfinished feature, and implement exactly one before stopping.

Source: landing/claude-progress.md. Parsed at build time by lib/changelog.ts.