What We Built (in planning)
A personal web app that searches eBay for watch listings — capturing both active listings (asking prices) and completed/sold listings (actual sale prices) — and stores comprehensive details to help track market value and time purchases.
Core Value
"Know what a watch actually sells for (not just what people ask) so you can time purchases well and understand what your collection is worth."
Key Features
🔍 Search & Ingest — eBay search returning both active and sold/completed listings with full details: title, price, condition, images, seller, URLs
📁 Saved Searches — Named, persistent searches tagged as "Wishlist" or "Research" — unified concept with target price threshold and notes
📈 Price History — Timestamped snapshots on every background refresh, displayed as Chart.js line charts with avg/median sold price
💼 Portfolio — Track owned watches with purchase price linked to live market data for real P&L tracking
🔔 Alerts — In-app price drop indicator when a saved search's average sold price drops below a configurable threshold
⏰ Auto-Refresh — Background APScheduler job refreshes all saved searches daily; macOS launchd ensures it survives reboots
Tech Stack
Chosen through parallel research agents investigating stack, features, architecture, and pitfalls:
findCompletedItems) was decommissioned February 5, 2025.
Sold/completed listing data now requires HTML scraping via ?LH_Sold=1&LH_Complete=1.
The research agents caught this before any code was written — saving a full rework of the data layer.
How Claude Code Was Used
This project used the GSD (Get Shit Done) workflow — a set of Claude Code skills that structure software projects from idea to executable plans. Here's the sequence:
Deep Questioning (/gsd:new-project)
Claude asked targeted follow-up questions to extract what mattered: sold vs. active prices, wishlist vs. portfolio distinction, alert delivery, data refresh model. Not a form — a conversation.
Parallel Research (4 agents)
Four specialist agents ran simultaneously — Stack, Features, Architecture, and Pitfalls — each writing a research document. A fifth synthesized them into a SUMMARY.md.
Requirements Definition
Research findings drove a structured requirements session. 21 requirements scoped with REQ-IDs, organized by category, with explicit v2 and out-of-scope sections.
Roadmap Creation (gsd-roadmapper agent)
A specialized agent decomposed requirements into 4 phases with observable success criteria — each requirement mapped to exactly one phase, 100% coverage verified.
Phase Research + Planning + Verification (/gsd:plan-phase 1)
Phase-specific researcher confirmed eBay API status live. Planner created 3 executable PLAN.md files. Plan checker verified all requirements covered, dependencies correct, tests mapped.
The key insight is separating "what to build" from "how to build it". The new-project flow forces you to answer the hardest questions (scope, constraints, core value) before any code is written. By the time you get to execution, there's nothing left to guess — each plan is a specific, verifiable, ordered set of tasks with known dependencies.
How the Conversation Went
The initial prompt was intentionally vague. Claude used the GSD questioning workflow to extract what was actually needed. Here's the key exchange:
From there, Claude asked 6 structured questions (using an interactive UI) to extract:
Purpose
Both buying research + portfolio tracking
Interaction model
Search-driven (not a fixed watchlist)
Interface
Web app in browser
Alerts
In-app price drop alerts only
Portfolio type
Owned watches + wishlist (both)
Data refresh
Scheduled auto-refresh
The entire requirements and roadmap session then ran without further input. Claude handled all the scoping, research, and planning autonomously — only surfacing decisions that required human judgment.
The opening prompt was deliberately vague — "I want to build an app..." You don't need a detailed spec to start. The GSD workflow is designed to extract the spec through conversation. The more specific your opening prompt, the less value the questioning phase adds. Start with the idea; let Claude ask what matters.
What Was Produced
Every artifact was committed to git automatically after it was created.
📋 Requirements (21 total)
| ID | Requirement | Phase |
|---|---|---|
| INGEST-01 | User can search eBay by keyword and view active listings | 1 |
| INGEST-02 | User can view completed/sold listings separately from active | 1 |
| INGEST-03 | Each listing stores title, price, condition, images, seller, URL, date | 1 |
| INGEST-04 | Box & papers auto-detected from listing title keywords | 1 |
| SCHED-01 | System auto-refreshes all saved searches on a background schedule | 2 |
| SCHED-02 | UI shows "last refreshed" timestamp per saved search | 2 |
| SCHED-03 | Scheduler persists on macOS via launchd | 2 |
| SRCH-01 | User can save a named search query | 3 |
| SRCH-02 | User can tag searches as "Wishlist" or "Research" | 3 |
| SRCH-03 | User can set a target price threshold on a saved search | 3 |
| SRCH-04 | User can add notes to a saved search | 3 |
| SRCH-05 | User can view current eBay listings per saved search | 3 |
| PORT-01 | User can add owned watch with purchase price + notes | 3 |
| PORT-02 | User can link owned watch to saved search for market value | 3 |
| PORT-03 | Portfolio shows purchase price, market value, P&L | 3 |
| HIST-01 | System stores timestamped price snapshots per refresh | 4 |
| HIST-02 | User can view price history chart for any saved search | 4 |
| HIST-03 | Average / median sold price displayed per saved search | 4 |
| ALRT-01 | User can enable price drop alerts on a saved search | 4 |
| ALRT-02 | System detects drops vs. previous price snapshot | 4 |
| ALRT-03 | In-app alert indicator appears after a drop is detected | 4 |
🗺 Roadmap — 4 Phases
Foundation
eBay API client (Browse API active + HTML scraper for sold) + SQLite schema with sold/active price separation baked in from day one
Core Loop
APScheduler in FastAPI lifespan, ingest pipeline, launchd macOS persistence, basic web UI proving end-to-end data flow
Saved Searches & Portfolio
Named persistent searches with wishlist tagging, portfolio with purchase price vs. current market value P&L
Analytics & Alerts
Chart.js price history charts, avg/median sold price, configurable price drop alerts with in-app notification indicator
📄 Phase 1 Plans (3 executable)
01-01 · Wave 1 — eBay API Verification Spike
Investigation task, not a coding task. Output is a SPIKE.md document confirming live CSS selectors for eBay's sold-listings HTML, OAuth token lifetime, and API quotas. Plans 01-02 and 01-03 depend on this output.
01-02 · Wave 2 — DB Schema + Project Scaffold
pyproject.toml, SQLModel models (Listing with separate listing_type field), Alembic migrations, Wave 0 pytest stubs. Requires spike output to finalize nullable fields for scraped sold-listing data.
render_as_batch=True required for SQLite+Alembic ALTER TABLE01-03 · Wave 3 — eBay API Client
OAuth token manager with proactive 5-min-before-expiry refresh, Browse API client for active listings, HTML scraper for sold listings using spike-confirmed selectors, normalization layer, manual search CLI script for testing.
What This Shows About Claude Code
Plan 01-01 is an investigation, not an implementation. It produces a document, not code. This is the spike pattern — a time-boxed task to resolve a critical unknown before committing to architecture. Claude structured this explicitly because the research flagged eBay's Finding API deprecation as unverified. The plan checker validated this wave ordering was correct.
The initial STACK.md recommended the eBay Finding API. The phase-specific researcher went further — fetching live eBay developer docs — and discovered it was decommissioned 5 weeks ago. Without this research step, the first implementation attempt would have failed and required a full data-layer rework.
Research surfaced something the user hadn't explicitly said: a "wishlist item" is just a saved search with extra context. Instead of building two separate data models, Claude proposed a unified model and confirmed it with the user. This kind of scope consolidation reduces code complexity without losing functionality.
The requirement to separate sold prices from active asking prices was treated as
a schema-level constraint, not a display concern. The plan checker
explicitly verified that listing_type was structurally separate in the Listing
model — not a single price field that gets filtered in a WHERE clause.
Getting this wrong early would have required a data migration later.
The global CLAUDE.md included this instruction: "When starting Claude in an empty or
nearly empty folder (no existing source code), automatically invoke /gsd:new-project."
Claude detected the empty directory and triggered the full planning workflow without being
asked. You can encode your own team conventions and defaults into CLAUDE.md.