Skip to content

Platform Overview

The Feyenoord digital platform provides fans, members, and partners with access to sports data, membership services, and club content through web and native applications. Client apps are the presentation layer. A federated GraphQL graph and a legacy monolith API form the domain logic layer. PostgreSQL, MongoDB, Redis, and third-party data feeds make up the data layer.

For how requests and events move through these layers, see Data Flow.

The three layers

Presentation

Client applications render UI and orchestrate user interactions. They do not own domain rules or persistent data.

ApplicationStackRole
WebNext.jsPublic website
NativeExpo / React NativeiOS and Android mobile app
Sanity StudioSanityContent management system
StorybookStorybookComponent library

Domain logic

Backend services enforce domain rules, compose APIs, and coordinate integrations.

ServiceRole
API Gateway (Traefik)Single edge endpoint: path-based routing, TLS, trace propagation
GraphQL Router (Apollo Federation)Composes subgraph schemas into one federated graph
Monolith API (deprecated)v1 REST + GraphQL for most existing domains to be migrated to subgraphs
IdentityUser identity, authentication, and basic personally identifiable information
NotificationsPush and in-app notifications
LoyaltyOwns everything related to season cards, memberships, and other loyalty related interactions
Match GatewayIngests live match events and publishes domain events to the platform

Data

StoreUsed for
PostgreSQLRelational data within API services
MongoDBDocument based data, deployed using CosmosDB
RedisCaching and Dapr pub/sub broker (Redis Streams)
External integrationsCMS, sports feeds, ticketing, CRM, and more (see table below)

INFO

All client apps connect through Traefik. Federated GraphQL queries go to the Apollo Router, which fans out to subgraphs. The legacy monolith serves /api/v1 and /api/graphql. API services also expose OpenAPI REST endpoints at /v2/{service}.

External integrations

Third-party systems the platform reads from or writes to, grouped by category.

CategoryIntegrationPurposeUsed by
IdentityTwo CirclesOIDC SSO: login, userinfo, account changesweb, native, api, identity, loyalty
ContentSanityHeadless CMS / content lakesanity, api, match-gateway, notifications, web, native
BynderDigital asset management pickersanity
TypeformEmbedded surveys and formssanity, web
YouTubeEmbedded videoweb
Sports dataStatsPerformPro match data (SDAPI) + live feed (SDDP)api, match-gateway, loyalty, match-tools
SportlinkAcademy teams, matches, standingsapi
TotoBetting odds and content (feature-flagged)api
MiscellaneousTymes4Ticketing platform: mobile tickets, season cardsloyalty, native, api
AdyenHosted checkout for Legioen and Kameraadjes membershipsapi
EasylinqMembership CRM handoff after paymentapi
HubSpotB2B preferences and transactional emailapi
Postcode.euDutch address lookupapi (web/native via GraphQL)
TalentLinkVacancies and job applicationsapi
AlgoliaSite search indexing and search UIapi, web, native
TriniCoSupporter-service contact and change formsweb
OneSignalPush notificationsnotifications, match-gateway, web, native
MediaMarktProduct and deals feedapi
EndeavorFeyenoord One streamingnative
Azure Blob StorageGoal-replay video storageapi
Analytics & client toolingGoogle Tag ManagerWeb analytics and taggingweb
FirebaseAnalytics, crashlytics, performancenative
Azure Application InsightsTelemetry sink for traces, logs, and exceptionsweb, all backend services
MopinionIn-app feedback surveysnative, web
Cloudflare TurnstileCAPTCHA on web formsweb

Observability

Every service emits OpenTelemetry traces, logs, and exceptions through the shared @repo/observability package. Trace context propagates end-to-end from the native app through Traefik, the Apollo Router, and the subgraphs. See Observability for the full pipeline, the Instrumentation guide for how each app is wired in, and Azure Container Apps for how telemetry reaches Application Insights in production.