NotreCouple 1.2 — livre d’aventures et accomplissements
Cadrage mis à jour le 5 octobre 2026 : ancien périmètre V1.3 repris dans la prochaine release 1.2. Module Plane : notrecouple-release-12. Plan de livraison.
Le modèle, le moteur et le livre sont déjà intégrés à la 1.1.1 (PR #431, #646, #652 et promotion #953). Ce contrat décrit les invariants du socle et les extensions à terminer en 1.2 : récompenses/personnalisation, quête facultative et validation intégrée. Les anciennes références de lots sont conservées ; les preuves restantes se qualifient sans réimplémenter le socle.
Intention et boucle produit
Le couple construit un livre d’aventures commun en choisissant une activité, en participant chacun, en découvrant le résultat ensemble puis en conservant un jalon. La récompense rend visible ce vécu. La prochaine proposition donne envie de revenir à son rythme.
Trois horizons : progression dans Jouer pendant la séance, quête facultative sur une semaine, accomplissements permanents dans Nous. Une seule prochaine action dominante. La fin de séance reste une fin satisfaisante et propose aussi de terminer pour aujourd’hui.
La 1.2 comprend un livre dans Nous, douze accomplissements, trois familles, un prochain jalon, des récompenses visuelles et une quête hebdomadaire facultative. Aucun XP individuel, classement, score de qualité relationnelle, monnaie, boutique ou perte d’acquis pour absence. Les contenus de base restent accessibles. Aucun univers intime n’est obligatoire pour compléter une collection.
Lot 1 — contrat de comptage
L’unité 1.2 est une découverte partagée, et non une expérience réelle prétendument vérifiée. Le code actuel couple_play_store.daily_state expose revealed quand les réponses correspondent aux deux membres actifs. submit_answer écrit sous transaction et verrouille la sélection. Le moteur du lot 2 devra enregistrer la transition vers cet état au moment de la seconde réponse, dans la même transaction. Un GET, le polling ou une animation ne produisent aucun événement.
Événement projeté : shared_discovery_v1, clé unique (couple_id, day_key, activity_id), avec horodatage serveur de première révélation et identifiant d’univers issu du catalogue serveur. Rejouer la même activité le même jour ne compte qu’une fois ; un autre jour peut compter comme nouvelle découverte. Le client ne choisit ni couple, ni date de gain, ni univers autoritaire.
Un jour actif est une date UTC contenant au moins une découverte partagée, calculée depuis l’horodatage serveur du gain (pas depuis le day_key fourni pour la séance). Une semaine active est une semaine ISO UTC contenant un tel jour. Les deux réponses peuvent être asynchrones ; le gain est daté de la seconde. Le fuseau UTC est fixe pour cette version et doit être expliqué dans l’aide ; un changement de fuseau futur exige un contrat de migration.
Un univers exploré contient au moins une découverte partagée éligible. Le mapping activité→univers est versionné côté serveur ; un identifiant inconnu est exclu du compteur d’univers et doit être corrigé avant activation du catalogue. Le compteur de découvertes reste valable. Aucune pondération selon le caractère intime d’un univers.
Les marques learning_match et declic_match ne sont pas des prérequis : elles peuvent exister indépendamment d’une révélation dans le store actuel. Un souhait accepté, une invitation, une ouverture de page ou un accord à une proposition ne donne aucun point. Une expérience hors application pourra être ajoutée plus tard avec un contrat déclaratif explicite.
Catalogue initial : douze accomplissements
Les seuils sont des choix produit initiaux à évaluer en bêta. Les clés sont stables ; noms et illustrations pourront être révisés sans redonner les gains.
| Clé | Famille | Nom | Condition cumulée | Récompense |
|---|---|---|---|---|
| experience_01 | Expérience commune | Le premier chapitre | 1 découverte partagée | Page d’ouverture |
| experience_05 | Expérience commune | Nos premières pages | 5 découvertes | Vignette duo |
| experience_15 | Expérience commune | Une histoire qui grandit | 15 découvertes | Cadre de chapitre |
| experience_30 | Expérience commune | Trente moments à nous | 30 découvertes | Couverture alternative |
| exploration_01 | Exploration | Une porte s’ouvre | 1 univers | Emblème d’exploration |
| exploration_02 | Exploration | Un autre regard | 2 univers | Vignette de voyage |
| exploration_03 | Exploration | Explorateurs | 3 univers | Cadre d’exploration |
| exploration_04 | Exploration | À la croisée des chemins | 4 univers librement choisis | Couverture exploration |
| regularity_days_03 | Régularité | On se retrouve | 3 jours actifs | Marque-page |
| regularity_days_07 | Régularité | Sept rendez-vous | 7 jours actifs | Marque-page illustré |
| regularity_weeks_04 | Régularité | Notre rythme | 4 semaines actives | Cadre de saison |
| regularity_weeks_12 | Régularité | Au fil du temps | 12 semaines actives | Couverture au fil du temps |
Descriptions affichées : « Vous avez partagé N découvertes », « Vous avez découvert N univers ensemble », « Vous avez joué ensemble sur N jours / semaines ». Les jours et semaines ne sont jamais obligatoirement consécutifs.
Modèle durable et intégrité
Catalogue versionné : clé, famille, métrique, seuil, nom, description, reward_key, ordre. Gain : couple_id, achievement_key, catalog_version, unlocked_at, reward_key ; unicité couple+clé. Projection : événements minimaux, jours actifs distincts, semaines actives distinctes, univers distincts et agrégats. Les récompenses sont acquises sans consommation et leur équipement est facultatif, sans effet sur les compteurs.
La transaction du gain doit sérialiser la projection par couple, y compris si deux activités différentes franchissent simultanément un seuil. INSERT ON CONFLICT seul sur les événements ne suffit pas pour éviter un jalon manqué. Un rollback métier ne laisse aucun événement, compteur ni notification. Une reprise après erreur rejoue sans duplication. Les comptes de deux couples ne se croisent jamais, même avec le même activity_id et day_key.
Pas de backfill automatique au lancement : seuls les événements après activation produisent des gains. L’interface indique « Votre livre commence ici ». L’historique actuel ne permet pas de promettre une reconstruction complète des anciennes révélations, des appartenances et des dates. Aucun badge ancien n’est inventé.
Un changement de seuil ne retire pas les gains existants et ne réutilise pas une clé pour une autre signification. Les acquis ne diminuent pas avec l’inactivité. Les suppressions de données restent prioritaires : les gains et agrégats suivent le cycle de vie du couple, sans transfert vers un nouveau couple. Le départ d’un membre n’autorise plus de nouveaux gains en duo ; les droits du membre restant suivent le contrat d’effacement existant. Après effacement du dernier membre, événements, agrégats, gains, préférences visuelles et notifications associées sont purgés. Le lot moteur doit prouver la compatibilité restauration/anti-résurrection.
Ne conserver dans la projection aucun texte de réponse, prénom, e-mail, opinion ou contenu intime. Les identifiants et agrégats restent des données tenantisées. Les clés de déduplication sont conservées tant que leur source reste rejouable ; leur purge doit être coordonnée avec celle de la source, jamais indépendante. La matrice de conservation du lot data-lifecycle doit définir et valider ce cycle avant activation, sans durée arbitraire inventée ici.
Livre, prochain jalon et célébration
Dans Nous : couverture, pages de jalons par date, collection des trois familles et un prochain jalon. Les pages ne recopient pas les réponses. Les illustrations sont des assets éditoriaux partagés. Ajouter un souvenir personnel reste hors première livraison et exige un contrat séparé.
Le prochain jalon est le gain non acquis au ratio compteur/seuil le plus élevé, avec départage stable par ordre du catalogue. Un accomplissement terminé est retiré des candidats. Tous acquis : présenter le livre et proposer une activité libre, sans nouvelle exigence artificielle.
Lors d’un premier déblocage, afficher une célébration groupée courte et non bloquante, même si plusieurs badges arrivent ensemble. Lecture accessible, reduced-motion, pas de déplacement de focus automatique, pas de saut de scroll. L’état de présentation est propre à chaque utilisateur, les gains sont communs : A ne consomme pas la célébration de B. Un retry ne renvoie pas une succession de popups. Aucun e-mail d’accomplissement pour cette version ; la consultation dans l’application suffit.
Quête hebdomadaire facultative
Lot distinct. Le couple choisit une quête commune parmi des propositions éditoriales simples : deux découvertes dans la semaine, ou un univers encore non exploré. La semaine court du lundi 00:00 UTC au lundi suivant. Le choix crée une instance partagée unique ; deux choix concurrents doivent retourner le choix enregistré et permettre une modification explicite avant le premier progrès.
Seules les découvertes postérieures au choix comptent. Les deux participants n’ont pas à être présents simultanément. Une quête terminée attribue une vignette, une seule fois. À la fin de la semaine, une quête inachevée se ferme silencieusement sans dette, badge retiré ni message d’échec. Les récompenses éditoriales reviennent dans les rotations suivantes, sans rareté perdue à jamais. La progression permanente acquise pendant la quête reste conservée.
Découpage et critères de sortie
| Lot | Livrable | Dépendances / sortie |
|---|---|---|
| achievements-model | Présent contrat et catalogue | Revue produit et vérification des sources métier ; aucune migration/runtime |
| achievements-engine | Projection transactionnelle PostgreSQL et lecture tenantisée | Modèle ; matrice data-lifecycle ; tests concurrence, reprise et effacement sur PostgreSQL réel |
| achievements-ui | Livre, collections, prochain jalon et célébrations | Moteur ; responsive, clavier, reduced-motion et stabilité polling |
| achievements-rewards | Assets et personnalisation du livre | Modèle puis moteur/UI ; choix partagé, droits de gain vérifiés serveur, alternatives accessibles |
| achievements-quests | Quête hebdomadaire commune | Moteur + récompenses ; concurrence de choix, frontière temporelle, expiration douce, retries |
| achievements-validation | Recette intégrée 1.2 | Tous les lots requis ; tests multi-couple, A/B, accessibilité, cycle de vie et mesure bêta sobre |
Conserver les quatre clés existantes. Ajouter uniquement les deux Lots récompenses et quêtes, qui ont chacun leur comportement et leur recette. Aucune micro-story pour chaque badge. Plane pilote directement ces lots via son API. Les clés et références NC existantes sont conservées ; aucune écriture dans la branche historique plane.
Scénarios d’acceptation à implémenter dans les lots suivants
- Première réponse : aucun gain ; seconde réponse : une découverte et premiers gains, une célébration groupée.
- Même requête rejouée, refresh et deux onglets : compteurs identiques, aucune nouvelle récompense.
- Deux activités terminées simultanément au seuil : les deux découvertes comptent et le badge est gagné une fois.
- Réponse de B une autre semaine : gain daté de B côté serveur ; aucune semaine rétroactivement inventée.
- Trois mois d’absence : livre et badges intacts ; proposition de reprise sans reproche.
- Quatre univers non intimes explorés : collection exploration complète sans obligation d’un univers particulier.
- Suppression puis restauration : aucune donnée effacée ne revient via la projection.
- Deux couples avec mêmes activités : aucune lecture, notification ou récompense croisée.
- Animation réduite et lecteur d’écran : le gain reste lisible ; A et B peuvent chacun le découvrir.
- Dernière seconde d’une quête / retry après échéance : horodatage transactionnel décide, récompense unique.
Mesure bêta proposée : activation duo, retour J+7, semaines avec une découverte partagée, taux de réalisation volontaire des quêtes et retour qualitatif sur le plaisir/pression. Aucune collecte des réponses et aucun objectif de temps d’écran. Instrumentation à cadrer avec le lot bêta, sans tracker tiers ajouté par cette spécification.
Preuves et limites
Le contrat initial est livré par PR #431 ; moteur et livre sont intégrés via #646/#652, avec chargement corrigé par #951 et promotion 1.1.1 par #953. Les assets personnalisables, préférences et quêtes restent dans NC-18/19. NC-17 porte la recette intégrée 1.2 et la qualification des environnements effectivement exécutés. Les dix scénarios ci-dessus restent les critères de comportement ; leur présence dans une spécification ne constitue pas une preuve de recette.