the challenge
Most dating apps measure success in messages. Matcha measures it in dates that actually happen. Two people like each other, each pays €10 (a drink included), each picks the evenings they're free, and Matcha books a table at a partner venue in Milan. A short chat opens two hours before the date and closes an hour after it.
A dating app that ends at a real table carries more weight than a chat app. From the first release it needed:
- Payments that count. A match counts as paid only when Stripe says so, never because the app claims it.
- Private availability. Two people's free evenings are matched without either one seeing the other's.
- Safety from day one. Identity checks, reports, blocks and moderation, because strangers meet face to face.
- A venue network run by one person. Bookings and reports need a work queue, not a custom CRM.





the architecture
The app may express intent, but only the server records facts. —
ARCHITECTURE.md
The app is a thin Expo / React Native client that talks straight to Supabase with the user's session. Postgres is the single source of truth. The app can like a profile, submit free evenings or send a chat message. It can't mark a match as paid, change its status, grant a credit or suspend anyone. Row-level security enforces that, not code review.
Edge Functions are the only door to the outside world: Stripe for payments, Didit for identity checks, OneSignal for push, PostHog for analytics. Timed work like daily match pools, match expiry and the chat window runs on pg_cron.
a match, step by step
Every match moves through a fixed set of states, and the app writes none of them. Both people share one 24-hour clock from the moment they match.
- Pending payment. Both pay within 24 hours. Moved by Stripe confirming both payments.
- Picking evenings. Each person picks free slots. Moved by the database finding an overlap.
- Finding a venue. An operator books a partner venue. Moved by the operator confirming from Airtable.
- Confirmed. Date, time and place are set. Moved by a scheduled job, two hours before.
- Chat open. A short chat for last-minute logistics. Closed by a scheduled job, an hour after.
- Completed. Feedback opens. A no-show earns the other person a free date.
Paying comes before picking evenings on purpose. The payment is the moment you commit, and it filters out the matches nobody meant to keep.
manual first
The first design had an algorithm that rotated venues by availability and capacity. We had none of that data and one person running operations, so a decision record cut it: a person books every venue by hand. Airtable is the operators' work queue, and a button on a row calls an Edge Function that moves the match forward. Slack is the alarm bell when money or safety needs a human. The algorithm is deferred, not deleted.
who writes the code
A task is ready when a new agent can finish it without asking product or technical questions. —
AGENTS.md
Mostly agents. Every issue carries an area label and an autonomy label. An issue is supervised when it touches auth, the schema, money, personal data, security, deployment or anything a revert can't undo. There the agent posts a plan and waits for "Approved" before writing code. Everything else runs on auto: the agent takes it through a tested, reviewed pull request and merges it once CI is green. An agent can raise an issue from auto to supervised, never the other way around. When it's stuck, it writes down the options and a recommendation, and stops.
the results
My job is the rules. The rubric decides what an agent may do alone, database permissions make the wrong write impossible instead of unlikely, and the decision records keep the reasoning alive between sessions. Prompts change every week. The rules are what keep the code reading like one engineer's decisions.
121
pull requests merged in 16 weeks
Shipping pace
78%
of pull requests opened by agents
Agent-written
20
architecture decisions on record
Rules in writing


