Matcha
Real-time dating platform, load-tested to 1,000 users
Matcha is the 42 Network dating platform — register, verify, build a profile, discover people, match on mutual likes, then chat, call, and arrange to meet. Around 55,000 lines of TypeScript across a React SPA and an Express/PostgreSQL API, packaged with Docker Compose behind Nginx. Every mandatory requirement is complete and four of the five bonuses shipped; the part I am most pleased with is what came after the features worked — a load test and a metrics stack that turned "it feels fast" into a number, and then into a named bottleneck.
1k VUs · 62 endpoints
Highlights
- 62 REST endpoints over 20 SQL migrations, with 17 repositories separating data access from Express routes
- Real-time layer on Socket.io — presence, read receipts, live notifications — plus WebRTC audio/video from matched chats
- Security by default: SHA-256 hashed sessions, bcrypt + zxcvbn, helmet CSP, rate limiting, parameterized SQL, magic-byte upload validation
- Journey-based k6 load test: 1,080 VUs, 135k requests at 187 req/s, 99.99% of 138k checks passing
- Prometheus + Grafana observability: 90 panels over ~70 metric families, from cgroup CPU throttling to per-statement query time
- Tested at four levels — 59 unit, 29 API permission, 2 SQL/TypeScript parity, 9 Playwright end-to-end — gated in CI
Problem
The subject asks for a complete product rather than a demo: secure auth and email verification, complete profiles, orientation-aware discovery and search, mutual matching, match-gated messaging, live notifications, location with consent, a fame score, and safety tools. Bonuses only count if the mandatory path is flawless, so correctness had to come before anything else — and "correct" includes behaving under load, which nothing in the brief tells you how to check.
Role
Full-stack co-author with Manar Ben Salah at 1337 Khouribga. I owned the identity and profile surfaces including the photo editor, shared the discovery, chat, and real-time work, and built the performance and observability tooling — the k6 suite, the Prometheus exporters inside the API, and both Grafana dashboards.
Architecture
React + Vite SPA against an Express API, both TypeScript, with PostgreSQL reached through 17 repository modules so no route talks to SQL directly. Twenty ordered migrations own the schema. Socket.io carries presence, chat, and notifications; WebRTC handles calls peer-to-peer with the API only brokering signalling. Nginx terminates TLS and fronts both apps, and Docker Compose layers three files — base, observability, load test — so the same stack serves development, monitoring, and performance runs.
Security
Session cookies are httpOnly and sameSite, and stored as a SHA-256 hash so a database leak yields hashes rather than usable cookies. Passwords go through zxcvbn strength scoring before bcrypt. Every query is parameterized; uploads are validated by magic bytes rather than by extension; helmet sets a strict CSP; and the auth routes are rate limited independently of the API. Messaging, calls, and date proposals are gated on a real mutual match, checked server-side on every request rather than hidden in the UI.
Testing
Four levels, all in CI: 59 unit tests across 17 suites for the pure logic; 29 API tests asserting the permission matrix — who may read, message, block, or report whom; 9 Playwright journeys through the browser; and two parity tests that run the fame-rating and match-score algorithms against the SQL functions mirroring them, because the same formula living in TypeScript and in Postgres will drift silently otherwise. CI also runs lint, formatting, both typechecks, and a production build on every push.
Performance
The load test models journeys, not endpoints: a page view costs a session check, an unread count, and a filter-metadata call before its own query, and 5–25 seconds of think time separates journeys so 1,000 virtual users mean 1,000 people rather than 1,000 request loops. Three scenarios run together — browsing, signing in, signing up — for 1,080 VUs, 135,357 requests at 187 req/s, with 99.99% of 138,640 checks passing. It found what guessing would not: p95 of 2.36s against a 1.5s budget, and connection-pool waiters spiking to 17 against a pool of 10 — naming the pool, not the queries, as the first constraint.
Observability
The API exports roughly 70 Prometheus metric families and two provisioned Grafana dashboards read them: one for the running product — users, matches, messages, moderation, per-route latency — and one for load-test runs. The runtime metrics are the ones that answer "why": cgroup CPU throttling, which docker stats cannot show; event-loop utilisation, the real ceiling for a single-threaded runtime; a probe that measures libuv threadpool queueing directly; GC pauses; and pg_stat_statements for per-statement cost. Pool queueing is measured at the call site, because a snapshot gauge only catches contention a scrape happens to land on.
Outcome
A defense-ready platform with the full mandatory scope and four bonuses — photo editor, live map of users, WebRTC calls, and match-gated dates with map-based meetup picking — leaving OAuth sign-in as the one deliberate gap. The lasting lesson was the second half of the project: features that work are not the same as a system you can reason about, and the difference is measurement you can point at.