← projets/tapapamai

2026 →

Tapapamai

Plateforme sportive communautaire

tapapamai.com
En coursProduitFull-stack

Défis, soumissions vidéo, classements vérifiés. Monorepo fullstack en production.

4

apps dans le monorepo

3

surfaces (API · Admin · Mobile)

71

tests backend (xUnit)

Le problème

Dans une communauté sportive, suivre les défis et performances passe par Strava, Instagram ou un Google Sheet partagé. Aucun outil ne permet à la fois de publier un challenge avec règles claires, recevoir des soumissions avec preuve vidéo, et produire un classement crédible. Les plateformes existantes coûtent cher et sont conçues pour des structures affiliées, pas pour des groupes informels ou des compétitions ponctuelles.

L'approche

Monorepo avec 4 surfaces : API REST (.NET 8 + PostgreSQL sur Railway), app mobile Flutter (iOS/Android/Web), panel admin Next.js et landing. L'athlète soumet son score avec un lien vidéo, l'admin valide avant que ça compte au classement. Architecture stateless JWT avec refresh token automatique côté mobile.

Décisions clés

01

Statuts WODs calculés côté client

Le backend stocke startDate/endDate/isActive. Les statuts OPEN, PROCHAIN, CLOSED sont calculés côté UI, sans job cron à maintenir. Une seule source de vérité.

02

Dockerfile builder forcé sur Railway

Railpack ignorait l'ENTRYPOINT du Dockerfile, cassant le binding du PORT dynamique. railway.toml force builder = "dockerfile" pour contourner le bug.

03

Soft-delete sur toutes les entités critiques

Users, Challenges, Submissions ne sont jamais supprimés physiquement. Flags IsActive + DeletedAt conservent l'historique des classements et permettent la restauration de compte.

Stack

Next.jsReact QueryRechartsZodTailwind.NET 8ASP.NET CorePostgreSQLEntity FrameworkJWTSendGridFlutterRiverpodGo Router

Ce que j'ai appris

Gérer 4 surfaces simultanément dans un monorepo force une discipline d'architecture que tu n'aurais pas avec un projet simple. Le vrai défi n'est pas technique : c'est de garder les contrats d'interface synchronisés entre clients sans introduire de couplage.