I shipped a dating app five months ago. The matching engine is one Postgres function, a 100-line edge function, and a launchd job on my desk that hits a route every hour. No queue, no worker, no fancy ML stack. Here is the whole thing in order, and the small disaster that taught me to move the cron off Vercel.

What a "match" actually is

In most dating apps a match is a mutual swipe. In ours a match is a row in a suggested_matches table with a score above a threshold. Two profiles, one float in [0, 1], and a reason that gets shown to both sides.

The pipeline that creates that row is short.

launchd (hourly, on my Mac)