← All projects

FULL STACK · TECHNICAL DEMO · v1.0.0

MatchdaySimulated betting, real football data.

Matchday is a simulated sports betting platform: real fixtures from Europe’s top five leagues, odds generated by the app and fictitious credits. I designed and released it as a TypeScript monorepo with a React site, an Express API on PostgreSQL and an Angular back-office, on Vercel with Neon; the code was written with Claude Code and every change went through a merge request.

Role
Personal AI-assisted project: design, integration, review and release
Stack
React · Angular · Express · TypeScript · PostgreSQL · Drizzle · Zod
Quality
Vitest · React Testing Library · Cypress · GitLab CI
Status
v1.0.0 released on Vercel and Neon · fictitious credits
01

The goal

The goal was to show a complete application, not just an interface: data from an external provider with usage limits, rules that must hold on every request, an operator panel and a controlled release. A simulated betting system brings these constraints together without any real money.

02

How it works

Three applications in one repository, with shared types. The API integrates football-data.org, generates and stores odds, and records bets. The public site shows fixtures, odds and the bet slip. The back-office lets operators manage odds and events.

Features

Football data

Competitions, fixtures and standings from football-data.org. The key stays on the server, responses are validated with Zod and mapped to internal types, and a cache helps respect the free tier’s limits. If the provider is slow or rate-limits a refresh, the API serves the last cached response instead of an error.

Simulated odds

A deterministic model for the 1X2 market: points per game, home advantage, a draw probability that falls as the strength gap widens, and a 5% margin. It is a pure function, so it is easy to test.

Public site

Serie A, Premier League, La Liga, Bundesliga and Ligue 1, with upcoming fixtures and a match page with odds. Mobile-first layout with CSS Modules and design tokens, plus loading, error, empty and not-found states.

Bet slip and weekly limit

Selections, total odds, potential payout and a weekly limit in fictitious credits. On submission the API rechecks the odds and records the bet in a transaction that verifies the remaining allowance.

Angular back-office

Operator sign-in to suspend and resume fixtures, set manual odds and review fictitious users, bets and remaining limits. Sessions in PostgreSQL, an HttpOnly cookie and a CSRF token for changes.

Tests and accessibility

Unit and component tests for logic, API and interfaces; two Cypress flows for browsing, the bet slip, placing a bet and the limit block, using fixed responses. Semantic structure, keyboard support, focus management in the bet slip and announcements for loading and errors.

Screens

Upcoming Serie A fixtures, with the league selector at the top and the bet slip button.
Upcoming fixtures by league
Bet slip with a 20-credit weekly limit, two selections, total odds of 6.72 and a 10-credit stake.
Bet slip and weekly limit
Back-office: odds management for one fixture, with buttons to edit prices and suspend the event.
Back-office: odds management

Real screenshots of the app, captured with test data rather than live football-data.org data.

Technical decisions

01

Layered API

HTTP routes, business services, external clients and database repositories each have a distinct responsibility. External dependencies are injected or replaced in tests.

02

Consistent contracts

TypeScript types shared across the apps, Zod validation at the API boundary and a single format for responses and errors. The rest of the code does not depend on the provider’s format.

03

Persistent state where it matters

Offered odds, bets, limits and operator sessions live in PostgreSQL and survive serverless restarts. A stored price keeps what the user was shown, along with back-office changes. Migrations run at API startup under a Postgres advisory lock, so several simultaneous cold starts never apply them twice.

04

Same-origin API calls

The site and back-office call /api on their own domain and Vercel forwards requests to the API: no CORS and first-party cookies. Neon uses a pooled connection for requests and a direct one for migrations.

05

AI-assisted workflow and release

Development with Claude Code on feature/* branches, with review in merge requests and required GitLab pipelines for linting, types, tests, builds and security. Preview separate from Production, manual checks of the main flows and a v1.0.0 tag.

Something similar in mind?

Tell me about it ↗