What it does
PrijsVink collects product and price information from major Dutch supermarkets and lets you search and compare them in one place. Behind the search box: retailer data ingestion, product normalization, promotion handling, a Rust API and a public web application.
Architecture

- Python scrapers collect product information and prices.
- SQLite stores products and prices.
- Rust (Axum) serves the API, opening the database read-only.
- React frontend on GitHub Pages.
Key decisions
Ship the database inside the image. The production API only reads, so a SQLite snapshot is packaged into the same Docker image as the API. No database server, no persistent disk, and every deployment is one predictable artifact. The trade-off: publishing new data means building and deploying a new image.
Keep the image private. The API exposes prices publicly, but the full database file shouldn't be a downloadable artifact, so the image lives in a private GitHub Container Registry and Render pulls it with credentials.
Accept free-tier trade-offs, knowingly. Render's free tier spins services down after inactivity, so the first request can be a cold start, and deploys are triggered manually. Fine for a side project; the upgrade path is clear when it matters.
Search
Search originally used repeated substring matching. Replacing it with SQLite's FTS5 full-text index reduced search latency by roughly 10× in current tests.
What's next
Automating image builds and deploys with GitHub Actions, and reducing the image size. The full deployment story, including a SQLite connection bug and how it was fixed, is in the blog post.