Overview
The Austrian Small-Field Football Federation (ÖKFB) has organised small-field football for more than 25 years, with around 200 clubs and up to 10,000 registered players. For a long time, much of that ran on manual admin work: forms, emails, spreadsheets and phone calls.
I joined the board as a volunteer in November 2023 as Head of Technology, and designed and built the platform that now runs the federation: a public website, an admin dashboard, a team portal, a referee portal and a mobile app, all on one shared backend.
Every Sunday, around 150 matches are scored live through it, and more than 80% of the routine admin work that used to be done by hand now runs automatically.
It is all live: oekfb.eu and team.oekfb.eu.
One backend, five applications



- Public website: fixtures, live scores, tables, discipline and transfers
- Team portal: player profiles, registrations and photos
- Match cards: recent form, kick-off and venue for every fixture
- AI matchday reports: a report for every league
- AI match previews: written from facts the backend computes
- Mobile app: live ticker, pushes and team management
Each user group gets an application built for its job, and they all work on the same data through one Swift/Vapor API.
Match day: the referee workflow
The referee portal turns a match into a sequence of states with clear correction paths. This is the part that has to work on a Sunday morning, on a phone, at the side of a pitch.
- Assigned
- Match sheet
- Kick-off
- Half-time
- Second half
- Full time
- Report
- Complete
Simplified match states in the referee portal.
- Add players and coaches to both match sheets
- Record goals, including own goals
- Yellow, red and yellow-red cards with player and minute
- Delete wrong events and adjust the score
- Abandoned matches and no-shows
- Reset game or half-time state when needed
- Kit selection
- Written match report
Results flow straight into live scores, tables, leaderboards and suspensions on the website and in the app, with no one in the office re-typing them.

Team onboarding without the paperwork
Registering a new team used to mean emails, paper contracts and manual checks. It is now a tracked workflow, from application to a live team account.
- Application
- Email verified
- Documents
- Review
- League assigned
- Payment
- Team created
Application lifecycle.
Documents before decisions
Applicants get a welcome email with contract downloads and a protected upload link. Partial submissions are allowed, but a team can’t be assigned to a league until the required ID documents and signed contracts are complete.
Every step is recoverable
Failed or pending emails are visible and can be resent, payments are recorded with protection against duplicate credits, and older records can be repaired explicitly.
Signed, expiring links
Registration, transfer and postponement confirmations use signed email links that expire, so people can act from their inbox without a login.
Payments, balances and fees
Every team has an account balance for registrations, fees and charges. Getting money right meant designing for retries, interruptions and duplicates from the start.
- Credit only verified paymentsStripe Checkout and PaymentIntents, with signed webhooks. A balance is credited only after Stripe confirms the payment.
- Idempotent by designIdempotency keys and durable receipts stop double credits and double debits, for example when a postponement approval is retried.
- Recover, don’t losePayment, accounting and email are tracked as separate steps, and interrupted processing resumes from persisted background jobs.
- Versioned feesFees are configured centrally and versioned, and every financial action stores the fee version it used. Player registrations, cancellations, deposits, overdraft and postponement fees all run on it.
Paid invoices and confirmation emails are generated automatically, with an invoice history per team.
AI match previews and reviews

- Recent form from recorded results
- Kick-off and venue from the fixture
- Table position and what’s at stake this matchday
- Top scorer counted from recorded goals
The website publishes German-language previews before every match and a review of each matchday. Football fans notice a wrong number immediately, so the system is built to keep the model away from making facts up.
Facts are computed, not generated
The backend calculates recent form, table position, head-to-head, scorers, discipline and confirmed absences, with a historical cutoff so a preview never uses results from after the match. Incomplete rounds and awarded results are handled explicitly.
The model chooses, the backend writes
Through strict JSON Schema outputs, the model selects and orders verified facts and title candidates. The backend renders the article from those choices instead of publishing free-form text.
AI jobs that survive failure
Generation runs as persistent jobs with bounded concurrency across replicas, atomic claims and renewable leases, retries with backoff and idempotency keys. Each article records its source snapshot, model, prompt version, selected facts and token usage, and publishing is revision-safe.
Admins review, edit, publish or delete each article. The inference provider sits behind an interface: today it’s an OpenAI-compatible adapter, but the football logic doesn’t depend on it.
Generated kits
Admins can also upload a club’s jersey and get a standardised home or away kit illustration back. The pipeline uses the jersey and a layout reference as image inputs, validates the transparent PNG (structure, CRCs, visible pixels, transparent edges), shows a preview before saving to Firebase, and rejects stale saves.
Analytics built in
Instead of sending staff to Google Analytics, the admin dashboard has its own historical and realtime reports.
- Native Swift importer for GA4 reporting and realtime APIs
- Hourly snapshots, imported once across all replicas via shared leases
- Traffic, engagement, pages, sources, devices, countries, events
- Correct period totals instead of summed daily users
- Caching and coalescing of concurrent requests
- Visible freshness, empty and failure states
Architecture and reliability
Built-in safeguards
- Granular admin permissions
- Team ownership checks
- Signed, expiring links
- Upload signature and size checks
- Idempotency keys
- Stale-write protection
- Database migrations and indexes
- Mocked external services in tests
Outcome
More than 80% of the routine admin work that used to be done by hand now runs automatically. Around 200 clubs and 8,000 players are registered, transferred, scheduled, scored and invoiced through one platform, and fans get live scores, tables and AI previews without anyone in the office typing them up.
Because the platforms are documented and run on clear processes, they keep running and improving whether or not I’m in the room.
What’s next: an MCP server
Planned, not built yet. I want to put a custom MCP server in front of the existing backend, so AI assistants can use the federation’s data and actions safely, with any model provider.
- AI client
- ÖKFB MCP server
- Authenticated Vapor API
- MongoDB and integrations
Planned architecture. Football rules, accounting and permission checks stay in the backend.
- League assistant over fixtures, tables and teams
- Registration assistant that explains missing documents
- Referee report drafts from recorded events
- Scheduling help for postponements
- Finance and analytics questions with sources
- Rules assistant with cited regulations
What I learned
Owning a platform completely, from the board meeting to the production incident, changes how you build. Every shortcut eventually turns into a Sunday-morning phone call, so I design for the unglamorous parts first: correct data, idempotent money, recoverable jobs and documentation someone else can follow. That same discipline is what made the AI features trustworthy enough to publish.