Data and analytics

Used car price tracker with deal scoring

Python and Postgres pipeline that scrapes used car listings, stores price history, and scores whether each listing is a good deal.

pythonpostgrespsycopguvpytestruff

Built 1 time, downloaded 0 times.

Install from your terminal

Run this in your project folder. It signs you in, shows what changes and asks before it overwrites a file.

npx claude-lab add used-car-price-tracker-with-deal-scoring-1bdb1c
10 filesDownload zip
CLAUDE.md
# Used car price tracker

This tool tracks used car prices for a few models across listing sites. It stores each listing and its price history in Postgres, then scores each listing against comparable cars to answer one question: is this listing a good deal or not. Requirements are in SPEC.md and the build order is in PLAN.md.

## Stack

- Python 3.12, managed with uv
- Postgres, accessed with psycopg 3
- SQL migrations in db/migrations/
- pytest for tests, ruff for lint and format, mypy for types

## Layout

- src/the app/scrapers/: one module per listing site
- src/the app/normalize.py: price, mileage, year, and model cleanup
- src/the app/db/: connection, queries, migration runner
- src/the app/scoring.py: comparables and deal score
- src/the app/cli.py: the `the app` command
- models.yaml: tracked models and canonical names
- tests/: test files; tests/fixtures/ holds saved HTML and JSON
- db/migrations/: numbered SQL files

## Commands

- `uv sync`: install dependencies
- `uv run pytest -q`: run tests (uses the carprice_test database)
- `uv run ruff check .` and `uv run ruff format --check .`: lint and format check
- `uv run mypy src`: type check
- `uv run the app migrate`: apply migrations
- `uv run the app scrape --site SITE --dry-run`: parse a site without writing to the database
- `uv run the app score`: score current listings

## Working rules

- Run the verify skill before saying any task is done.
- Explain changes to the user in 3-5 plain lines: what changed and why.
- Ask before adding a dependency, running `git commit` or `git push`, or running `uv add`.

## Scraping rules

- Tests use saved fixtures in tests/fixtures/. Never call a live site from tests.
- Respect robots.txt and each site's terms.
- Wait at least 2 seconds between requests to the same site.
- Set a user agent and use timeouts with retries and backoff.
- Listings change or disappear. Dedupe on (site, listing_id).
- Never overwrite a price. Insert a price_history row when the price changes.

## Data rules

- Store price as an integer in whole currency units.
- Store mileage in km. Convert miles before saving.
- Map trim, year, and model to canonical names using models.yaml.
- Treat a missing or zero price as missing data, not as a value.

## Scoring rules

- Comparables: same model, year within +/-1, and a similar mileage band.
- Compare the listing price to the median of its comparables.
- Require a minimum sample size. If there are too few comparables, return "not enough data". Do not guess.
- Keep thresholds in config, not in code.
- Details and edge cases are in .claude/skills/score-deals/SKILL.md.

## Database rules

- Make every schema change in a new numbered migration file in db/migrations/.
- Never edit a migration that has already been applied.
- Read DATABASE_URL from the environment. In docs, use the placeholder YOUR_DATABASE_URL.
- Never commit .env or any real connection string.
- Never run destructive SQL (DROP, TRUNCATE, or DELETE without WHERE) against anything except the local carprice_test database. Ask first.
- Use parameterized queries only.

## Review

@REVIEW.md

## More detail

- SPEC.md: requirements and acceptance criteria
- PLAN.md: four build phases, each with a /goal prompt
- INSTALL.md: setup steps for a new machine
Use for my project