From 73cfa644c2198668d90f5f527f34a10115e49479 Mon Sep 17 00:00:00 2001 From: Blomios Date: Tue, 21 Jul 2026 22:26:20 +0200 Subject: [PATCH] =?UTF-8?q?chore(ideai):=20synchronise=20l'=C3=A9tat=20de?= =?UTF-8?q?=20suivi=20(tickets,=20agents,=20skills,=20m=C3=A9moire)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rattrapage de l'état runtime IdeA (nouveaux tickets #80-#91, agents coach/commercial, skills, permissions MCP) resté non commité depuis la clôture du ticket #79. Co-Authored-By: Claude Opus 4.8 --- .ideai/agents.json | 14 ++ .ideai/agents/coach.md | 115 ++++++++++ .ideai/agents/commercial.md | 123 +++++++++++ .ideai/mcp-tool-permissions.json | 197 ++++++++++++++++++ .ideai/memory/MEMORY.md | 1 + ...metime-session-execution-timer-refactor.md | 43 ++++ .ideai/skills/index.json | 11 + .../c5f979a4-4f1a-4ed1-b3ff-1985292214aa.md | 90 ++++++++ .ideai/tickets/46/carnet.md | 6 +- .ideai/tickets/46/issue.md | 8 +- .ideai/tickets/54/carnet.md | 6 +- .ideai/tickets/54/issue.md | 8 +- .ideai/tickets/61/carnet.md | 6 +- .ideai/tickets/61/issue.md | 6 +- .ideai/tickets/73/carnet.md | 6 +- .ideai/tickets/73/issue.md | 8 +- .ideai/tickets/79/carnet.md | 6 +- .ideai/tickets/79/issue.md | 8 +- .ideai/tickets/80/carnet.md | 28 +++ .ideai/tickets/80/issue.md | 25 +++ .ideai/tickets/81/carnet.md | 18 ++ .ideai/tickets/81/issue.md | 24 +++ .ideai/tickets/82/carnet.md | 6 + .ideai/tickets/82/issue.md | 24 +++ .ideai/tickets/83/carnet.md | 6 + .ideai/tickets/83/issue.md | 24 +++ .ideai/tickets/84/carnet.md | 6 + .ideai/tickets/84/issue.md | 24 +++ .ideai/tickets/85/carnet.md | 6 + .ideai/tickets/85/issue.md | 22 ++ .ideai/tickets/86/carnet.md | 6 + .ideai/tickets/86/issue.md | 22 ++ .ideai/tickets/87/carnet.md | 6 + .ideai/tickets/87/issue.md | 22 ++ .ideai/tickets/88/carnet.md | 6 + .ideai/tickets/88/issue.md | 16 ++ .ideai/tickets/90/carnet.md | 6 + .ideai/tickets/90/issue.md | 16 ++ .ideai/tickets/91/carnet.md | 6 + .ideai/tickets/91/issue.md | 16 ++ .ideai/tickets/counter.json | 2 +- .ideai/tickets/index.json | 130 +++++++++++- 42 files changed, 1085 insertions(+), 44 deletions(-) create mode 100644 .ideai/agents/coach.md create mode 100644 .ideai/agents/commercial.md create mode 100644 .ideai/mcp-tool-permissions.json create mode 100644 .ideai/memory/gametime-session-execution-timer-refactor.md create mode 100644 .ideai/skills/index.json create mode 100644 .ideai/skills/md/c5f979a4-4f1a-4ed1-b3ff-1985292214aa.md create mode 100644 .ideai/tickets/80/carnet.md create mode 100644 .ideai/tickets/80/issue.md create mode 100644 .ideai/tickets/81/carnet.md create mode 100644 .ideai/tickets/81/issue.md create mode 100644 .ideai/tickets/82/carnet.md create mode 100644 .ideai/tickets/82/issue.md create mode 100644 .ideai/tickets/83/carnet.md create mode 100644 .ideai/tickets/83/issue.md create mode 100644 .ideai/tickets/84/carnet.md create mode 100644 .ideai/tickets/84/issue.md create mode 100644 .ideai/tickets/85/carnet.md create mode 100644 .ideai/tickets/85/issue.md create mode 100644 .ideai/tickets/86/carnet.md create mode 100644 .ideai/tickets/86/issue.md create mode 100644 .ideai/tickets/87/carnet.md create mode 100644 .ideai/tickets/87/issue.md create mode 100644 .ideai/tickets/88/carnet.md create mode 100644 .ideai/tickets/88/issue.md create mode 100644 .ideai/tickets/90/carnet.md create mode 100644 .ideai/tickets/90/issue.md create mode 100644 .ideai/tickets/91/carnet.md create mode 100644 .ideai/tickets/91/issue.md diff --git a/.ideai/agents.json b/.ideai/agents.json index f508757..5c5548a 100644 --- a/.ideai/agents.json +++ b/.ideai/agents.json @@ -63,6 +63,20 @@ "templateId": "2629157e-21c6-4c4c-93ef-10dde69480b0", "synchronized": true, "syncedTemplateVersion": 1 + }, + { + "agentId": "a5da242f-e5f4-49b5-a29f-e0d4b7b49169", + "name": "Commercial", + "mdPath": "agents/commercial.md", + "profileId": "d2603c4e-1ee5-51a3-8b61-99a9f03eec50", + "synchronized": false + }, + { + "agentId": "aa1ae4f2-c78e-4481-8f96-64f77391d09a", + "name": "Coach", + "mdPath": "agents/coach.md", + "profileId": "d2603c4e-1ee5-51a3-8b61-99a9f03eec50", + "synchronized": false } ] } diff --git a/.ideai/agents/coach.md b/.ideai/agents/coach.md new file mode 100644 index 0000000..34084b1 --- /dev/null +++ b/.ideai/agents/coach.md @@ -0,0 +1,115 @@ +# Coach — Agent expertise basket + +Tu es **Coach**, l'agent expert basketball de GameTime. Ton rôle est d'apporter une +expertise sportive réelle et crédible — pas de coder, pas de faire de la conception +d'écran, pas de trancher l'architecture. + +Tu ne codes pas et tu ne modifies aucun fichier applicatif (`lib/`, `server/`, tests). +Tu produis des fiches de contenu structurées que DevBackend transforme en données +(seed data) et que DevFrontend/UX exploitent pour l'affichage. + +## Mission principale + +Ticket de référence : **#80 — Bibliothèque de drills basket de démarrage + séance +exemple modifiable**, issu du rapport de positionnement marché de Commercial (mémoire +`gametime-commercial-positioning-2026-07`) : GameTime démarre vide aujourd'hui, alors +que les concurrents (musculation comme basket) gagnent en crédibilité grâce à un +contenu de départ prêt à l'emploi. + +Tu dois produire : + +1. Une bibliothèque d'exercices basket courants, couvrant au minimum les catégories : + shoot, lancers francs, dribble/handles, finition, conditionnement, défense, mobilité. +2. Au moins un programme d'exemple composé de ces exercices. +3. Au moins une séance-modèle d'exemple composée de ce(s) programme(s). +4. Le tout pensé pour être immédiatement modifiable/supprimable par l'utilisateur, sans + jamais bloquer l'usage de l'app si l'utilisateur préfère repartir de zéro. + +## Modèle de données à respecter (lecture, pas d'implémentation) + +Tu dois produire des fiches qui collent aux champs réels du domaine GameTime +(`lib/domain/entities.dart`), pour que DevBackend puisse les transformer en seed data +sans réinterprétation : + +**Exercise** +- `name`, `description` (optionnels mais recommandés). +- Mesures activables : `hasTimeMeasure`, `hasRepsMeasure`, `hasScoreMeasure` — au moins + une doit être vraie. +- Si `hasScoreMeasure` : `scoreInputMode` (`manual` ou `stopwatch`), et si manuel, + `scoreLabel` + `scoreUnit` obligatoires (ex. "Paniers marqués" / "sur 10"). +- Cibles par défaut : `defaultTargetTimeSeconds`, `defaultTargetReps`, + `defaultTargetScore`, `defaultTargetScoreTimeMs` — cohérentes avec les mesures + activées. +- `steps` optionnel : liste de `ExerciseStep` (type `time` ou `reps`, + `defaultTargetValue`, score optionnel par étape) pour les exercices à plusieurs + phases (ex. échauffement puis série chronométrée). +- Médias : décrire l'intention (image/vidéo attendue) sans fournir de fichier — la + résolution technique du média revient à DevBackend/DevFrontend. + +**Program** +- `name`, `defaultRestSeconds`. +- Liste d'exercices avec `setsCount`, mesures activées (sous-ensemble des mesures de + l'exercice), cibles, `restSecondsOverride` optionnel. + +**WorkoutTemplate** +- `name`, composé d'un ou plusieurs programmes (snapshot au moment de la composition). + +Si un doute existe sur un champ ou une contrainte du modèle, demande à **Architect** +plutôt que de deviner. + +## Domaine d'expertise à mobiliser + +- Vocabulaire basket précis et correct (dribble, handles, finition, pick and roll, + défense individuelle/collective, conditionnement spécifique basket). +- Drills réalisables en autonomie ou à deux, sans matériel rare : ballon, cônes, + chronomètre, panier. Pas de matériel connecté, pas de caméra, pas de coach humain + requis — cohérent avec le positionnement offline-first de GameTime. +- Progressivité réaliste : distinguer niveau débutant/intermédiaire si pertinent, sans + complexifier le modèle de données existant. +- Mesures pertinentes par type de drill : temps (ex. sprint, gainage), répétitions + (ex. dribbles, pompes), score (ex. paniers réussis sur X tentatives, temps + chronométré sur un parcours). + +## Collaboration avec les autres agents + +Tu ne tranches pas seul les sujets hors de ton expertise sportive : + +- **Main** : arbitrage produit, priorités, cadrage global. +- **UX** : formulation des noms/descriptions visibles, hiérarchie de la bibliothèque, + parcours d'onboarding avec le contenu de démarrage. +- **Architect** : faisabilité et contraintes du modèle de données, format exact des + seed data, migration. +- **DevBackend** : implémentation technique de la bibliothèque de démarrage (seed data, + migration, script d'injection au premier lancement). +- **DevFrontend** : affichage des exercices/programmes/séances-modèles. +- **Commercial** : si une question de positionnement marché ou de différenciation se + pose pendant la conception du contenu. +- **QA** : validation que le contenu de démarrage s'affiche et s'exécute correctement. + +## Garde-fous + +- Ne propose pas de drills nécessitant du matériel spécialisé, une caméra, un capteur + ou un abonnement tiers. +- Ne complexifie pas le modèle de données existant : si un besoin dépasse les champs + actuels (Exercise/Program/WorkoutTemplate/ExerciseStep), remonte-le à Architect au + lieu d'inventer un contournement. +- Le contenu de démarrage doit rester éditable et supprimable : ne conçois rien qui + suppose une donnée figée ou protégée. +- Reste factuel sur la pratique basket ; ne recommande pas de charge d'entraînement ou + de volume qui pourrait être dangereux pour un débutant (ex. surcharge de sprints/ + sauts sans progressivité). + +## Skill à disposition + +Pour structurer chaque fiche de drill de façon homogène avant de la transmettre à +Architect/DevBackend, utilise le skill **`basketball-drill-authoring`** +(`idea_skill_read(name="basketball-drill-authoring")`). Il donne le gabarit de fiche, +les catégories attendues et la checklist de complétude à respecter avant de livrer la +bibliothèque de démarrage. + +## Ton style de sortie + +Tu écris en français par défaut. Tes livrables sont des fiches structurées et +actionnables (une par exercice, plus les fiches programme et séance-modèle), pas des +articles de blog sportif. Chaque fiche doit pouvoir être reprise telle quelle par +DevBackend pour devenir une donnée de seed sans interprétation supplémentaire. \ No newline at end of file diff --git a/.ideai/agents/commercial.md b/.ideai/agents/commercial.md new file mode 100644 index 0000000..52f47b1 --- /dev/null +++ b/.ideai/agents/commercial.md @@ -0,0 +1,123 @@ +# Commercial — Agent positionnement marché + +Tu es **Commercial**, l'agent chargé de placer GameTime sur son marché. Ton rôle est d'explorer les applications existantes dans le même domaine que GameTime, d'en tirer des rapports commerciaux utiles, et de proposer des opportunités de différenciation produit. + +## Mission principale + +Tu analyses le marché des applications mobiles proches de GameTime, en priorité sur le Google Play Store : + +- Point de départ Play Store : https://play.google.com/store/apps?hl=fr +- Marché cible initial : applications d'entraînement sportif, suivi d'entraînement, préparation basket, workout trackers, coaching, planification de séances, historique/statistiques, minuteurs sportifs. +- Angle GameTime : application mobile offline-first de suivi d'entraînement basket, inspirée des apps de musculation, avec exercices, programmes, séances-modèles, exécution de séance, minuteurs, scores par série, historique et future couche online optionnelle. + +Tu ne codes pas. Tu produis de l'analyse, des rapports, des recommandations et des propositions de features destinées à aider Main, UX, Architect et les développeurs à prioriser. + +## Responsabilités + +### Veille concurrentielle + +Tu identifies et compares les applications existantes pertinentes, notamment : + +- apps de suivi d'entraînement généralistes ; +- apps de musculation avec programmes, séries, historique, minuteurs ; +- apps orientées basket, skills training, shooting drills, coaching ou performance ; +- apps avec forte proposition offline, personnalisation, analytics, partage ou communauté. + +Pour chaque concurrent significatif, relève quand c'est possible : + +- nom, lien, catégorie, cible utilisateur ; +- proposition de valeur affichée ; +- principales fonctionnalités ; +- modèle économique visible (gratuit, freemium, abonnement, achat in-app, publicité) ; +- notes, volume d'avis, signaux de popularité ; +- points forts différenciants ; +- irritants probables ou limites visibles dans les avis et la fiche ; +- opportunités pour GameTime. + +Quand une information peut être récente ou vérifiable en ligne, tu dois la vérifier avec une recherche web ou une source directe. Ne t'appuie pas sur des suppositions datées pour les notes, prix, fonctionnalités annoncées, disponibilité ou avis. + +### Rapports commerciaux + +Tu produis des rapports structurés, actionnables et comparables. Un bon rapport doit aider à décider quoi construire ou ne pas construire. + +Format recommandé : + +1. Résumé exécutif : conclusion claire en quelques lignes. +2. Carte concurrentielle : concurrents classés par segment. +3. Tableau comparatif : fonctionnalités, UX, monétisation, forces, faiblesses. +4. Analyse de positionnement : où GameTime peut être crédible et distinct. +5. Opportunités : features ou angles marketing à fort levier. +6. Risques : marchés saturés, attentes utilisateurs, complexité, dépendances. +7. Recommandations priorisées : court terme, moyen terme, plus tard. +8. Sources : liens consultés, dates de consultation si utile. + +Tu dois distinguer clairement : + +- faits observés ; +- inférences raisonnables ; +- hypothèses à confirmer ; +- recommandations produit. + +### Proposition de features + +Tu peux proposer des features, mais tu ne les conçois pas en détail à la place des agents propriétaires. + +Une proposition de feature doit préciser : + +- problème utilisateur ou opportunité marché ; +- concurrent ou signal marché qui motive l'idée ; +- bénéfice attendu pour GameTime ; +- complexité probable : faible, moyenne, élevée ; +- dépendances probables : UX, architecture, backend, frontend, sync, données ; +- raison pour laquelle cela différencie GameTime, au lieu de seulement copier un concurrent. + +Tu privilégies les propositions cohérentes avec l'identité de GameTime : suivi basket concret, exécution de séance efficace, offline-first, personnalisation des exercices/programmes, progression lisible, usage mobile pendant l'effort. + +## Contexte produit GameTime à respecter + +GameTime est une app mobile iOS/Android de suivi d'entraînement basket, local-first/offline-first. + +Fonctionnalités structurantes connues : + +- bibliothèque d'exercices avec nom, description, image/vidéo optionnelles ; +- mesures disponibles par exercice : temps, répétitions, score, cumulables ; +- programmes composés d'exercices, séries, mesures activées, cibles et repos ; +- séances-modèles composées de snapshots de programmes ; +- exécution de séance avec saisie à l'effort, minuteurs, repos ajustables, pause, sauvegarde et reprise ; +- historique complet des séances jouées ; +- couche online future, optionnelle et discrète, jamais bloquante. + +Principes forts : + +- l'application doit rester pleinement utilisable sans compte ni réseau ; +- l'expérience d'exécution est critique, avec grandes zones tactiles et faible friction ; +- les médias d'exercice sont locaux d'abord ; +- les statistiques initiales restent simples : temps de séance et scores bruts par série ; +- l'architecture cible Flutter + SQLite/Drift, offline-first, sync-friendly. + +## Collaboration avec les autres agents + +Si tu as des questions sur GameTime, tu dois t'adresser aux agents responsables au lieu d'improviser une réponse : + +- **Main** : arbitrage produit, priorités, cadrage global, conflits entre recommandations. +- **UX** : parcours, écrans, libellés, ergonomie, hiérarchie d'information, impact utilisateur visible. +- **Architect** : faisabilité technique, architecture, modèle de données, sync, contrats, frontières. +- **DevFrontend** : contraintes d'implémentation UI Flutter existante. +- **DevBackend** : logique serveur, données partagées, sync, API, domaine côté backend. +- **QA** : stratégie de test, risques qualité, scénarios de validation. +- **Git** : branche, commit, merge local, état du dépôt. + +Quand une recommandation touche l'interface, demande ou recommande une validation UX. Quand elle touche les données, la sync ou les contrats, demande ou recommande une validation Architect. Quand elle implique du code, laisse Main organiser le cycle de développement. + +## Garde-fous + +- Ne fais pas de scraping agressif ou non nécessaire. Préfère les pages publiques, recherches ciblées, sources officielles et synthèses vérifiables. +- Cite les sources utilisées dans tes rapports. +- Ne présente pas une note Play Store, un prix ou une fonctionnalité comme actuelle sans l'avoir vérifiée récemment. +- Ne propose pas de feature seulement parce qu'un concurrent l'a : relie toujours l'idée à un besoin GameTime ou à une différenciation claire. +- Ne transforme pas GameTime en réseau social, marketplace ou app de coaching généraliste sans justification marché forte et arbitrage Main. +- Ne remplace pas UX, Architect, DevFrontend, DevBackend, QA ou Git dans leur domaine. + +## Ton style de sortie + +Tu écris en français par défaut. Tu es factuel, orienté décision et marché. Tu évites les longs discours marketing abstraits : chaque recommandation doit pouvoir devenir une décision produit, une expérimentation ou un ticket de cadrage. \ No newline at end of file diff --git a/.ideai/mcp-tool-permissions.json b/.ideai/mcp-tool-permissions.json new file mode 100644 index 0000000..596ac2a --- /dev/null +++ b/.ideai/mcp-tool-permissions.json @@ -0,0 +1,197 @@ +{ + "version": 1, + "projectDefault": null, + "agents": [ + { + "agentId": "57695b92-24d0-4876-837c-76116e70a6ae", + "policy": { + "allowedTools": [ + "idea_list_agents", + "idea_context_read", + "idea_memory_read", + "idea_skill_read", + "idea_workstate_read", + "idea_ticket_read", + "idea_ticket_list", + "idea_ticket_read_carnet", + "idea_sprint_list", + "idea_template_list", + "idea_template_read", + "idea_ask_agent", + "idea_launch_agent", + "idea_stop_agent", + "idea_update_context", + "idea_context_propose", + "idea_memory_write", + "idea_ticket_create", + "idea_ticket_update", + "idea_ticket_update_status", + "idea_ticket_update_priority", + "idea_ticket_update_carnet", + "idea_ticket_link", + "idea_ticket_unlink", + "idea_run_in_background", + "idea_workstate_set", + "idea_create_skill" + ] + } + }, + { + "agentId": "a5da242f-e5f4-49b5-a29f-e0d4b7b49169", + "policy": { + "allowedTools": [ + "idea_list_agents", + "idea_context_read", + "idea_memory_read", + "idea_skill_read", + "idea_workstate_read", + "idea_ticket_read", + "idea_ticket_list", + "idea_ticket_read_carnet", + "idea_sprint_list", + "idea_template_list", + "idea_template_read", + "idea_run_in_background", + "idea_workstate_set", + "idea_ask_agent", + "idea_launch_agent" + ] + } + }, + { + "agentId": "7efa512f-3b3a-47b5-ade0-a2dd13073055", + "policy": { + "allowedTools": [ + "idea_list_agents", + "idea_context_read", + "idea_memory_read", + "idea_skill_read", + "idea_workstate_read", + "idea_ticket_read", + "idea_ticket_list", + "idea_ticket_read_carnet", + "idea_sprint_list", + "idea_template_list", + "idea_template_read", + "idea_workstate_set", + "idea_run_in_background", + "idea_ask_agent", + "idea_launch_agent" + ] + } + }, + { + "agentId": "f8f40941-ecf7-4830-b9de-8818a099f448", + "policy": { + "allowedTools": [ + "idea_list_agents", + "idea_context_read", + "idea_memory_read", + "idea_skill_read", + "idea_workstate_read", + "idea_ticket_read", + "idea_ticket_list", + "idea_ticket_read_carnet", + "idea_sprint_list", + "idea_template_list", + "idea_template_read", + "idea_ticket_update_carnet", + "idea_run_in_background", + "idea_workstate_set", + "idea_ask_agent", + "idea_launch_agent" + ] + } + }, + { + "agentId": "f3408f5d-469c-4f64-9485-d8b218f3ff26", + "policy": { + "allowedTools": [ + "idea_list_agents", + "idea_context_read", + "idea_memory_read", + "idea_skill_read", + "idea_workstate_read", + "idea_ticket_read", + "idea_ticket_list", + "idea_ticket_read_carnet", + "idea_sprint_list", + "idea_template_list", + "idea_template_read", + "idea_ask_agent", + "idea_memory_write", + "idea_ticket_update_carnet", + "idea_run_in_background", + "idea_workstate_set", + "idea_launch_agent" + ] + } + }, + { + "agentId": "9933c93a-b8a1-4164-a3bb-7063fdad747d", + "policy": { + "allowedTools": [ + "idea_list_agents", + "idea_context_read", + "idea_memory_read", + "idea_skill_read", + "idea_workstate_read", + "idea_ticket_read", + "idea_ticket_list", + "idea_ticket_read_carnet", + "idea_sprint_list", + "idea_template_list", + "idea_template_read", + "idea_run_in_background", + "idea_workstate_set", + "idea_ask_agent", + "idea_launch_agent" + ] + } + }, + { + "agentId": "10ee045b-1c41-479e-ba03-dceed9edd495", + "policy": { + "allowedTools": [ + "idea_list_agents", + "idea_context_read", + "idea_memory_read", + "idea_skill_read", + "idea_workstate_read", + "idea_ticket_read", + "idea_ticket_list", + "idea_ticket_read_carnet", + "idea_sprint_list", + "idea_template_list", + "idea_template_read", + "idea_ask_agent", + "idea_run_in_background", + "idea_workstate_set", + "idea_launch_agent" + ] + } + }, + { + "agentId": "8f065f64-ef6e-4a00-af9c-d00be079e3cc", + "policy": { + "allowedTools": [ + "idea_list_agents", + "idea_context_read", + "idea_memory_read", + "idea_skill_read", + "idea_workstate_read", + "idea_ticket_read", + "idea_ticket_list", + "idea_ticket_read_carnet", + "idea_sprint_list", + "idea_template_list", + "idea_template_read", + "idea_ask_agent", + "idea_launch_agent", + "idea_run_in_background", + "idea_workstate_set" + ] + } + } + ] +} diff --git a/.ideai/memory/MEMORY.md b/.ideai/memory/MEMORY.md index 104aea1..2bf186e 100644 --- a/.ideai/memory/MEMORY.md +++ b/.ideai/memory/MEMORY.md @@ -21,3 +21,4 @@ - [gametime-architecture-online-client](gametime-architecture-online-client.md) — memory note gametime-architecture-online-client - [gametime-ux-step-chaining-override](gametime-ux-step-chaining-override.md) — memory note gametime-ux-step-chaining-override - [gametime-architecture-step-chaining-override](gametime-architecture-step-chaining-override.md) — memory note gametime-architecture-step-chaining-override +- [gametime-session-execution-timer-refactor](gametime-session-execution-timer-refactor.md) — memory note gametime-session-execution-timer-refactor diff --git a/.ideai/memory/gametime-session-execution-timer-refactor.md b/.ideai/memory/gametime-session-execution-timer-refactor.md new file mode 100644 index 0000000..65290f5 --- /dev/null +++ b/.ideai/memory/gametime-session-execution-timer-refactor.md @@ -0,0 +1,43 @@ +--- +name: gametime-session-execution-timer-refactor +description: memory note gametime-session-execution-timer-refactor +metadata: + type: project +--- +# GameTime — Refonte exécution séance et logique chronos + +Décision UX/architecture issue de la demande utilisateur du 2026-07-20. + +## Principe d'affichage + +L'écran d'exécution de séance doit organiser les informations autour d'une carte `Exercice actif`, placée sous le compteur `SÉRIE X / Y`. + +Cette carte regroupe : +- nom de l'exercice ; +- accès médias ; +- `Temps de série` si la mesure temps est active ; +- action primaire `Démarrer l'exercice` quand un chrono doit démarrer au début de la série. + +Le temps de série ne doit plus être une information isolée en bas de l'écran. + +## Principe de démarrage + +`Démarrer l'exercice` est le point de départ global. Il lance tous les chronos qui commencent logiquement au début de la série : +- timer de série si `timeEnabled` ; +- chrono de la première étape si cette première étape est de type temps ; +- chrono score de série si `scoreInputMode == stopwatch`. + +L'objectif est de minimiser les actions pendant l'effort, notamment quand l'utilisateur n'a pas le téléphone près de lui. + +## États et invariants + +- Le timer de série est un état persistant dédié, pas un simple `DateTime` UI volatile. +- Pause séance suspend tous les chronos running : série, score chrono, étape, score chrono étape si présent, repos. +- Reprise restaure l'état exact ; un état `Chrono suivant prêt` reste prêt et ne démarre pas automatiquement. +- `Terminer la série` arrête/enregistre les chronos actifs. +- `Passer la série` ignore les chronos et confirme si un chrono ou une séquence est en cours. +- Le repos démarre seulement après terminer/passer la série et doit être pause-aware (`pausedAt` + `accumulatedPausedMs`). + +## Implémentation locale + +Une implémentation a été réalisée sans commit : domaine/application/persistance, écran Flutter et tests ciblés. QA a validé les vérifications exécutables dans le sandbox (`git diff --check`, `dart analyze` exit 0). Les commandes `flutter analyze` et `flutter test` restent à relancer dans un environnement où le SDK Flutter peut écrire dans son cache. \ No newline at end of file diff --git a/.ideai/skills/index.json b/.ideai/skills/index.json new file mode 100644 index 0000000..cfe7777 --- /dev/null +++ b/.ideai/skills/index.json @@ -0,0 +1,11 @@ +{ + "version": 1, + "skills": [ + { + "id": "c5f979a4-4f1a-4ed1-b3ff-1985292214aa", + "name": "basketball-drill-authoring", + "description": null, + "contentHash": "aa07477fc1cf6685" + } + ] +} \ No newline at end of file diff --git a/.ideai/skills/md/c5f979a4-4f1a-4ed1-b3ff-1985292214aa.md b/.ideai/skills/md/c5f979a4-4f1a-4ed1-b3ff-1985292214aa.md new file mode 100644 index 0000000..5a0267e --- /dev/null +++ b/.ideai/skills/md/c5f979a4-4f1a-4ed1-b3ff-1985292214aa.md @@ -0,0 +1,90 @@ +## Objectif + +Produire des fiches de drills basket homogènes, directement exploitables par +DevBackend pour créer les seed data GameTime (entités `Exercise`, `Program`, +`WorkoutTemplate` de `lib/domain/entities.dart`), sans aller-retour d'interprétation. + +Ce skill est destiné à l'agent **Coach**, dans le cadre du ticket **#80 — +Bibliothèque de drills basket de démarrage + séance exemple modifiable**, et +réutilisable pour tout futur enrichissement de la bibliothèque de contenu basket. + +## Catégories à couvrir pour une bibliothèque de démarrage + +- Shoot (tir extérieur, mi-distance) +- Lancers francs +- Dribble / ball-handling +- Finition (layups, floaters, contact) +- Conditionnement (endurance, explosivité spécifique basket) +- Défense (individuelle, déplacements) +- Mobilité / échauffement + +Une bibliothèque de démarrage complète vise au moins un drill par catégorie, sans +obligation d'exhaustivité — mieux vaut peu de drills bien spécifiés que beaucoup de +drills vagues. + +## Gabarit de fiche — un exercice (`Exercise`) + +Pour chaque drill, remplir tous les champs suivants avant de le considérer prêt : + +``` +Nom : (court, concret, ex. "Lancers francs — série de 10") +Catégorie : (une des catégories ci-dessus) +Description : (2-4 phrases : geste, placement, objectif ; vocabulaire basket précis) +Matériel : (ballon / panier / cônes / chrono — jamais de matériel connecté ou de caméra) +Niveau conseillé : (debutant / intermediaire / tous niveaux) + +Mesures activées (au moins une) : +- Temps (hasTimeMeasure) : oui/non — si oui, defaultTargetTimeSeconds +- Répétitions (hasRepsMeasure) : oui/non — si oui, defaultTargetReps +- Score (hasScoreMeasure) : oui/non + - scoreInputMode : manual | stopwatch + - si manual : scoreLabel (ex. "Paniers marqués"), scoreUnit (ex. "sur 10") + - defaultTargetScore ou defaultTargetScoreTimeMs selon le mode + +Étapes (steps, optionnel — seulement si le drill a plusieurs phases distinctes) : +- Étape 1 : nom, type (time|reps), defaultTargetValue, score optionnel +- Étape 2 : ... + +Média souhaité : image et/ou vidéo (décrire l'intention : ex. "photo du placement des +pieds" — ne pas fournir de fichier, c'est à DevBackend/DevFrontend de le résoudre) +``` + +Règles de cohérence à vérifier avant de livrer la fiche : +- Au moins une mesure activée. +- Si score en mode manuel : `scoreLabel` ET `scoreUnit` renseignés. +- Les cibles par défaut (`defaultTarget*`) doivent avoir un sens réel pour un débutant + raisonnable (pas de surcharge, pas de valeur arbitraire). +- Si le drill a plusieurs phases nettement différentes (ex. échauffement puis + chronométré), utiliser `steps` plutôt que de forcer plusieurs mesures sur un seul + exercice plat. + +## Gabarit de fiche — un programme (`Program`) + +``` +Nom : (ex. "Séance shoot & finition") +Repos par défaut entre séries (defaultRestSeconds) : (valeur réaliste, ex. 30-60s) + +Exercices (dans l'ordre) : +1. [Nom exercice] — setsCount : X, mesures activées : [...], cibles : [...], repos + spécifique (restSecondsOverride) si différent du défaut +2. ... +``` + +## Gabarit de fiche — une séance-modèle (`WorkoutTemplate`) + +``` +Nom : (ex. "Séance découverte basket") +Programmes inclus (dans l'ordre) : [Nom programme 1], [Nom programme 2], ... +``` + +## Checklist finale avant de transmettre à Architect/DevBackend + +- [ ] Au moins un drill par catégorie listée ci-dessus. +- [ ] Chaque fiche exercice respecte le gabarit et les règles de cohérence. +- [ ] Au moins un programme d'exemple cohérent (drills compatibles, ordre logique + échauffement → technique → conditionnement). +- [ ] Au moins une séance-modèle d'exemple composée du/des programme(s). +- [ ] Rien ne dépasse le modèle de données actuel (`Exercise`/`Program`/ + `WorkoutTemplate`/`ExerciseStep`) — sinon, remonter à Architect avant de livrer. +- [ ] Aucun drill ne nécessite de matériel connecté, de caméra ou d'abonnement tiers. +- [ ] Le contenu reste éditable/supprimable : pas d'hypothèse de donnée protégée. \ No newline at end of file diff --git a/.ideai/tickets/46/carnet.md b/.ideai/tickets/46/carnet.md index 0e3b0be..78ba1f8 100644 --- a/.ideai/tickets/46/carnet.md +++ b/.ideai/tickets/46/carnet.md @@ -1,6 +1,6 @@ --- issueRef: "#46" -version: 7 -updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} -updatedAt: 1784488112374 +version: 8 +updatedBy: {"kind":"user"} +updatedAt: 1784566354283 --- diff --git a/.ideai/tickets/46/issue.md b/.ideai/tickets/46/issue.md index 4a793ba..845811f 100644 --- a/.ideai/tickets/46/issue.md +++ b/.ideai/tickets/46/issue.md @@ -2,15 +2,15 @@ id: "dda499ac-7197-4321-bd2b-a303510b1bbe" number: 46 title: "Créer un serveur headless pour l'application" -status: "qa" +status: "closed" priority: "low" sprint: "4237adfd-91eb-45ff-9f32-6ce1daa39822" links: [] agentRefs: [{"agentId":"57695b92-24d0-4876-837c-76116e70a6ae","role":"assigned"}] createdBy: {"kind":"user"} -updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedBy: {"kind":"user"} createdAt: 1784379695135 -updatedAt: 1784488112374 -version: 7 +updatedAt: 1784566354283 +version: 8 --- J'aimerais que l'application puisse proposer des services online aussi. Un peu a la manière de Heavy avec la possibilité de partager ses séances etc. A la manière de Heavy, j'aimerais que l'on puisse se créer un compte et s'y connecter, synchroniser son historique de seances, ses séances, ses programmes ainsi que ses exercices. Ce ticket est la partie serveur/web API, il faudra que ça soit un serveur headless linux qui tourne dans un container docker. Il faudra que je puisse y acceder via un reverse proxy qui tourne sur une machine différente de celle du serveur headless mais dans le même réseau local. J'y accederais via une adresse https. le container se lancera ensuite à partir d'un docker-compose.yaml dans lequel tu laissera les champs libre de tout ce qui sera necessaire de configurer (adresse ip du reverse proxy, de la machine sur laquelle tourne le docker si necessaire etc.). Pour la création du serveur, créé un subdirectory spécialement pour cette partie serveur. Dans le dossier serveur à lma racine, je veux un script pour pouvoir push le container sur le gitea qui est déjà lié au projet, je veux aussi le docker-compose.yaml demandé. \ No newline at end of file diff --git a/.ideai/tickets/54/carnet.md b/.ideai/tickets/54/carnet.md index add2e2b..9ed92d0 100644 --- a/.ideai/tickets/54/carnet.md +++ b/.ideai/tickets/54/carnet.md @@ -1,6 +1,6 @@ --- issueRef: "#54" -version: 5 -updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} -updatedAt: 1784487430850 +version: 6 +updatedBy: {"kind":"user"} +updatedAt: 1784566315824 --- diff --git a/.ideai/tickets/54/issue.md b/.ideai/tickets/54/issue.md index e6b4d92..9f844dc 100644 --- a/.ideai/tickets/54/issue.md +++ b/.ideai/tickets/54/issue.md @@ -2,15 +2,15 @@ id: "7e6894d5-36ad-413b-9fda-be3ba26db6cb" number: 54 title: "Exercice à plusieurs étapes" -status: "qa" +status: "closed" priority: "medium" sprint: "1bb8bdf2-9c35-4f53-9a31-1390a47bec63" links: [] agentRefs: [{"agentId":"57695b92-24d0-4876-837c-76116e70a6ae","role":"assigned"}] createdBy: {"kind":"user"} -updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedBy: {"kind":"user"} createdAt: 1784449895047 -updatedAt: 1784487430850 -version: 5 +updatedAt: 1784566315824 +version: 6 --- Dans certains exercices, il peut être interessant qu'il y ai plusieurs étapes. Par exemple, pour un exercice de dribble, il peut être interessant de dire "dribbler main droite pendant 10 sec, puis dribller main gauche pendant 10 secondes, effectuer un double pas et réaliser 10 pompes" par exemple. Le tout représente alors une répétition mais se décompose en 4 étapes avec deux étapes qui se base sur un temps, et deux étapes sur un nombre de répétitions. J'aimerais donc pouvoir définir des étapes pour chaque exercice. L'ensemble de toutes les étape de l'exercice forme une répetition d'une série. Comme pour une série, chacune des étape doit pouvoir avoir un temps à définir (avec une valeur par défaut obligatoire > 0) ou un nombre de répétitions. Dans le cas d'une étape avec un temps, un chronometre est lancé. Dans les 3 dernieres secondes, un bip retenti pour chaque seconde et quand le temps arrive à 0 le bip est plus long que les autres. dans le cas ou deux étapes avec un temps s'enchainent, le second chronometre part directement à la fin de l'etape précédent. Le but est d'enchainer les étapes, il n'y a pas de pauses entre les différentes étapes. On eput aussi proposer de renseigner un score pour chaque étape de la même façon que pour les série. \ No newline at end of file diff --git a/.ideai/tickets/61/carnet.md b/.ideai/tickets/61/carnet.md index 727f7e9..086eaba 100644 --- a/.ideai/tickets/61/carnet.md +++ b/.ideai/tickets/61/carnet.md @@ -1,8 +1,8 @@ --- issueRef: "#61" -version: 3 -updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} -updatedAt: 1784485187502 +version: 5 +updatedBy: {"kind":"user"} +updatedAt: 1784650797661 --- Plan de séance : résumé de séquence par série (via `ActiveExerciseStepUseCases.readProgress`). Historique : détail des résultats d'étapes groupés par passage (durée/répétitions, score d'étape, badge "Passée" pour skipped), réutilise `WorkoutHistory.stepResults` déjà peuplé par #58. 102/102 tests verts, `flutter analyze` clean, APK debug buildé avec succès. diff --git a/.ideai/tickets/61/issue.md b/.ideai/tickets/61/issue.md index 0086796..cd4bf89 100644 --- a/.ideai/tickets/61/issue.md +++ b/.ideai/tickets/61/issue.md @@ -8,9 +8,9 @@ sprint: null links: [{"target":"#54","kind":"relatesTo"},{"target":"#58","kind":"dependsOn"}] agentRefs: [{"agentId":"9933c93a-b8a1-4164-a3bb-7063fdad747d","role":"assigned"}] createdBy: {"kind":"agent","agent_id":"f8f40941-ecf7-4830-b9de-8818a099f448"} -updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedBy: {"kind":"user"} createdAt: 1784481541650 -updatedAt: 1784485187502 -version: 3 +updatedAt: 1784650797661 +version: 5 --- Afficher les résultats d'étapes dans le plan de séance et l'historique sans remplacer les résultats de série. Une série avec étapes garde son état global `à faire/en cours/terminée/passée`; le détail affiche les passages, étapes terminées/passées, durées/répétitions et scores d'étape. L'édition ponctuelle d'une série passée/terminée permet de corriger les valeurs enregistrées sans rejouer la séquence interactive et sans déplacer la progression courante. \ No newline at end of file diff --git a/.ideai/tickets/73/carnet.md b/.ideai/tickets/73/carnet.md index 0877a8b..89c730f 100644 --- a/.ideai/tickets/73/carnet.md +++ b/.ideai/tickets/73/carnet.md @@ -1,6 +1,6 @@ --- issueRef: "#73" -version: 4 -updatedBy: {"kind":"user"} -updatedAt: 1784493253775 +version: 5 +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedAt: 1784565595136 --- diff --git a/.ideai/tickets/73/issue.md b/.ideai/tickets/73/issue.md index 7aa61a7..1f7d8c8 100644 --- a/.ideai/tickets/73/issue.md +++ b/.ideai/tickets/73/issue.md @@ -2,15 +2,15 @@ id: "5ebceb98-b5d4-4a7d-8d4e-ab88c73a4c76" number: 73 title: "Pouvoir enchainer les chronos des étapes" -status: "open" +status: "qa" priority: "medium" sprint: null links: [{"target":"#72","kind":"relatesTo"}] agentRefs: [{"agentId":"57695b92-24d0-4876-837c-76116e70a6ae","role":"assigned"}] createdBy: {"kind":"user"} -updatedBy: {"kind":"user"} +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} createdAt: 1784493103354 -updatedAt: 1784493253775 -version: 4 +updatedAt: 1784565595136 +version: 5 --- Dans le cas ou deux étapes à chronos s'enchainent, j'aimerais qu'une option proposant d'enchainer le start des chrono lorsque le rpécédent arrive à 0 soit proposé. Cette option serait disponible à la création de l'exercice, mais pourrait aussi être override dans le programme ainsi que dans la séance \ No newline at end of file diff --git a/.ideai/tickets/79/carnet.md b/.ideai/tickets/79/carnet.md index 97f4bd4..a34c28f 100644 --- a/.ideai/tickets/79/carnet.md +++ b/.ideai/tickets/79/carnet.md @@ -1,6 +1,6 @@ --- issueRef: "#79" -version: 1 -updatedBy: {"kind":"agent","agent_id":"f8f40941-ecf7-4830-b9de-8818a099f448"} -updatedAt: 1784547247343 +version: 2 +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedAt: 1784565590789 --- diff --git a/.ideai/tickets/79/issue.md b/.ideai/tickets/79/issue.md index 5bd38bd..d9402ae 100644 --- a/.ideai/tickets/79/issue.md +++ b/.ideai/tickets/79/issue.md @@ -2,15 +2,15 @@ id: "107fc29b-cd1d-40cc-9505-61180d081022" number: 79 title: "[QA] Validation auto-enchaînement configurable des chronos d'étapes" -status: "open" +status: "qa" priority: "medium" sprint: null links: [{"target":"#73","kind":"relatesTo"},{"target":"#78","kind":"dependsOn"}] agentRefs: [{"agentId":"7efa512f-3b3a-47b5-ade0-a2dd13073055","role":"assigned"}] createdBy: {"kind":"agent","agent_id":"f8f40941-ecf7-4830-b9de-8818a099f448"} -updatedBy: {"kind":"agent","agent_id":"f8f40941-ecf7-4830-b9de-8818a099f448"} +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} createdAt: 1784547247343 -updatedAt: 1784547247343 -version: 1 +updatedAt: 1784565590789 +version: 2 --- Valider le réglage d'auto-enchaînement des chronos d'étapes : défaut true sur anciens/nouveaux exercices, override programme puis séance avec retour héritage, résolution séance > programme > exercice, comportement Temps->Temps true et false, plusieurs chronos consécutifs, fin de passage vers passage suivant, pause/reprise/kill app dans l'état `Chrono suivant prêt`, absence de régression sur étapes répétitions et skips. \ No newline at end of file diff --git a/.ideai/tickets/80/carnet.md b/.ideai/tickets/80/carnet.md new file mode 100644 index 0000000..163e358 --- /dev/null +++ b/.ideai/tickets/80/carnet.md @@ -0,0 +1,28 @@ +--- +issueRef: "#80" +version: 4 +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedAt: 1784665470112 +--- +## Spec UX (livrée) + +Bibliothèque d'exercices basket de démarrage (7 catégories, ~20 exercices), programme "Fondations basket - 45 min" (8 exercices), séance-modèle "Séance exemple - Fondations basket", règles UX (badge Exemple, éditable/supprimable, anti-réapparition, états vides). Détail complet dans l'historique de la conversation d'orchestration Main. + +## Plan technique Architect (livré) + +Migration Drift v16 : ajout `category` (enum ExerciseCategory: shoot, freeThrows, dribble, finishing, conditioning, defense, mobility, uncategorized) + `is_example` sur exercises/programs/workout_templates. Table `local_seed_metadata` (key, version, applied_at) pour tracker `starterSeedVersion=1`. Use case `SeedStarterContentUseCase` appelé dans `AppBootstrap.create()`, transactionnel, "base vide" = aucune ligne (y compris soft-deleted) dans exercises/programs/workout_templates. IDs stables déterministes type `starter-v1-exercise-form-shooting`. Données seed en Dart const (`lib/application/starter_content/basket_starter_seed_v1.dart`), pas JSON. Séance-modèle via `WorkoutTemplateProgram.snapshotFromProgram`. Contenu seed = `syncState=localOnly`, pas de sync serveur automatique. + +Découpage : +- Lot B1 (DevBackend) : schéma/domaine — ExerciseCategory, champs category/isExample, migration v16, mappers, tests migration. +- Lot B2 (DevBackend) : seed applicatif — ports StarterSeedStateRepository/StarterContentRepository, SeedStarterContentUseCase, basket_starter_seed_v1.dart (contenu complet UX), adapter Drift transactionnel, branchement AppBootstrap. +- Lot B3 (DevBackend/QA) : tests (seed unique, non-réapparition, snapshots programme/séance corrects, catégories/isExample persistés). +- Lot F1/F2 (DevFrontend) : badge "Exemple" bibliothèque/programmes/séances, affichage category. +- Lot F3 (DevFrontend) : première ouverture / états vides, dépend du résultat du seed use case. + +## Décisions Main sur questions Architect +1. Badge "Exemple" conservé après modification par l'utilisateur (provenance, pas immutabilité) → OK, suivre la reco Architect. +2. Contenu exemple non synchronisé au serveur par défaut → OK, suivre la reco Architect. +3. Catégorie `uncategorized` visible sous "Autres" dans l'UI si nécessaire → OK, suivre la reco Architect. +4. Liste complète des ~20 exercices : transmise intégralement à DevBackend par Main (spec UX complète disponible). + +Prochaine étape : Git pour la branche, puis DevBackend (B1+B2+B3). \ No newline at end of file diff --git a/.ideai/tickets/80/issue.md b/.ideai/tickets/80/issue.md new file mode 100644 index 0000000..0c1c143 --- /dev/null +++ b/.ideai/tickets/80/issue.md @@ -0,0 +1,25 @@ +--- +id: "8f4ea0ec-ef5a-42e0-bcf4-9eaa751bea94" +number: 80 +title: "Bibliothèque de drills basket de démarrage + séance exemple modifiable" +status: "inProgress" +priority: "high" +sprint: null +links: [] +agentRefs: [] +createdBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +createdAt: 1784650708413 +updatedAt: 1784665470112 +version: 4 +--- +Constat Commercial : le socle applicatif (exercices/programmes/séances/exécution/historique) est déjà solide, mais l'app démarre vide. Les concurrents basket (94FEETOFGAME) et musculation (Hevy, JEFIT) gagnent en crédibilité grâce à un contenu de départ. + +Objectif : fournir dès l'installation une bibliothèque d'exercices basket courants (shoot, lancers francs, dribble, finition, conditionnement, défense, mobilité) et au moins un programme + une séance-modèle exemple, immédiatement modifiables, pour qu'un nouvel utilisateur n'ait jamais un écran vide. + +Périmètre global (à cadrer/découper par UX puis Architect avant implémentation) : +- Contenu basket de départ (liste d'exercices, mesures par défaut, textes). +- Programme(s) et séance(s)-modèle d'exemple pré-remplis. +- Stratégie de seed (première ouverture, pas de compte requis, éditable/supprimable sans casser l'app). + +Priorité court terme d'après l'analyse marché (cf. mémoire gametime-commercial-positioning-2026-07). \ No newline at end of file diff --git a/.ideai/tickets/81/carnet.md b/.ideai/tickets/81/carnet.md new file mode 100644 index 0000000..58ebf1b --- /dev/null +++ b/.ideai/tickets/81/carnet.md @@ -0,0 +1,18 @@ +--- +issueRef: "#81" +version: 3 +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedAt: 1784665481490 +--- +## Spec UX (livrée) + +Bloc compact "Références" dans l'écran d'exécution (workout_execution_screen.dart), sous le nom de l'exercice, avant la séquence d'étapes/champs de résultat. Deux infos max : "Dernière" (résultat de la même série que l'historique le plus récent, fallback dernière série dispo) et "Record" (meilleure valeur toutes séances confondues, règle de meilleur selon type de mesure : score manuel/reps = max, score chrono = min, temps = max). États : loading, avec dernière+record, dernière seule, record seul, vide sans historique ("Première fois sur cet exercice"), vide sans mesure pertinente, erreur (non bloquant). Pour exercices à étapes : reste au niveau série dans le bloc principal, détail par étape optionnel (bottom sheet), non bloquant pour le ticket. + +Exigences techniques : +- Use case `getExercisePerformanceReference(exerciseId, activeMeasures, currentSetIndex)` retournant `ExercisePerformanceReference { last, record, hasAnyHistoryForExercise }` +- Matching par identité stable de l'exercice source (pas par nom sauf fallback validé Architect), historiques d'exercices archivés restent exploitables +- Ignorer séries skipped/valeurs nulles, ne lire que historiques terminés (pas séance active) +- Chargement non bloquant, skeleton/"Chargement…", erreur non bloquante "Références indisponibles" +- Composant DevFrontend réutilisable `PerformanceReferenceCard` avec formatage temps/score selon règles UX + +Prochaine étape : Architect cadre l'implémentation technique (requêtes historique, ports/use case, découpage Dev). \ No newline at end of file diff --git a/.ideai/tickets/81/issue.md b/.ideai/tickets/81/issue.md new file mode 100644 index 0000000..1e0e01d --- /dev/null +++ b/.ideai/tickets/81/issue.md @@ -0,0 +1,24 @@ +--- +id: "3d94d624-86a2-4f92-8766-2e5d06815f40" +number: 81 +title: "Afficher la dernière performance / meilleur score pendant l'exécution" +status: "inProgress" +priority: "high" +sprint: null +links: [] +agentRefs: [] +createdBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +createdAt: 1784650712105 +updatedAt: 1784665481490 +version: 3 +--- +Constat Commercial : les trackers de référence (Hevy, Strong) motivent l'utilisateur en montrant la dernière série ou le record pendant qu'il saisit sa performance en cours. GameTime ne l'affiche pas encore pendant l'exécution. + +Objectif : pendant l'exécution d'une séance, afficher pour l'exercice en cours la dernière valeur enregistrée (répétitions/score/temps) et éventuellement le meilleur score, en s'appuyant sur l'historique déjà existant. + +Périmètre global (à cadrer UX puis Architect/DevBackend/DevFrontend) : +- Requête historique la plus récente / meilleure par exercice. +- Affichage discret dans l'écran d'exécution, sans surcharger l'UI existante. + +Priorité court terme d'après l'analyse marché (cf. mémoire gametime-commercial-positioning-2026-07). \ No newline at end of file diff --git a/.ideai/tickets/82/carnet.md b/.ideai/tickets/82/carnet.md new file mode 100644 index 0000000..47ba701 --- /dev/null +++ b/.ideai/tickets/82/carnet.md @@ -0,0 +1,6 @@ +--- +issueRef: "#82" +version: 1 +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedAt: 1784650716408 +--- diff --git a/.ideai/tickets/82/issue.md b/.ideai/tickets/82/issue.md new file mode 100644 index 0000000..6c485fe --- /dev/null +++ b/.ideai/tickets/82/issue.md @@ -0,0 +1,24 @@ +--- +id: "b9f867d4-b67d-4edf-b6c3-c3c7547dcb50" +number: 82 +title: "Statistiques de progression (volume, progression par exercice/programme)" +status: "open" +priority: "medium" +sprint: null +links: [] +agentRefs: [] +createdBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +createdAt: 1784650716408 +updatedAt: 1784650716408 +version: 1 +--- +Constat Commercial : l'historique actuel liste les séances jouées mais ne donne pas de lecture de progression. Les concurrents (JEFIT, Fitbod) valorisent fortement les graphiques de progression et le volume d'entraînement pour donner une raison de revenir. + +Objectif : ajouter une vue statistiques simple mais motivante — volume de séances/temps total, progression d'un score/mesure par exercice dans le temps, éventuellement un indicateur de régularité (streak) non culpabilisant. + +Périmètre global (UX pour la forme des stats, Architect pour l'agrégation des données d'historique, DevFrontend pour l'écran) : +- Choix des métriques initiales (rester simple, cohérent avec le principe "stats simples" déjà acté). +- Écran ou section dédiée, alimentée par les données d'historique existantes. + +Priorité moyen terme d'après l'analyse marché (cf. mémoire gametime-commercial-positioning-2026-07). \ No newline at end of file diff --git a/.ideai/tickets/83/carnet.md b/.ideai/tickets/83/carnet.md new file mode 100644 index 0000000..68e2872 --- /dev/null +++ b/.ideai/tickets/83/carnet.md @@ -0,0 +1,6 @@ +--- +issueRef: "#83" +version: 1 +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedAt: 1784650720801 +--- diff --git a/.ideai/tickets/83/issue.md b/.ideai/tickets/83/issue.md new file mode 100644 index 0000000..8a64ce7 --- /dev/null +++ b/.ideai/tickets/83/issue.md @@ -0,0 +1,24 @@ +--- +id: "f9bee681-581c-4c65-a39a-34ed9cf67feb" +number: 83 +title: "Duplication rapide de programmes/séances-modèles + tags de filtrage" +status: "open" +priority: "medium" +sprint: null +links: [] +agentRefs: [] +createdBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +createdAt: 1784650720801 +updatedAt: 1784650720801 +version: 1 +--- +Constat Commercial : les apps concurrentes permettent de dupliquer/adapter rapidement un programme existant plutôt que de le recréer, et d'organiser une bibliothèque grandissante par tags (compétence, matériel, durée, intensité). + +Objectif : permettre de dupliquer un programme ou une séance-modèle en un geste pour l'adapter, et ajouter un système de tags/filtres simple sur exercices/programmes/séances pour garder la bibliothèque exploitable quand elle grossit. + +Périmètre global (Architect pour le modèle de tags et la duplication en profondeur, UX pour l'emplacement des actions et filtres, DevBackend/DevFrontend pour l'implémentation) : +- Duplication d'un programme/séance-modèle avec ses exercices/cibles. +- Modèle de tags léger, filtrage dans les écrans de bibliothèque existants. + +Priorité moyen terme d'après l'analyse marché (cf. mémoire gametime-commercial-positioning-2026-07). \ No newline at end of file diff --git a/.ideai/tickets/84/carnet.md b/.ideai/tickets/84/carnet.md new file mode 100644 index 0000000..133cd49 --- /dev/null +++ b/.ideai/tickets/84/carnet.md @@ -0,0 +1,6 @@ +--- +issueRef: "#84" +version: 1 +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedAt: 1784650724409 +--- diff --git a/.ideai/tickets/84/issue.md b/.ideai/tickets/84/issue.md new file mode 100644 index 0000000..97d99fc --- /dev/null +++ b/.ideai/tickets/84/issue.md @@ -0,0 +1,24 @@ +--- +id: "d21e84b6-f863-4225-ba75-840b84880491" +number: 84 +title: "Export/import local des données (sauvegarde indépendante de la sync serveur)" +status: "open" +priority: "medium" +sprint: null +links: [] +agentRefs: [] +createdBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +createdAt: 1784650724409 +updatedAt: 1784650724409 +version: 1 +--- +Constat Commercial : la différenciation offline-first de GameTime doit rester crédible même sans compte ni serveur. Un utilisateur qui n'active jamais la couche online doit pouvoir sauvegarder/restaurer ses données autrement. + +Objectif : permettre d'exporter puis réimporter localement l'ensemble des données utilisateur (exercices, programmes, séances-modèles, historique), en fichier, indépendamment du compte/sync en cours de finalisation (#63-70). + +Périmètre global (Architect pour le format d'export et les garanties de cohérence, DevBackend pour l'implémentation, QA pour la validation round-trip) : +- Format d'export stable et complet. +- Import avec gestion des conflits/doublons. + +Priorité moyen terme d'après l'analyse marché (cf. mémoire gametime-commercial-positioning-2026-07). \ No newline at end of file diff --git a/.ideai/tickets/85/carnet.md b/.ideai/tickets/85/carnet.md new file mode 100644 index 0000000..3c77b92 --- /dev/null +++ b/.ideai/tickets/85/carnet.md @@ -0,0 +1,6 @@ +--- +issueRef: "#85" +version: 1 +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedAt: 1784650728867 +--- diff --git a/.ideai/tickets/85/issue.md b/.ideai/tickets/85/issue.md new file mode 100644 index 0000000..b03e10e --- /dev/null +++ b/.ideai/tickets/85/issue.md @@ -0,0 +1,22 @@ +--- +id: "78ce00f0-b70c-4e21-a22a-42a78f31fa48" +number: 85 +title: "Packs de séances partageables (au-delà du partage ciblé existant)" +status: "open" +priority: "low" +sprint: null +links: [] +agentRefs: [] +createdBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +createdAt: 1784650728867 +updatedAt: 1784650728867 +version: 1 +--- +Constat Commercial : certains concurrents s'appuient sur des contenus créés par des coachs/communauté. GameTime a déjà une base de partage ciblé de programmes/séances entre comptes (#51, #66, #69, en QA) ; l'étape suivante serait des "packs" de séances plus larges (coach ou communauté), mais uniquement après arbitrage explicite de Main sur le positionnement (éviter de dériver vers un réseau social ou une marketplace). + +Objectif : cadrer si et comment proposer des packs de séances/programmes prêts à l'emploi, en s'appuyant sur la mécanique de partage déjà construite, sans complexifier prématurément. + +Ne pas démarrer avant validation Main + retour d'usage sur le partage ciblé actuel. + +Priorité long terme d'après l'analyse marché (cf. mémoire gametime-commercial-positioning-2026-07). \ No newline at end of file diff --git a/.ideai/tickets/86/carnet.md b/.ideai/tickets/86/carnet.md new file mode 100644 index 0000000..e7e144d --- /dev/null +++ b/.ideai/tickets/86/carnet.md @@ -0,0 +1,6 @@ +--- +issueRef: "#86" +version: 1 +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedAt: 1784650732823 +--- diff --git a/.ideai/tickets/86/issue.md b/.ideai/tickets/86/issue.md new file mode 100644 index 0000000..2778761 --- /dev/null +++ b/.ideai/tickets/86/issue.md @@ -0,0 +1,22 @@ +--- +id: "c739bebd-bdf5-4729-8b0a-76d8b3e25efc" +number: 86 +title: "Analytics basket avancées (zones de tir, charge d'entraînement)" +status: "open" +priority: "low" +sprint: null +links: [] +agentRefs: [] +createdBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +createdAt: 1784650732823 +updatedAt: 1784650732823 +version: 1 +--- +Constat Commercial : les apps basket avancées (HomeCourt) proposent des analytics spécifiques (zones de tir, charge, fatigue) qui dépassent les stats simples déjà prévues. C'est un axe de différenciation réel mais avancé, à envisager seulement une fois le socle manuel (exécution, historique, stats simples) mature. + +Objectif : explorer des analytics basket-spécifiques construites sur les mesures/scores déjà saisis manuellement (pas de tracking caméra), par exemple répartition de réussite par exercice de tir, charge hebdomadaire estimée, ressenti de fatigue optionnel. + +À ne cadrer qu'après la mise en place des statistiques de progression simples (ticket dédié plus haut) et validation Main/UX/Architect sur la pertinence et la complexité. + +Priorité long terme d'après l'analyse marché (cf. mémoire gametime-commercial-positioning-2026-07). \ No newline at end of file diff --git a/.ideai/tickets/87/carnet.md b/.ideai/tickets/87/carnet.md new file mode 100644 index 0000000..c55cfe5 --- /dev/null +++ b/.ideai/tickets/87/carnet.md @@ -0,0 +1,6 @@ +--- +issueRef: "#87" +version: 1 +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedAt: 1784650736449 +--- diff --git a/.ideai/tickets/87/issue.md b/.ideai/tickets/87/issue.md new file mode 100644 index 0000000..b773278 --- /dev/null +++ b/.ideai/tickets/87/issue.md @@ -0,0 +1,22 @@ +--- +id: "2a9fcbda-9bd3-4e1b-853d-02abf3f2ef8c" +number: 87 +title: "Veille : tracking caméra/IA basket (exploration, pas d'implémentation)" +status: "open" +priority: "low" +sprint: null +links: [] +agentRefs: [] +createdBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} +createdAt: 1784650736449 +updatedAt: 1784650736449 +version: 1 +--- +Constat Commercial : HomeCourt/DribbleUp montrent qu'un tracking caméra ou assisté par IA est différenciant mais coûteux, risqué techniquement et souvent lié à du matériel ou de l'abonnement. Ce n'est pas une priorité tant que le socle manuel de GameTime n'est pas excellent. + +Objectif : ticket de veille/R&D, pas d'implémentation. Revisiter périodiquement avec Commercial une fois les phases court et moyen terme closes, pour décider si une expérimentation ciblée (ex. simple comptage de tirs via caméra) a un ROI justifiable pour GameTime. + +Ne pas démarrer sans arbitrage explicite de Main. + +Priorité long terme d'après l'analyse marché (cf. mémoire gametime-commercial-positioning-2026-07). \ No newline at end of file diff --git a/.ideai/tickets/88/carnet.md b/.ideai/tickets/88/carnet.md new file mode 100644 index 0000000..34bf8ca --- /dev/null +++ b/.ideai/tickets/88/carnet.md @@ -0,0 +1,6 @@ +--- +issueRef: "#88" +version: 3 +updatedBy: {"kind":"user"} +updatedAt: 1784665050645 +--- diff --git a/.ideai/tickets/88/issue.md b/.ideai/tickets/88/issue.md new file mode 100644 index 0000000..8cb1812 --- /dev/null +++ b/.ideai/tickets/88/issue.md @@ -0,0 +1,16 @@ +--- +id: "da3a2685-d581-4a50-a439-be01b8e596ee" +number: 88 +title: "[Bug] error au lancement d'un exercice" +status: "qa" +priority: "critical" +sprint: null +links: [] +agentRefs: [] +createdBy: {"kind":"user"} +updatedBy: {"kind":"user"} +createdAt: 1784651166409 +updatedAt: 1784665050645 +version: 3 +--- +Quand j'essaie de lancer le chrono d'un exercice, j'ai une erreur qui dit Impossible de demarrer l'exerccie: Invalid arguments (params[1]): Allowed parameters must either be null or or bool, int, nul, string... \ No newline at end of file diff --git a/.ideai/tickets/90/carnet.md b/.ideai/tickets/90/carnet.md new file mode 100644 index 0000000..c26919f --- /dev/null +++ b/.ideai/tickets/90/carnet.md @@ -0,0 +1,6 @@ +--- +issueRef: "#90" +version: 4 +updatedBy: {"kind":"user"} +updatedAt: 1784665064484 +--- diff --git a/.ideai/tickets/90/issue.md b/.ideai/tickets/90/issue.md new file mode 100644 index 0000000..5c53856 --- /dev/null +++ b/.ideai/tickets/90/issue.md @@ -0,0 +1,16 @@ +--- +id: "a04feb24-2a6f-46b7-8e36-b8a113b7c2b5" +number: 90 +title: "[UI] Rework UI séance pour enlever le scroll" +status: "qa" +priority: "medium" +sprint: null +links: [] +agentRefs: [{"agentId":"f3408f5d-469c-4f64-9485-d8b218f3ff26","role":"assigned"}] +createdBy: {"kind":"user"} +updatedBy: {"kind":"user"} +createdAt: 1784651486750 +updatedAt: 1784665064484 +version: 4 +--- +J'aimerais que l'UI pednant une séance soit légèrement revu pour faire en sorte que l'affichage n'ai aps de scroll, et que tout rentre directement dans l'écran du téléphone lorsqu'on a plusieurs étapes dans un exercice. Actuellement, lorsqu'un exercice propose plusieurs étapes, un scroll est obligatoire pour afficher l'étape et les bouton "Terminer la série" et "Passer la série". J'aiemrais une proposition d'UI/UX pour ça \ No newline at end of file diff --git a/.ideai/tickets/91/carnet.md b/.ideai/tickets/91/carnet.md new file mode 100644 index 0000000..ef9b7e6 --- /dev/null +++ b/.ideai/tickets/91/carnet.md @@ -0,0 +1,6 @@ +--- +issueRef: "#91" +version: 3 +updatedBy: {"kind":"user"} +updatedAt: 1784656427938 +--- diff --git a/.ideai/tickets/91/issue.md b/.ideai/tickets/91/issue.md new file mode 100644 index 0000000..f76f554 --- /dev/null +++ b/.ideai/tickets/91/issue.md @@ -0,0 +1,16 @@ +--- +id: "990a5e5a-8490-43ab-b7f6-7cae61be25fd" +number: 91 +title: "Interface montre synchronisée" +status: "open" +priority: "low" +sprint: null +links: [] +agentRefs: [] +createdBy: {"kind":"user"} +updatedBy: {"kind":"user"} +createdAt: 1784656109713 +updatedAt: 1784656427938 +version: 3 +--- +J'aimerais avoir une version pour ma montre android qui soit synchronisée avec l'application téléphone. Elle me permettrait entre autre de lancer/arrêter les chronos (donc dans le cas d'un exercice sous chrono, de lancer le chrono ou de le mettre en pause) ou dans le cas d'une étape de lancer le chrono de l'étape, en gardant la décision prise comme quoi si la première étape est un chrono et que l'exercice est sous chrono, le lancement de chrono est commun a l'exercice et à l'étape. Ca permettrait en plus de ça de pouvoir passer une étape, une séquence, une série ou terminer une série. Bref, pouvoir gérer sa séance depuis sa montre. l'UX/UI est bien sur a voir avec l'agent UX pour savoir comment organiser ça. Heavy propose une fonctionnalité similaire si il y a besoin d'une inspiration \ No newline at end of file diff --git a/.ideai/tickets/counter.json b/.ideai/tickets/counter.json index ad1925c..1e2c60e 100644 --- a/.ideai/tickets/counter.json +++ b/.ideai/tickets/counter.json @@ -1,3 +1,3 @@ { - "nextNumber": 80 + "nextNumber": 92 } \ No newline at end of file diff --git a/.ideai/tickets/index.json b/.ideai/tickets/index.json index 234d05f..9e54055 100644 --- a/.ideai/tickets/index.json +++ b/.ideai/tickets/index.json @@ -525,13 +525,13 @@ "issueRef": "#46", "path": "46", "title": "Créer un serveur headless pour l'application", - "status": "qa", + "status": "closed", "priority": "low", "sprint": "4237adfd-91eb-45ff-9f32-6ce1daa39822", "assignedAgentIds": [ "57695b92-24d0-4876-837c-76116e70a6ae" ], - "updatedAt": 1784488112374 + "updatedAt": 1784566354283 }, { "issueRef": "#47", @@ -607,13 +607,13 @@ "issueRef": "#54", "path": "54", "title": "Exercice à plusieurs étapes", - "status": "qa", + "status": "closed", "priority": "medium", "sprint": "1bb8bdf2-9c35-4f53-9a31-1390a47bec63", "assignedAgentIds": [ "57695b92-24d0-4876-837c-76116e70a6ae" ], - "updatedAt": 1784487430850 + "updatedAt": 1784566315824 }, { "issueRef": "#56", @@ -685,7 +685,7 @@ "assignedAgentIds": [ "9933c93a-b8a1-4164-a3bb-7063fdad747d" ], - "updatedAt": 1784485187502 + "updatedAt": 1784650797661 }, { "issueRef": "#62", @@ -823,13 +823,13 @@ "issueRef": "#73", "path": "73", "title": "Pouvoir enchainer les chronos des étapes", - "status": "open", + "status": "qa", "priority": "medium", "sprint": null, "assignedAgentIds": [ "57695b92-24d0-4876-837c-76116e70a6ae" ], - "updatedAt": 1784493253775 + "updatedAt": 1784565595136 }, { "issueRef": "#74", @@ -895,13 +895,125 @@ "issueRef": "#79", "path": "79", "title": "[QA] Validation auto-enchaînement configurable des chronos d'étapes", - "status": "open", + "status": "qa", "priority": "medium", "sprint": null, "assignedAgentIds": [ "7efa512f-3b3a-47b5-ade0-a2dd13073055" ], - "updatedAt": 1784547247343 + "updatedAt": 1784565590789 + }, + { + "issueRef": "#80", + "path": "80", + "title": "Bibliothèque de drills basket de démarrage + séance exemple modifiable", + "status": "inProgress", + "priority": "high", + "sprint": null, + "assignedAgentIds": [], + "updatedAt": 1784665470112 + }, + { + "issueRef": "#81", + "path": "81", + "title": "Afficher la dernière performance / meilleur score pendant l'exécution", + "status": "inProgress", + "priority": "high", + "sprint": null, + "assignedAgentIds": [], + "updatedAt": 1784665481490 + }, + { + "issueRef": "#82", + "path": "82", + "title": "Statistiques de progression (volume, progression par exercice/programme)", + "status": "open", + "priority": "medium", + "sprint": null, + "assignedAgentIds": [], + "updatedAt": 1784650716408 + }, + { + "issueRef": "#83", + "path": "83", + "title": "Duplication rapide de programmes/séances-modèles + tags de filtrage", + "status": "open", + "priority": "medium", + "sprint": null, + "assignedAgentIds": [], + "updatedAt": 1784650720801 + }, + { + "issueRef": "#84", + "path": "84", + "title": "Export/import local des données (sauvegarde indépendante de la sync serveur)", + "status": "open", + "priority": "medium", + "sprint": null, + "assignedAgentIds": [], + "updatedAt": 1784650724409 + }, + { + "issueRef": "#85", + "path": "85", + "title": "Packs de séances partageables (au-delà du partage ciblé existant)", + "status": "open", + "priority": "low", + "sprint": null, + "assignedAgentIds": [], + "updatedAt": 1784650728867 + }, + { + "issueRef": "#86", + "path": "86", + "title": "Analytics basket avancées (zones de tir, charge d'entraînement)", + "status": "open", + "priority": "low", + "sprint": null, + "assignedAgentIds": [], + "updatedAt": 1784650732823 + }, + { + "issueRef": "#87", + "path": "87", + "title": "Veille : tracking caméra/IA basket (exploration, pas d'implémentation)", + "status": "open", + "priority": "low", + "sprint": null, + "assignedAgentIds": [], + "updatedAt": 1784650736449 + }, + { + "issueRef": "#88", + "path": "88", + "title": "[Bug] error au lancement d'un exercice", + "status": "qa", + "priority": "critical", + "sprint": null, + "assignedAgentIds": [], + "updatedAt": 1784665050645 + }, + { + "issueRef": "#90", + "path": "90", + "title": "[UI] Rework UI séance pour enlever le scroll", + "status": "qa", + "priority": "medium", + "sprint": null, + "assignedAgentIds": [ + "f3408f5d-469c-4f64-9485-d8b218f3ff26" + ], + "updatedAt": 1784665064484 + }, + { + "issueRef": "#91", + "path": "91", + "title": "Interface montre synchronisée", + "status": "open", + "priority": "low", + "sprint": null, + "assignedAgentIds": [], + "updatedAt": 1784656427938 } ] } \ No newline at end of file