One Club · Publicis Groupe
The Publicis employees' sports club, gamified
- iOS and Android app
- Website
- Web back-office

The web version

Role
Web and mobile developer, apprenticeship
A web and mobile ecosystem that rallies employees around shared sports goals: activities flow in from Strava or Garmin, a gamification engine turns them into points, tiers and rankings, and a social feed keeps the club alive. Sign-in with the company Microsoft account. Presented as a proof of concept.
What's inside
- React and TypeScript web app, Flutter mobile app for iOS and Android.
- NestJS backend, MongoDB Atlas hosted in Paris, hourly activity sync.
- Microsoft Entra ID sign-in with OpenID Connect and PKCE, no client secret.
- Strava and Garmin over OAuth2 with webhooks, optional and consent-based connections.
- Gamification: points, tiers, individual and team rankings, collective rewards.
- Social feed, collective events and outings proposed between colleagues.
- Back-office behind JWT and a second factor, rate limiting, input validation.
In detail
01The product
An internal sports gamification platform for Publicis France, named One Club. An employee links a Strava or Garmin account, their activities flow in automatically, are converted into points and feed individual and team rankings around events. Around it live a social feed and outings organised between colleagues.
The guiding principle: the collective is the point. Individual points push team and club gauges forward, whose tiers unlock rewards for everyone.
Three surfaces: a Flutter mobile app for iOS and Android, a React website, and a web-only admin back-office.
02Identity and sign-in
The entrance is Microsoft Entra ID, with OpenID Connect and PKCE: the employee authenticates with Microsoft under the tenant's policies, MFA included, and the application never sees their password. The backend fetches the tenant's public keys, checks signature, issuer, audience, expiry and tenant, then issues its own 8-hour session token. No Microsoft token is kept.
The back-office has its own path: bcrypt-hashed password, then a six-digit code sent by e-mail, randomly drawn, valid ten minutes, single-use, compared in constant time. Creating an administrator is done by a server command, never through an exposed route.
SSO still awaits the Azure Client IDs from IT: meanwhile a "Continue with Strava" link remains and disappears by itself once the Client ID is configured.
03Activities, points, events
Strava and Garmin are linked independently, each revocable, with a consent sheet that states what will be read, the purpose and the read-only access, as the CNIL recommends. Tokens are stored per user and refreshed automatically; provider secrets stay server-side.
Sync runs through an hourly job and through both providers' webhooks. On a webhook, the server calls the API back rather than trusting the payload. Every activity is deduplicated on the provider's identifier, so repeated syncs never double the points.
One points rule per sport, editable by administrators: 100 points per kilometre run, 40 cycling, 400 swimming, 50 walking, and time-based for hiking, strength, yoga and crossfit. Garmin activities are mapped to Strava's vocabulary so one rule set covers both. Automatic badges on yearly distance and total points.
Two kinds of events. Official ones, created from the back-office, with a period, accepted sports, a global goal and three tiered reward families, in teams if enabled. Personal ones, which anyone creates from the Events tab, earn no points: the server enforces it whatever the client sends, which rules out cheating and avoids moderation.
04Architecture and security
Mobile in Flutter with Riverpod, go_router and Dio; web in React 19, Vite and TypeScript on Vercel; NestJS 10 API on Render in Frankfurt; MongoDB Atlas in Paris. No inbound flow to Publicis' information system, the only contact is outbound authentication to Entra ID.
HTTPS everywhere, JWT sessions verified on every call, allow-listed CORS, rate limiting at 120 requests per minute and 5 on authentication, Helmet headers, strict input validation that closes NoSQL injection, mobile secrets in the iOS Keychain and Android Keystore. A blocked account loses access in under thirty seconds, without waiting for its session to expire.
It is a proof of concept, presented as such: free hosting for the demonstration phase, Azure in France on the group subscription as the target, and a few screens still unfinished, such as team chat, referral and the Steam integration.