- SyncToSheet.vue: add "Download Excel" export alongside Copy rows,
using exceljs (dynamically imported to avoid bundling ~940KB into
AnalysePage) instead of xlsx (unpatched high-severity CVEs)
- appscript/Sync.gs: rewrite the Sheet-pull layout from column-per-field/
row-per-competitor to the transposed layout (fields down column A,
one column per competitor) — matches the dashboard's Copy rows/Excel
export and the real legacy client reference sheet, which the old
layout was never actually reconciled against. Row detection is now
label-based and self-bootstraps a blank template on first pull.
- CLAUDE.md: correct §15 to document the transposed layout instead of
the stale column-per-field description
- battlecard_service.py: replace two hardcoded placeholder strings
(positioning_summary, recent_changes) with real computed data —
actual price_history-derived recent changes, and richer product
summaries (service levels, target audience, activities). Raise
BATTLECARD_PRODUCT_LIMIT 10->50 and loosen prompt word caps so the
richer input isn't compressed away
- BattlecardCard.vue: render pricing_observation, generated but never
displayed before
- pb_migrations/009: fix battlecards.generated_at to stamp on update,
not just create, so regenerated battlecards show an accurate
"Updated" timestamp
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Implements CLAUDE.md Build Order Phase 1 end to end:
- PocketBase migration covering all 15 MVP-scope collections
- Repository layer (11 repos) with real PocketBase-backed + in-memory
mock implementations for every collection
- Service layer (licence, trip-finder, battlecard, embedding, brief,
alert, analysis, onboarding, billing, auth) — Phase 2 scraping/
extraction dependencies are lazy-imported so this layer is fully
testable ahead of the app.py refactor
- Flask API (api.py) covering every MVP route from the spec, with
X-API-Key auth, Flask-Limiter rate limits, and structured JSON errors
- RQ job queue (jobs.py) with per-competitor failure isolation and
duration-based Gotify alerting
- 142 tests, 95% coverage, 100% on licence validation / seat
management / Stripe webhook dispatch per CLAUDE.md's testing floor
/sheet/push and /sheet/tabs intentionally return structured 501s until
the Apps Script Web App deployment exists (Phase 4).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>