Canadeal — Automated Deal Aggregation
The problem
Finding good deals for Canada's Chinese-speaking community meant manually searching fragmented sources, rewriting product descriptions, and posting across multiple platforms by hand — every single day. The real problem wasn't just volume — it was that every step of the pipeline required a human decision.
What I built
Designed and built the entire platform from architecture to deployment. The pipeline runs across multiple stages, each built to handle failure gracefully and operate without manual intervention.
Crawling: Distributed Python + Playwright crawler workers bypass Amazon bot-detection via Chrome DevTools Protocol. Workers run across two machines with distributed locking mechanisms (Redis-backed) to prevent concurrent data conflicts and duplicate processing. Scheduling, monitoring, and logging are built in — failures surface immediately rather than silently corrupting data.
Data pipeline: Raw posts are always preserved before any processing — if the frontend surfaces a bad record, I can back-trace to the original crawl and correct it without data loss. A two-layer normalization pass cleans and standardises incoming data before it enters the main store. Deduplication handles both exact matches and the harder case: the same deal arriving from different channels with different titles, prices, or metadata — the system automatically reconciles these rather than creating duplicates.
Verification: A separate automated Amazon crawler re-checks live prices after ingestion, catching deals that expired between crawl and publish.
AI layer: A pluggable AI-provider layer (OpenAI / Claude / Deepseek, hot-swappable via one env variable) auto-generates Traditional Chinese titles, categories, and feature summaries. Prompt engineering was iterative — tuning for minimum token cost, maximum throughput, and output quality simultaneously, since all three pull in different directions.
Infrastructure: FastAPI backend + Next.js 14 frontend, containerized with Docker Compose, running on a self-managed Linux server. Redis caches hot queries to reduce database load and improve frontend response times. Meilisearch replaced Elasticsearch for full-text search — lower resource usage on the server, no credential management overhead. Facebook Graph, Instagram Stories, and Threads APIs handle scheduled auto-posting. Monitoring and logging added later to make system health observable at a glance.
Manual work it replaces
Manual deal hunting, manual description rewriting, manual translation, manual deduplication, manual social posting — the entire content pipeline now runs on its own across two machines.
What I learned
Distributed systems fail in ways single-machine systems don't — distributed locking was not an afterthought, it was necessary. Preserving raw data before processing turned out to be the right call more than once; the ability to back-trace and reprocess saved data that would otherwise have been lost. Prompt engineering for production is a different problem than prompt engineering for demos — cost, speed, and quality all degrade each other, and finding the right balance requires real measurement. Proactive security work matters: I audited the system myself and patched 3 critical vulnerabilities including hardcoded DB credentials, an X-Forwarded-For rate-limit bypass, and an XSS-readable admin key.
Built with
- Python
- FastAPI
- Next.js
- TypeScript
- MongoDB
- Redis
- Meilisearch
- Playwright
- Docker
- Linux
- OpenAI
- LLM
Status
Live at canadeal.ca.