Skip to content

Plan backend collection, pricing et alertes ​

Date : 2026-05-18. Statut : plan d'architecture produit/backend avant implémentation des providers pricing.

SKN doit devenir plus qu'un scanner. Le scanner identifie l'objet ; les moteurs collection, pricing et alertes transforment cet objet en portfolio privé qui aide l'utilisateur à décider quand acheter, conserver, vendre ou mettre en vente.

Ce plan sépare volontairement la fondation backend de la formule pricing provider-specific. Le modèle exact de pondération doit attendre la documentation pricing dédiée. L'architecture ci-dessous définit où ce modèle tournera et quelles données il devra consommer.

Thèse produit ​

La boucle utilisateur coeur :

text
scanner ou rechercher un item
-> confirmer identité, condition, langue, grade, quantité
-> ajouter à la collection privée
-> attacher prix d'acquisition et preuves/photos
-> calculer valorisation et confiance
-> suivre les mouvements dans le temps
-> notifier l'utilisateur sur un pump/drop/opportunité significatif

L'app doit se rapprocher d'un terminal portfolio plutôt que d'un classeur statique. Mais elle ne doit pas prétendre être un marché financier si la donnée sous-jacente est faible. Chaque valorisation et alerte doit afficher fraîcheur, confiance et explication des sources.

Limite de scope ​

Dans le scope ​

  • collections utilisateur privées ;
  • cartes raw, slabs et produits scellés comme classes d'objets séparées ;
  • prix d'acquisition et gain/perte portfolio ;
  • observations marché depuis des providers normalisés ;
  • estimations pondérées avec confiance ;
  • snapshots de valorisation par holding et portfolio ;
  • règles d'alertes et événements d'alerte pour drops, pumps et items surveillés ;
  • adapters provider derrière des contrats normalisés ;
  • audit trail pour les changements sensibles de collection.

Hors scope pour maintenant ​

  • checkout marketplace, paiement, payout, escrow, litiges ;
  • partage public de collection par défaut ;
  • exécution automatique achat/vente ;
  • scraping non revu comme dépendance production ;
  • redistribution publique d'images ou données marché que les providers n'autorisent pas ;
  • promesse d'alertes temps réel si les quotas provider imposent du polling.

Domaines backend ​

1. Domaine utilisateur et collection ​

Le Collection Engine répond : "Que possède cet utilisateur ?"

Tables coeur :

TableRôle
usersIdentité compte. Peut démarrer simple, mais les holdings doivent être user-scoped dès le premier jour.
collection_itemsUne ligne de possession : référence item, type, quantité, condition, langue, grade, état scellé.
collection_item_photosPhotos preuve utilisateur, photos affichables, captures scan.
collection_item_acquisitionsPrix d'achat, date d'achat, vendeur/source, shipping, frais, notes.
collection_item_eventsAudit trail : création, édition, quantité changée, vendu, supprimé, restauré.
collection_item_valuation_snapshotsValeur courante et historique d'un holding.
collection_exportsJobs d'export explicites pour les données utilisateur.

Exigences privacy :

  • collection privée par défaut ;
  • chaque requête est scopée par user ID ;
  • les labels de localisation/stockage ne sont jamais publics par défaut ;
  • le prix d'acquisition est privé et ne doit pas fuiter dans une future annonce marketplace ;
  • l'EXIF doit être supprimé des photos uploadées ;
  • les suppressions doivent d'abord être soft-delete, avec restore/audit.

Pour une app professionnelle, le backend distant doit être canonique. Le mobile pourra cacher localement plus tard, mais le backend doit posséder identité, audit, valorisation, alertes et état des refresh providers.

2. Domaine identité item ​

Les moteurs Pricing et Collection ne doivent pas stocker directement les formes provider brutes. Ils référencent des identités SKN normalisées.

Identités coeur :

Classe itemChamps d'identité
raw_cardTCG, set, numéro collector, langue, variante, finish, condition.
graded_card / slabidentité carte intérieure, grader, grade, numéro certificat, metadata label.
sealed_producttype produit, set/série, langue, région, SKU/code barre quand disponible.

L'Identity Engine reste responsable de résoudre un scan vers une de ces classes. Le Collection Engine stocke l'instance possédée par l'utilisateur.

3. Domaine observations pricing ​

Le Pricing Engine répond : "Quelles preuves marché existent ?"

Tables coeur :

TableRôle
price_sourcesRegistre provider : Cardmarket, eBay, TCGPlayer, PriceCharting, APIs provider, imports manuels.
price_provider_itemsMapping entre identité SKN et SKU/listing/category provider.
price_observationsObservation marché normalisée : sold comp, listing actif, ask, comp graded, comp scellé.
price_observation_feesShipping, frais acheteur, frais vendeur, taxes quand connus.
price_observation_flagsOutlier, low-confidence, mauvaise langue, damaged, incomplet, suspect.
price_import_runsSuivi des jobs d'ingest, fraîcheur provider, erreurs, quotas.

Chaque observation doit garder :

  • source et URL source ou ID externe ;
  • vendu vs listing actif ;
  • prix et devise ;
  • traitement shipping/frais ;
  • date vente/listing ;
  • région ;
  • langue ;
  • condition ;
  • classe item ;
  • grader et grade si pertinent ;
  • pointeur payload brut ou checksum pour audit ;
  • statut terms/licensing pour cache/affichage.

Les adapters provider spécifiques peuvent arriver plus tard, mais le schéma d'observation doit exister avant d'ajouter beaucoup de providers.

4. Domaine estimation pricing ​

Le Pricing Engine répond : "Quelle est la valeur estimée actuelle ?"

Tables coeur :

TableRôle
price_estimatesEstimation courante pour une identité SKN et un contexte marché.
price_estimate_componentsBreakdown par source/signal : Cardmarket, eBay sold, listings actifs, source graded, override manuel.
price_estimate_historySérie temporelle des estimations pour charts et alertes.
price_estimate_explanationsPayload explicatif lisible par l'app.

La sortie d'estimation doit inclure :

  • estimation low / mid / high ;
  • devise ;
  • score de confiance ;
  • score de liquidité ;
  • taille d'échantillon ;
  • fraîcheur ;
  • sources les plus fortes ;
  • warnings : donnée stale, peu de comps, mismatch langue, mismatch grade, beaucoup d'outliers.

Ne pas démarrer par une "moyenne magique". La première version peut être simple, mais elle doit être explicable :

  • les comps vendus pèsent plus que les listings actifs ;
  • les observations récentes pèsent plus que les anciennes ;
  • les signaux EU/FR pèsent plus pour les utilisateurs FR/EU que les données US-only ;
  • les matchs exacts langue/condition/grade pèsent plus que les mismatches ;
  • les listings actifs peuvent informer la pression ask mais ne doivent pas dominer la valeur vendue ;
  • un faible échantillon réduit la confiance même si les prix semblent hauts.

5. Domaine valorisation ​

Le Valuation Engine applique les estimations de prix aux vrais holdings utilisateur.

Il répond :

  • valeur totale portfolio ;
  • valeur par classe item : raw, slab, scellé ;
  • gain/perte non réalisé vs prix d'acquisition ;
  • top movers ;
  • nombre de valorisations stale ;
  • nombre de valorisations low-confidence.

Tables coeur :

TableRôle
portfolio_snapshotsValeur portfolio agrégée par utilisateur dans le temps.
collection_item_valuation_snapshotsValeur estimée par holding dans le temps.
portfolio_breakdownsSplit par classe item, TCG, set, condition, grade, langue.

Cette couche ne doit pas recalculer les providers en live à chaque écran mobile. Elle doit lire des estimations et snapshots pré-calculés, puis afficher la fraîcheur.

6. Domaine alertes ​

L'Alert Engine répond : "Qu'est-ce qui a assez changé pour compter ?"

Types d'alertes :

AlerteDéclencheur
Price dropItem surveillé ou wishlist passe sous un seuil.
Price pumpItem possédé dépasse un seuil de mouvement.
Portfolio moverUn holding devient top mover jour/semaine.
Spread opportunityLes comps vendus et listings actifs créent une possible opportunité achat/vente.
Donnée staleHolding important sans donnée marché fraîche.
Pricing manquantItem possédé sans estimation.

Tables coeur :

TableRôle
alert_rulesRègles définies par l'utilisateur ou suggérées par le système.
alert_rule_targetsItem, holding, recherche, set, classe produit ou segment portfolio.
alert_eventsAlertes déclenchées avec payload et IDs d'estimation source.
alert_deliveriesÉtat de delivery push/email/in-app et retry.
alert_deduplication_keysCooldowns pour éviter le spam sur feeds bruités.

Quasi temps réel doit vouloir dire "assez frais pour un comportement marketplace", pas faux tick-by-tick trading. Les permissions et quotas provider décident si on fait du polling, webhook, batch refresh ou hybride. Le backend doit afficher la fraîcheur honnêtement.

Cadence de rafraîchissement des prix ​

La fraîcheur pricing doit être organisée par tiers. Pokémon contient trop de cartes, variantes, slabs et produits scellés pour tout rafraîchir en continu.

Contraintes source actuelles :

  • Cardmarket documente son price guide public comme mis à jour une fois par jour, tandis que le catalogue produit est mis à jour quand de nouvelles releases sont ajoutées. Cardmarket est donc une baseline quotidienne solide, pas une source tick-by-tick. Source : annonce Cardmarket du 2024-06-05.
  • Les APIs eBay Browse permettent de rechercher des listings actifs et des cas de découverte/refinement, mais l'accès à l'historique des ventes est contraint. eBay documente beaucoup de Buy APIs comme limited release et précise que Marketplace Insights est restreint et pas ouvert aux nouveaux utilisateurs pour le moment. La Feed API eBay peut fournir des snapshots horaires d'items modifiés, mais elle est aussi limited release. Sources : overview eBay Buy APIs, support Buy API par marketplace, ressources Feed API.

Tiers de refresh recommandés :

TierCadenceScopeObjectif
Baseline marché complèteQuotidienPrice guide Cardmarket, feeds provider quotidiens, catalogue largeRecalculer les estimations stables et le long tail.
Portfolio utilisateurToutes les 1 à 6 hItems possédés, holdings chers, items récemment scannésDonner une sensation portfolio vivant sans rafraîchir tout le marché.
Watchlist / alertes activesToutes les 30 à 60 min si le budget provider le permetItems surveillés, wishlist, items avec règles d'alerte activesCapturer les mouvements utiles à l'utilisateur plus vite que la baseline quotidienne.
Hot queueToutes les 5 à 30 min quand c'est légalement et techniquement autoriséItems qui viennent de bouger fort ou très surveillésPermettre un comportement quasi temps réel pump/drop sans prétendre que tout le marché est live.
Long tailQuotidien ou plus lentItems sans propriétaire, sans watch, faible liquiditéÉviter de brûler les quotas provider.

L'app doit afficher la fraîcheur à côté des estimations et alertes. Une alerte utile avec "mis à jour il y a 22 min" est crédible ; une alerte stale sans fraîcheur crée une fausse confiance.

Modèle d'évaluation des alertes ​

Les alertes doivent partir depuis les changements d'estimation, pas depuis une observation provider brute isolée.

Flow d'évaluation :

text
nouvelles observations ingérées
-> estimation recalculée
-> historique estimation mis à jour
-> alert evaluator compare aux baselines
-> gates confiance et liquidité appliqués
-> déduplication/cooldown vérifiés
-> alerte in-app/push créée

Baselines de comparaison :

  • dernière estimation fiable ;
  • moyenne 7 jours ;
  • moyenne 30 jours ;
  • prix d'acquisition utilisateur quand l'item est possédé ;
  • seuil utilisateur pour watchlist ou wishlist.

Seuils d'alerte par défaut :

AlerteDéfaut recommandé
Price drop-10% à -15% vs moyenne 7 jours, ou sous un seuil utilisateur.
Price pump+15% à +25% vs moyenne 7 jours, avec assez de liquidité.
Portfolio moverLe holding entre dans les top movers jour/semaine de l'utilisateur.
Spread opportunityListing actif nettement sous la valeur vendue/estimée récente.

Gates qualité avant notification :

  • nombre minimum d'observations ou source fiable forte ;
  • fraîcheur source dans le SLA du tier d'alerte ;
  • confiance estimation au-dessus du minimum de la règle ;
  • mouvement au-dessus du bruit en pourcentage et en valeur absolue ;
  • condition/langue/grade suffisamment cohérents ;
  • les outliers suspects ne dominent pas l'estimation ;
  • pas d'alerte dupliquée dans la fenêtre de cooldown.

Exemple de payload alerte :

json
{
  "type": "price_pump",
  "title": "Dracaufeu 4/102 FR monte de 18%",
  "itemId": "raw_card:pokemon:base1:4:fr",
  "estimate": { "mid": 182.0, "currency": "EUR", "confidence": 0.76 },
  "movement": { "window": "7d", "percent": 18.0, "absolute": 27.8 },
  "primarySignals": ["ebay_sold", "cardmarket_daily"],
  "freshness": "2h",
  "action": "review_sell_or_list"
}

Le wording produit doit aider la décision sans faire du conseil financier. Préférer "revoir opportunité de vente/listing" à "vends maintenant".

Stratégie providers et MCP ​

Les intégrations provider doivent être des adapters runtime backend, pas des dépendances mobile.

Familles de providers candidates :

  • Cardmarket pour le contexte marché EU ;
  • eBay sold comps et listings actifs ;
  • TCGPlayer ou APIs provider pour le contexte US ;
  • PriceCharting ou providers graded pour slabs ;
  • plus tard Vinted / Leboncoin comme signaux peer-to-peer français si les terms l'autorisent.

Les connecteurs MCP sont utiles pour l'outillage interne, les opérations, les backfills et l'exploration provider. Pour le runtime produit, SKN doit quand même stocker des observations normalisées dans sa base backend et servir l'app via les APIs SKN. L'app mobile ne doit jamais dépendre directement des formes provider ou MCP.

Avant usage production, chaque provider demande une revue des terms :

  • permission de cache ;
  • permission d'affichage ;
  • quota de refresh ;
  • usage commercial ;
  • attribution ;
  • rate limits ;
  • contraintes de redistribution ;
  • possibilité de stocker et afficher des estimations dérivées.

Surface API ​

Endpoints backend initiaux :

EndpointRôle
POST /collection/itemsAjouter un holding depuis scan ou recherche manuelle.
GET /collection/itemsLister les holdings utilisateur avec filtres.
PATCH /collection/items/:idModifier condition, quantité, notes, stockage, acquisition.
DELETE /collection/items/:idSoft-delete d'un holding.
GET /collection/portfolioTotaux portfolio et breakdowns.
GET /pricing/items/:identityId/estimateEstimation normalisée courante et explication.
GET /pricing/items/:identityId/observationsPreuves debug/provider quand l'utilisateur a le droit de les voir.
POST /alerts/rulesCréer une règle d'alerte.
GET /alerts/eventsFeed d'alertes in-app.
PATCH /alerts/events/:idMarquer lu, ignoré, actionné.

Intégration scan :

text
résultat scan
-> écran de confirmation
-> ajout à collection
-> collection item créé
-> snapshot de valorisation attaché si estimation disponible
-> règles d'alerte optionnelles suggérées

Roadmap d'implémentation ​

Phase 0 — verrouillage architecture ​

Livrables :

  • ADR schéma pour holdings utilisateur, observations pricing, estimations et alertes ;
  • checklist terms providers ;
  • contrat identité item partagé par collection/pricing/scan ;
  • décision sur le modèle auth pour holdings privés.

Phase 1 — fondation collection privée ​

Livrables :

  • tables collection scopées utilisateur ;
  • add/edit/delete/list holdings ;
  • prix et date d'acquisition ;
  • support classes raw_card, sealed_product et futur graded_card ;
  • audit trail ;
  • tests locaux sur isolation utilisateur et soft-delete.

Phase 2 — ajout depuis scan ​

Livrables :

  • endpoint backend pour créer un holding depuis résultat de scan ;
  • flow mobile de confirmation ;
  • fallback manuel quand le résultat scan est faux ou ambigu ;
  • capture condition, langue, quantité, prix d'acquisition, notes.

Phase 3 — schéma pricing avec provider mock ​

Livrables :

  • price_sources, price_observations, price_estimates ;
  • ingestion provider synthétique/mock pour les tests ;
  • premier estimateur explicable avec règles déterministes ;
  • pas encore de dépendance provider live.

Cette phase prouve le modèle de données avant la complexité Cardmarket/eBay.

Phase 4 — valorisation portfolio ​

Livrables :

  • snapshots de valorisation par holding ;
  • totaux portfolio ;
  • gain/perte vs acquisition ;
  • breakdown raw/slab/scellé ;
  • labels stale/low-confidence.

Phase 5 — alertes avec événements marché simulés ​

Livrables :

  • règles d'alerte ;
  • détection pump/drop sur historique d'estimations ;
  • déduplication et cooldown ;
  • feed d'alertes in-app ;
  • tests avec mouvements de prix synthétiques.

Cela valide la boucle produit avant les quotas provider réels.

Phase 6 — premier adapter provider réel ​

Livrables :

  • un adapter provider derrière PriceObservationSource ;
  • observabilité import-run ;
  • comportement cache/display compatible terms ;
  • table mapping provider ;
  • flags de confiance source-specific.

Choisir le premier provider seulement après la documentation pricing dédiée et la revue des terms. Cardmarket/eBay sont de bons candidats, mais le premier adapter production doit être la source avec le meilleur fit légal, quota et qualité data.

Phase 7 — alertes quasi temps réel ​

Livrables :

  • tiers de refresh planifiés selon importance item ;
  • refresh prioritaire watchlist ;
  • génération événements après update d'estimation ;
  • intégration push notification ;
  • explications d'alertes montrant source, mouvement, confiance et fraîcheur.

Première slice de dev recommandée ​

Commencer par la Phase 1 : fondation collection privée.

Pourquoi :

  • elle est requise pour chaque feature future de valorisation et d'alerte ;
  • elle est testable sans risque provider ;
  • elle crée une surface produit immédiate après le scan ;
  • elle garde les actifs utilisateur privés dès le début ;
  • elle évite de construire le pricing avant d'avoir un endroit où attacher les valorisations.

La première PR backend ne doit pas encore intégrer Cardmarket ou eBay. Elle doit créer les holdings user-scoped et assez de forme API pour "scan -> confirmation -> ajout à collection".

Décisions ouvertes ​

  1. Quel modèle auth est acceptable pour le premier backend de collection privée ?
  2. Les photos collection doivent-elles être stockées d'abord sur le filesystem VPS, en object storage plus tard, ou directement en object storage ?
  3. Le premier provider pricing doit-il cibler la pertinence EU/Cardmarket ou des sold comps eBay plus larges ?
  4. Quelle latence minimum rend une alerte utile : minutes, heure, jour ?
  5. Quel wording évite de promettre du conseil financier tout en aidant fortement les décisions achat/vente ?
  6. Quelle classe item doit recevoir le pricing en premier : cartes raw, scellés ou slabs ?