From 125813c34e36d391110d4db4a4e56415bcbc1533 Mon Sep 17 00:00:00 2001 From: Thomas Fransolet Date: Wed, 16 Sep 2026 15:29:16 +0200 Subject: [PATCH] =?UTF-8?q?Cr=C3=A9dits=20Studio=20:=20un=20pr=C3=A9avis,?= =?UTF-8?q?=20pas=20un=20nouveau=20plafond=20(d=C3=A9cision=2027)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La limite demandée existe déjà deux fois — le solde prépayé est le plafond, et StudioPerUserDailyCap borne la journée d'un utilisateur. Ce qui manque est l'alerte : aujourd'hui le premier signal reçu est une génération qui échoue en InsufficientCredits, et l'expiration à 12 mois fait s'évaporer un solde sans prévenir. Seuil configurable par instance, mail au franchissement et rappel d'expiration à J-30. Carte kanban 282. Co-Authored-By: Claude Opus 5 (1M context) --- ...seuil-d-alerte-sur-le-solde-de-credits-studio.md | 13 +++++++++++++ v2/studio-plan.md | 1 + 2 files changed, 14 insertions(+) create mode 100644 kanban/cards/5-planifie/282-seuil-d-alerte-sur-le-solde-de-credits-studio.md diff --git a/kanban/cards/5-planifie/282-seuil-d-alerte-sur-le-solde-de-credits-studio.md b/kanban/cards/5-planifie/282-seuil-d-alerte-sur-le-solde-de-credits-studio.md new file mode 100644 index 0000000..e5d0497 --- /dev/null +++ b/kanban/cards/5-planifie/282-seuil-d-alerte-sur-le-solde-de-credits-studio.md @@ -0,0 +1,13 @@ +--- +title: Seuil d'alerte sur le solde de crédits Studio (pas un nouveau plafond) +area: backend manager +horizon: v2 +tags: studio, crédits +flag: warn | Nouveau 16/09 · le plafond dur a été retiré exprès (décision 22) +src: studio-plan.md décisions 17 et 22 · StudioCreditService.cs · studio_credits_section.dart +--- +

La limite demandée existe déjà, deux fois. Avec des crédits prépayés (décision 17), le solde est le plafond — c'est exactement pour ça que la décision 22 a retiré le plafond dur organisation le 13/09. Et le garde-fou contre le stagiaire qui vide le budget en une après-midi, c'est Instance.StudioPerUserDailyCap, déjà appliqué dans StudioCreditService.ReserveAsync (CreditError.DailyCapReached). Rien à ajouter de ce côté : ne pas recréer un plafond organisation.

+

⚠️ Le modèle n'est pas celui de Google AI Studio ni de fal.ai. Là-bas on est en postpayé : sans budget alert ni hard cap, on découvre la facture. Ici le client a payé avant ; il ne peut pas se faire surprendre par une dépense, seulement par une indisponibilité — et ça, ça ne se règle pas avec un plafond, mais avec un préavis.

+

Ce qui manque vraiment : le préavis. Aujourd'hui aucune alerte n'existe. studio_credits_section.dart affiche disponible / solde / réservé / expiration, mais il faut aller ouvrir l'écran Facturation pour les voir ; une génération qui échoue en InsufficientCredits est le premier signal reçu par le conservateur. Et surtout, l'expiration à 12 mois (décision 17) est le vrai piège : un solde qui s'évapore sans prévenir, sur une institution publique, c'est un litige — pas une notification manquée.

+

À faire : Instance.StudioCreditsAlertThreshold (en crédits, 0 = désactivé) + StudioCreditsAlertSentAt pour ne pas renvoyer le mail à chaque génération ; déclenchement dans StudioCreditService.Record quand le solde passe sous le seuil, et dans ExpireDueAsync (déjà un job quotidien) pour un rappel d'expiration à J-30. Envoi par IEmailService / ResendEmailService, déjà en place. Côté manager-app : un champ dans l'écran Facturation et un bandeau dans le popover de la jauge du pied de menu, i18n FR/EN/NL.

+

Petit lot : 2 colonnes, un hook, un template de mail, un champ d'UI. À faire après la fixation des prix (décision 16, fin du lot 3) — un seuil en crédits n'a pas de valeur par défaut tant que l'unité de crédit n'est pas arrêtée.

diff --git a/v2/studio-plan.md b/v2/studio-plan.md index f792a12..22ba5a3 100644 --- a/v2/studio-plan.md +++ b/v2/studio-plan.md @@ -162,6 +162,7 @@ Tout sur `Instance`, dupliqué depuis `SubscriptionPlan` : `StorageQuotaBytes`, | 23 | Écarts des lots 2 à 4 — *13/09* | **Fournisseur interchangeable** : `IGenerationProvider` (soumission, sondage, lecture du webhook) + `GenerationModel.ProviderKey` en base ; changer de fournisseur = une classe et une ligne de catalogue. **Une requête par variante** (FLUX.2 pro n'a pas de `num_images`). **Référence source avant celles de l'identité** dans l'ordre d'envoi. Migration unique `AddStudioGeneration` pour les lots 2 et 3. **Non livrés** : `preview`, `GET /jobs`, `cancel`, `reject`, `regenerate`, l'interrupteur UI de `CanValidateAssets`. **Pas de `target` serveur** : l'onglet « Générer » vit dans le sélecteur (`showSelectResourceModal`, mode sélection) et la ressource validée revient au champ qui l'a ouvert — donc absent du bouton « Ajouter » de la Médiathèque, qui relève du lot 5. Surcharges d'identité en puces, pas en onglets ; `ModelKey` non exposé (un seul modèle). **`GuidedStep.ImageUrl` conservée** et remplie par le client avec `ImageResourceId` (motif `GeoPoint`) : visitapp-web n'a rien à changer, mymuseum-visitapp lit l'id pour l'hors-ligne, tablet-app n'a pas d'étapes. `CreditCost = 10` provisoire jusqu'au calibrage || 24 | Modèles 3D et multi-vues — *15/09* | **Tout reste sur fal** : Meshy (v5, v6-preview, v7), Hi3D, Tripo3D, Hunyuan3D et Trellis y sont exposés — aucun second fournisseur à intégrer, aucune seconde clé. **Deux lignes de catalogue, pas une** : `3d-default` mono-image (~0,02–0,05 $) et `3d-multiview` = `meshy/v7/multi-image-to-3d` (~1,20 $). Le facteur ~25 sur le coût impose que le basculement de l'un à l'autre soit **annoncé avant la génération, jamais silencieux**. Hi3D n'expose pas de multiview : excellent en fidélité structurelle, il ne couvre pas le cas d'usage central. Ids et prix à revérifier au calibrage (§9.4) | | 25 | Casting visiteur — *15/09* | **Retenu** — lève le « hors périmètre » de §3.8. `ConfigurationPersona { ConfigurationId, PersonaId, Order, IsFeatured }` ne porte **que** l'ordre et la mise en avant : l'appartenance reste **calculée** depuis les narrateurs assignés. Un personnage ne s'assigne qu'à **un seul endroit — le contenu** ; l'écran casting est une *vue*, jamais une seconde saisie. Rien ne s'affiche côté visiteur sans `Configuration.IsCastingShownToVisitor` (défaut off). Lot 8bis | | 26 | Prise de vue mobile — *16/09* | **Page de dépôt dédiée ouverte par QR code, pas un manager-app responsive.** Le conservateur est devant la vitrine avec son téléphone, pas devant son poste ; rendre responsive un back-office Flutter web pour un seul écran revient à le rendre responsive tout court — refus déjà posé sur le routing (décision 23) — et CanvasKit se charge mal sur la 4G d'une salle. La page vit sur **la même surface web non-Flutter que l'éditeur de POI** (décision n°9 d'[immersif-frontiere-plan.md](immersif-frontiere-plan.md)) : aucune nouvelle cible de déploiement. Capture par ``, qui ouvre l'appareil photo natif — **jamais `getUserMedia`**, dont le flux est sans autofocus ni traitement constructeur, alors que c'est le seul gabarit du Studio où la qualité des photos pèse plus lourd que le prompt. Accès par **token de dépôt** borné (§3.7bis), jamais un JWT manager. **Lot 11bis, après le lot 11** : le dépôt de fichiers depuis le poste couvre déjà le besoin fonctionnel | +| 27 | Alerte de solde, pas de nouveau plafond — *16/09* | **Le plafond reste retiré** (décision 22) : avec des crédits prépayés, le solde *est* le plafond, et `StudioPerUserDailyCap` couvre déjà le budget vidé en une après-midi. Ce qui manque est le **préavis** — le modèle n'est pas celui de Google AI Studio ni de fal.ai, **postpayés**, où l'alerte protège d'une facture ; ici elle protège d'une **indisponibilité**. On ajoute `Instance.StudioCreditsAlertThreshold` (0 = désactivé) + `StudioCreditsAlertSentAt` (anti-répétition), déclenchés dans `StudioCreditService.Record` au franchissement du seuil et dans `ExpireDueAsync` pour un rappel **d'expiration à J-30** — c'est le vrai risque de la décision 17, un solde qui s'évapore en silence chez une institution publique. Envoi par `IEmailService` (Resend, déjà en place), champ dans l'écran Facturation et bandeau dans le popover de la jauge. **Après la décision 16** : un seuil en crédits n'a pas de valeur par défaut tant que l'unité n'est pas fixée | ---