Commit Graph

2 Commits

Author SHA1 Message Date
JasonFraser ad1d7f1815 Fix critical scrape-targeting bug and harden proxy, matching, and dashboard reliability
The highest-impact fix: run_research_job() only ever read entry['id'] from
confirmed competitors, silently discarding the Firecrawl-matched or
manually-swapped URL — every scrape fell back to the competitor's bare
root domain regardless of what was confirmed. This explains most of the
"unpredictable/wrong data" behavior seen against the old app.py. Threaded
confirmed_url through jobs.py -> analysis_service.py so the actually
confirmed page is what gets scraped.

Other fixes bundled in this pass:
- Proxy layer: Webshare rotating-gateway country code lowercased (was
  silently failing auth), Bright Data port corrected to 33335 (current
  cert), dedicated-IP candidate rotation added before falling back to the
  shared gateway/Bright Data escalation.
- Trip-intent matching: score_and_rank_urls() now hard-gates on
  destination keyword and excludes bare root-domain candidates, instead
  of letting duration/category signals alone push a wrong-country or
  homepage URL over the confidence threshold.
- force_refresh cache-bypass toggle added (opt-in, collapsed "Advanced
  options"), plus a "Skip this competitor" affordance for unmatched URLs.
- De-hardcoded "G Adventures" (the hackathon reference client) out of the
  extraction prompt — now uses the real tenant's company name.
- RunHistory/Apps-Script "latest results" queries filtered to
  triggered_by = "manual" so per-competitor content-hash bookkeeping rows
  no longer drown out real batch runs.
- Dashboard fixes: stuck-state bug on revisiting the Analyse page,
  AccountPage/BattlecardsPage restacked to single-column layout, Alerts
  moved to a header bell dropdown, invisible Export/Run Analysis icons
  (fill -> stroke), tour popup width mismatch, horizontal-scroll bug on
  cards (missing min-width: 0 in flex layout).
- New PocketBase migrations for scrape_runs (content_hash fields,
  tab_type, created_by_email) and products (departures, start_days).

335 backend tests passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-04 17:33:05 -04:00
JasonFraser 11610b8b4a Phase 3: Vue 3 + Nuxt UI v4 dashboard
Implements CLAUDE.md Build Order Phase 3 — the 7-page dashboard,
matching the approved bettersight-dashboard.html mockup's design
system (dot-grid motif, dark sidebar, card shadows, badges) exactly.

Scope note: nuxt-ui-templates/dashboard-vue (the template CLAUDE.md
says to clone) ships entirely in TypeScript, which directly conflicts
with §18's "JavaScript only, no .ts files" rule. Per user decision,
converted the template to plain JS and rebuilt the dashboard chrome
(sidebar/topbar) as custom components matching the mockup instead of
Nuxt UI's own dashboard components, since the mockup is the approved
design (§25) and Nuxt UI's dashboard components have their own default
look that would fight against it.

- Core plumbing: pocketbase.js client, api_service.js (X-API-Key +
  JWT + 401-refresh interceptor), auth_store/analysis_store/
  notifications_store (Pinia), 5 repositories, explicit vue-router
  (v4, not v5 — matching CLAUDE.md's stack table) with an auth guard
- Shared components: programmatic DotGrid.vue, StatCard, EmptyState,
  CompetitorForm, SeatManager, BattlecardCard, SubscriptionCard,
  CsvUpload+ImportPreviewModal, FeedItem, AlertCard
- All 7 pages: Login (+Google OAuth, forgot password), ResetPassword,
  Account (subscription, upgrade prompt, seats, onboarding), Competitors
  (CSV bulk import), Analyse (full find-urls → confirm → poll → results
  → confidence → push-to-sheet flow with all 4 JobProgress terminal
  states), Activity (stat row, feed, alerts, onboarding tour trigger),
  Battlecards
- Shepherd.js 5-step onboarding tour ported verbatim from §21
- Sentry init (prod-only) + global error handler in main.js

Two backend gaps surfaced and fixed while building this:
- Added GET /account/me (dashboard had no way to learn its own
  tenant_id after login) and fixed GET /account/<tenant_id> to verify
  the session's tenant matches the requested one (previously any valid
  X-API-Key could read any tenant's account data)
- Added GET /alerts and PATCH /alerts/<id>/read (no route existed to
  list or acknowledge alerts, needed by the sidebar badge and
  ActivityPage's alerts panel)

Deliberately deferred: the mockup's Price Position sparkline/corridor
card has no defined data contract anywhere in CLAUDE.md — omitted
rather than backed with fabricated numbers. /sheet/push and
/sheet/tabs still return their Phase-1 structured 501 pending Phase 4.

Verified: full production build succeeds, dev server serves the login
page correctly (screenshotted, zero console errors), and the router's
auth guard correctly redirects an unauthenticated session to
/login?return=... with no console errors. Backend: 202 tests still
passing after the two route additions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 13:16:31 -04:00