← Retour à l'accueil

Documentation

Référence technique de la plateforme Timline — architecture, structure des données, zones dynamiques, sécurité et limites par plan.

Architecture générale

Stack technique

Timline est une application web full-stack construite avec Next.js 15 (App Router), React 19, TypeScript 5 et Tailwind CSS. L'éditeur visuel repose sur Fabric.js 6. La base de données est PostgreSQL via Prisma ORM (hébergée sur Neon). L'authentification utilise NextAuth v5. Les médias sont stockés sur Cloudflare R2 ou en local selon la configuration.

Environnements

Développement : http://localhost:3000. Production : défini par la variable d'environnement NEXT_PUBLIC_APP_URL. Le build de production exécute automatiquement prisma migrate deploy avant next build.

Routes API

L'API REST interne expose ~68 routes organisées par domaine : projets, joueurs, équipes, matchs, sponsors, catégories, templates, compositions, visuels, médias, IA, abonnements, administration, santé du service. Toutes les routes sont protégées par session NextAuth sauf les webhooks Stripe et le endpoint /api/health.

Modèle de données

Entités principales

User · Account · Session · Project · VisualSet · Visual · Player · SportTeam · Jersey · Sponsor · Category · Match · MatchLineup · MatchStat · ProjectImage · Template · UserComposition · ImportLog · Team · TeamMember.

Projet

Un projet est le conteneur principal. Il est lié à un sport, une palette de couleurs, une image de couverture, et possède sa propre base de données sportive (joueurs, équipes, matchs, sponsors, médias). Il appartient à un User ou à une Team selon le plan.

Visual et VisualSet

Un Visual représente un artboard sauvegardé. Un VisualSet regroupe plusieurs Visuals liés par format (Post 1:1, Story 9:16, Paysage 16:9) sous une même clé setKey. Le contenu du canvas est sérialisé en JSON Fabric.js et stocké en base.

Match et compositions

Un Match lie deux SportTeam avec un score, un statut (UPCOMING / LIVE / FINISHED), une date et un lieu. MatchLineup stocke la composition avec le rôle (STARTER / SUBSTITUTE) et le flag gardien. MatchStat stocke les statistiques par joueur ou en entrée libre.

Jersey

Plusieurs maillots peuvent être associés à une SportTeam. Chaque Jersey a un type (joueur ou gardien), un mode (SVG builder ou image) et des propriétés graphiques (fond, logos, numéro, nom, overlays).

Artboards et formats

Formats standards

LANDSCAPE : 1920 × 1080 px (16:9) · SQUARE : 1080 × 1080 px (1:1) · STORY : 1080 × 1920 px (9:16). Ces trois artboards peuvent coexister dans un même Visual et sont affichés côte à côte sur le canvas Fabric.js.

Formats personnalisés

Un artboard peut avoir des dimensions libres. Les formats personnalisés ne bénéficient pas de la synchronisation automatique avec les formats standards.

Positions canvas

Les artboards sont positionnés horizontalement avec un espacement de 60 px. La position de chaque artboard sur le canvas est calculée depuis src/lib/artboards.ts.

Zones dynamiques

Types de zones

player — affiche un joueur selon le mode visuel configuré. team — affiche le logo ou le nom d'une équipe. sponsor — affiche le logo d'un sponsor. score — affiche le score du match. teamName — affiche le nom d'une équipe. matchText — affiche un champ texte lié au match (date, lieu, compétition, journée…).

Synchronisation inter-artboards

Chaque zone dynamique est identifiée par un identifiant logique (slotId). Lorsqu'une zone est assignée sur un artboard, les zones ayant le même slotId sur les autres artboards reçoivent automatiquement la même assignation.

Modes visuels joueur

photo · cutout (photo détourée) · jersey (maillot joueur) · jersey-gk (maillot gardien) · helmet (casque) · helmet-gk (casque gardien) · gloves (gants gardien). Le mode est stocké dans les customData de l'objet Fabric.js.

Champs sport-spécifiques

Football : round (Journée/Tour), competition. Basketball : period (Quart-temps/Mi-temps), competition. Volleyball : set, competition. Hockey : period, competition. Rugby / Handball : half, competition. Karting : circuit.

Import de données

Formats supportés

.csv (séparateur virgule ou point-virgule, auto-détecté) · .xls · .xlsx. Traitement via la librairie xlsx côté serveur.

Entités importables

Joueurs · Équipes · Matchs · Statistiques de match.

Wizard d'import

5 étapes : (1) Sélection du type d'entité → (2) Upload du fichier → (3) Mapping des colonnes avec presets suggérés → (4) Prévisualisation ligne par ligne → (5) Résultat avec journal d'erreurs. Les mappings sont mémorisés par type via UserImportMapping.

Déduplication

Les doublons sont détectés sur des clés métier (email, nom + numéro pour les joueurs, nom pour les équipes). En cas de doublon, la ligne existante est mise à jour plutôt que dupliquée. Les équipes référencées mais absentes de la base peuvent être créées automatiquement.

Statuts de photo joueur

Après import, les photos joueurs ont un statut de détourage : PENDING (pas encore traité) · DONE (cutout disponible) · FAILED (échec du traitement). Le cutout peut être déclenché manuellement depuis la fiche joueur.

Détourage — implémentation

Technologie

Le détourage s'exécute entièrement côté navigateur via MediaPipe Vision Tasks. Deux modèles sont utilisés : ImageSegmenter (segmentation automatique, modèle selfie_multiclass_256x256) et InteractiveSegmenter (segmentation guidée par points). Le runtime est WASM / CPU, sans GPU requis.

Assets ONNX

Les modèles ONNX sont servis via une route proxy interne (/api/background-removal-assets/[...assetPath]) avec des en-têtes de cache long terme (Cache-Control: public, max-age=31536000, immutable). Ils sont téléchargés une seule fois et mis en cache par le navigateur.

Modes

Automatique : détection dominante des bords + segmentation. Interactif : placement de points include/exclude avec algorithme de clustering. Pinceau : tracés manuels inclusion/exclusion. Baguette magique : sélection par tolérance de couleur (flood fill).

Stockage

La photo originale est conservée. La version détourée est stockée séparément sous players/cutouts/{id}. Les deux URLs sont référencées dans le modèle Player (photo et cutoutPhoto). Le statut est tracé dans le champ cutoutStatus.

Textures procédurales

Implémentation

Les 18 motifs sont générés en JavaScript via l'API Canvas 2D et appliqués comme overlay sur les objets Fabric.js. Le générateur est dans src/lib/texturePatterns.ts.

Motifs disponibles

carbone · papier · déchirure · béton · bois · métal brossé · tissu · bruit · vagues · hexagones · lignes diagonales · points · hachures · marbre · cuir · grille · chevrons · circuits.

Paramètres

Chaque motif expose : primaryColor (couleur principale), secondaryColor (couleur secondaire), opacity (0–1), scale (taille du motif), rotation (orientation en degrés), intensity (force de l'effet). Les paramètres sont persistés dans customData.textureOverlay de l'objet Fabric.js.

Rendu

L'overlay est un objet Fabric.js de type FabricImage positionné automatiquement au-dessus de l'objet cible et lié à ses dimensions. Il n'est pas exporté comme calque indépendant — il fait partie de l'objet parent.

Stockage médias

Drivers disponibles

local : stockage dans le dossier public/uploads/ (développement ou serveur auto-hébergé). r2 : Cloudflare R2 (production recommandée). Le driver est sélectionné via la variable d'environnement MEDIA_STORAGE_DRIVER.

Structure des dossiers

projects/{id}/backgrounds · projects/{id}/assets · projects/{id}/logos · players/photos · players/cutouts · jerseys/thumbnails · visuals/thumbnails · visuals/canvas.

Proxy médias

Toutes les URLs médias passent par /api/media/[...key] qui résout le bon driver (local ou R2) et sert le fichier. Cela évite d'exposer les URLs R2 directement et permet de changer de driver sans modifier le frontend.

Proxy images externes

/api/proxy-image?url=... permet d'importer des images depuis des URLs externes. La route valide la sécurité de la cible (liste noire de plages réseau sensibles) et contourne les restrictions CORS.

Sécurité

Authentification

NextAuth v5 avec sessions JWT. Le middleware Edge vérifie le cookie de session sur toutes les routes protégées (/dashboard, /editor) sans requête base de données, pour un contrôle d'accès ultra-rapide.

En-têtes HTTP

Content-Security-Policy stricte · X-Frame-Options: DENY · X-Content-Type-Options: nosniff · Referrer-Policy: strict-origin-when-cross-origin · Permissions-Policy · HSTS (production uniquement, max-age 2 ans).

Rate limiting

Les routes sensibles (login, register, reset password, 2FA, export) sont protégées par un rate limiter en mémoire basé sur l'IP. Les limites sont configurées par route dans src/lib/rate-limit.ts.

Journal d'audit admin

Toutes les actions admin sensibles (modification de plan, suspension de compte, suppression de données…) sont enregistrées dans AdminAuditLog avec l'acteur, la cible, l'action et le timestamp.

2FA

La double authentification par email génère un code à usage unique valable 10 minutes. Des codes de récupération permanents sont générés à l'activation et peuvent être révoqués depuis les paramètres.

Plans et limites

FREE

1 projet actif · 3 templates · Éditeur visuel de base · Export PNG standard · Pas d'automatisation assistée · Pas de fond transparent.

PRO — 19 €/mois

Projets illimités · Templates premium · Export HD · Fond transparent · Zones dynamiques avancées · Automatisation assistée · Détourage avancé (tous les modes) · Support prioritaire.

TEAM — 49 €/mois

Tout le plan Pro · Jusqu'à 5 membres · Accès et rôles partagés (OWNER, ADMIN, MEMBER) · Médiathèque commune · Facturation centralisée · Invitations par email.

Gestion des abonnements

Les abonnements sont gérés via Stripe. Le portail Stripe permet de consulter les factures, modifier le mode de paiement et résilier. Les webhooks Stripe mettent à jour le statut en temps réel dans la base de données.