Code de licence : guide complet du développement, débogage et mise en ligne

v1.0.0

Logiciel client : développement → débogage → mise en ligne — guide complet du processus (v4)

Concerne : les développeurs qui publient un logiciel client sur PowerSoftware.net et intègrent le système de codes de licence. Ce document couvre l’ensemble du cycle de vie, de la « création du produit » à l’« achat par de vrais utilisateurs », en mettant l’accent sur la nouvelle capacité de débogage à double environnement de la v4 : avant la mise en ligne, utiliser son propre ordinateur comme machine de débogage pour parcourir tout le processus avec la véritable chaîne de paiement (environnement Waffo Test).

1. Vue d’ensemble du processus

┌──────────────┐   ┌──────────────┐   ┌──────────────┐   ┌──────────────┐
│ ① Développement│ → │ ② Débogage   │ → │ ③ Mise en    │ → │ ④ Exploitation│
│              │   │              │   │ ligne        │   │ après sortie │
│ Créer le     │   │ Enregistrer  │   │ Soumettre    │   │ Consulter    │
│ produit      │   │ machine de   │   │ la revue     │   │ commandes    │
│ Intégrer SDK │   │ débogage     │   │ approuvée    │   │ délier/remb. │
│ Enregistrer  │   │ chaîne réelle│   │ synchroniser │   │ Itération    │
│ brouillon    │   │ (env. Test)  │   │ production   │   │ versions     │
└──────────────┘   └──────────────┘   └──────────────┘   └──────────────┘
Phase Statut du produit Où vont licences/commandes Revenus réels ?
① Développement Brouillon (DRAFT) Non
② Débogage Brouillon / en revue Tables Test (codes de licence préfixés T-) Non (canal de paiement test)
③ Mise en ligne Publié Tables de production Oui

Règle clé : débogage et production sont totalement isolés. Tout ce qui se passe sur les machines de débogage (essais, commandes, paiements, émission de codes, activation, remboursements) n’affecte que les tables test — cela n’entre ni dans le partage de revenus ni dans la réconciliation, et n’affecte aucun utilisateur réel ; les accès depuis des machines non-débogage passent toujours par la chaîne de production.

2. Phase de développement

2.1 Créer le produit

  1. Se connecter au Developer Center de PowerSoftware.net → publier un produit, choisir « Logiciel client » comme type de produit
  2. Choisir le modèle de vente Essayer avant d’acheter et renseigner les jours d’essai (recommandé 7~14 jours)
  3. Configurer les éditions de licence : trois niveaux par défaut BASIC / PRO / ULTIMATE ; le code, le nom, le prix et la liste des fonctionnalités sont personnalisables
  4. Cocher « La plateforme encaisse les frais de licence » (obligatoire pour Essayer avant d’acheter)
  5. Téléverser le paquet logiciel et les supports de présentation

2.2 Enregistrer le brouillon (nouvelle capacité)

En bas du formulaire produit se trouvent deux boutons :

Bouton Comportement
Enregistrer le brouillon Le produit est enregistré au statut DRAFT, n’entre pas dans la file de revue et peut être modifié à tout moment
Enregistrer et soumettre la revue Le produit entre dans la file de revue (PENDING_RELEASE)

Après l’enregistrement du brouillon / la soumission, la plateforme synchronise asynchroniquement le produit vers l’environnement Waffo Test (un échec déclenche seulement une alerte sans bloquer l’enregistrement) ; c’est la condition pour pouvoir passer commande en phase de débogage. Recommandation : pendant le développement, enregistrer le brouillon suffit pour commencer à déboguer, inutile de soumettre la revue.

Après l’enregistrement, noter le productUniqueCode (visible sur la page de publication, pas un secret).

2.3 Intégrer le SDK de licence (deux scénarios d’intégration)

PowerSoftware.net propose deux modes d’intégration de licence pour les logiciels clients. Choisissez selon votre situation :

Scénario A : chaîne complète de la plateforme (Essayer avant d’acheter) Scénario B : commandes hors plateforme
Produits concernés Logiciel client + modèle de vente Essayer avant d’acheter Logiciel en promotion seule (encaissement autonome) ; ou logiciel serveur / client avec modèle Payer d’abord (PAY_FIRST) ou fonctions VIP à encaissement autonome
Qui gère le paiement La plateforme PowerSoftware.net (Waffo, Alipay, PayPal) ; le débogage utilise l’environnement Waffo Test comme canal de paiement Le développeur lui-même (paiement dans l’application ou autres canaux)
Qui émet les codes La plateforme émet automatiquement après paiement réussi Le logiciel appelle l’API de la plateforme pour émettre (signature HMAC)
Secret de licence licenseApiSecret requis ? ❌ Non ✅ Oui (stocké côté serveur uniquement, jamais côté client)
Serveur requis ? ❌ Non, purement côté client ✅ Oui (conserve licenseApiSecret, relaie les requêtes d’émission)
Licence d’essai ✅ Prise en charge (claimTrial) ❌ Pas d’essai (l’essai ne concerne que les produits Essayer avant d’acheter)
Page d’achat Fournie par la plateforme, redirection SDK en une ligne Pas de page d’achat plateforme, le développeur gère lui-même

Concernant la configuration des éditions : tous les types de produits (client/serveur/promotion seule) peuvent activer les codes de licence et personnaliser les éditions (BASIC/PRO/ULTIMATE, etc.). Les prix des éditions et les listes de fonctionnalités ne s’affichent sur la page d’achat que si le développeur coche « La plateforme encaisse les frais de licence » (licensePlatformPayment) ; sinon, le développeur gère lui-même l’encaissement et la plateforme ne fournit que l’émission et la vérification des codes.

Comment choisir :

  • Développeur indépendant / petite équipe sans serveur propre → Scénario A (les chapitres 4 et 5 de ce document suivent le scénario A comme ligne principale)
  • Vous avez déjà des canaux de paiement (p. ex. marchand WeChat/Alipay) et souhaitez uniquement l’émission et la vérification de codes par la plateforme → Scénario B

2.3.1 Installation du SDK

Les trois langages (Node.js / Python / Java) sont sans dépendances — copiez directement le code source dans votre projet, sans aucun gestionnaire de paquets. L’algorithme du code machine est cohérent entre langages (une même machine génère le même machineCode). Dépôt SDK : github.com/mizhanchengxi/powersoftware-license-sdk

2.3.2 Scénario A : chaîne complète de la plateforme (Essayer avant d’acheter)

Prérequis : le modèle de vente du produit est Essayer avant d’acheter, les jours d’essai et les éditions de licence sont configurés, « La plateforme encaisse les frais de licence » est coché. Le secret de licence licenseApiSecret n’est PAS requis :

# Python
from ps_license_sdk import LicenseClient, machine_code

client = LicenseClient(product_unique_code="PRO-2026-001", api_secret="")  # laisser api_secret vide
mc = machine_code()
// Node.js
import { LicenseClient, machineCode } from './index.js';

const client = new LicenseClient({ productUniqueCode: 'PRO-2026-001', apiSecret: "" });  // Scénario A : secret vide
const mc = machineCode();
// Java
import com.powersoftware.sdk.LicenseClient;

LicenseClient client = new LicenseClient("PRO-2026-001", "");  // Scénario A : secret vide
String mc = LicenseClient.machineCode();

Parcours complet d’intégration :

Premier lancement
    │
    ├─ claimTrial(machineCode) ────────────→ obtenir la licence d’essai
    │     ↓ retourne { licenseCode, activationToken, licenseUpgradeMode }
    │     ↓ stockage persistant local
    │
    ├─ Pendant l’essai : toutes les fonctions disponibles
    │     │
    │     └─ clic sur une fonction payante → verifyCached() vérification avec cache 60s → autorisation
    │
    └─ Essai expiré / non activé
          │
          ├─ verifyCached() retourne invalid/expired
          ├─ boîte de dialogue : « achat d’une licence d’activation requis »
          └─ purchaseUrl(machineCode) → redirection vers la page d’achat de la plateforme
                │
                ↓ l’utilisateur paie sur la plateforme → la plateforme émet le code + envoi par e-mail
                │
          L’utilisateur revient dans le logiciel et saisit le code de licence
                │
                ├─ activate(licenseCode, machineCode)
                │     ↓ retourne { activationToken, licenseUpgradeMode }, stockage persistant local
                │
                └─ utilisation ultérieure → vérification verifyCached() → autorisation

À implémenter : claimTrial (obtenir l’essai au premier lancement) → verifyCached (vérification des fonctions payantes) → purchaseUrl (redirection vers la page d’achat sans licence) → activate (activation par saisie du code) → persistance locale de licenseCode + activationToken → traitement des codes d’erreur LicenseError.

Code principal (Python) :

import json
from pathlib import Path
from ps_license_sdk import LicenseClient, machine_code

# ---------- Initialisation ----------
client = LicenseClient(product_unique_code="PRO-2026-001", api_secret="")
CRED_FILE = Path.home() / ".myapp" / "license.json"

def load_cred():
    if CRED_FILE.exists():
        return json.loads(CRED_FILE.read_text())
    return {}

def save_cred(d):
    CRED_FILE.parent.mkdir(parents=True, exist_ok=True)
    CRED_FILE.write_text(json.dumps(d, ensure_ascii=False))

# ---------- Premier lancement : obtenir l’essai ----------
def claim_trial():
    mc = machine_code()
    try:
        result = client.claim_trial(mc)
        save_cred({
            "licenseCode": result["licenseCode"],
            "activationToken": result["activationToken"],
        })
        print(f"Essai activé, code de licence : {result['licenseCode']}")
    except Exception as e:
        print(f"Échec de l’obtention de l’essai : {e}")

# ---------- Vérifier la licence (appelée au clic sur une fonction payante) ----------
def check_license(required_edition="PRO"):
    cred = load_cred()
    if not cred.get("licenseCode"):
        return {"valid": False, "reason": "Non activé"}

    mc = machine_code()
    try:
        result = client.verify_cached(
            cred["licenseCode"], mc, cred["activationToken"]
        )
        if not result.get("valid"):
            return {"valid": False, "reason": "Licence invalide ou expirée"}

        user_edition = result.get("edition", "")
        levels = {"BASIC": 0, "PRO": 1, "ULTIMATE": 2}
        if levels.get(user_edition, 0) < levels.get(required_edition, 0):
            return {"valid": False, "reason": f"Édition {required_edition} ou supérieure requise"}

        return {"valid": True, "edition": user_edition,
                "expiryTime": result.get("expiryTime"),
                "trialExpiryTime": result.get("trialExpiryTime")}
    except Exception as e:
        return {"valid": False, "reason": str(e)}

# ---------- Activer un code de licence (après achat) ----------
def activate(license_code):
    mc = machine_code()
    try:
        result = client.activate(license_code, mc)
        save_cred({
            "licenseCode": license_code,
            "activationToken": result["activationToken"],
        })
        return True
    except Exception as e:
        print(f"Échec de l’activation : {e}")
        return False

# ---------- Ouvrir la page d’achat ----------
def open_purchase_page():
    mc = machine_code()
    url = client.purchase_url(mc)
    import webbrowser
    webbrowser.open(url)

Exemple de blocage de fonction :

# Définir l’édition requise par fonction
FEATURE_EDITION = {
    "basic_feature":   "BASIC",
    "plus_feature":    "PRO",
    "ultimate_feature": "ULTIMATE",
}

def run_feature(feature_name):
    required = FEATURE_EDITION.get(feature_name, "BASIC")
    if required == "BASIC":
        do_basic_feature()
        return

    result = check_license(required)
    if result["valid"]:
        do_paid_feature(feature_name)
    else:
        print(f"Impossible d’utiliser cette fonction : {result['reason']}")
        open_purchase_page()

2.3.3 Scénario B : commandes hors plateforme (encaissement autonome)

Produits concernés : logiciels en promotion seule (encaissement autonome), ou logiciels serveurs / clients avec modèle Payer d’abord (PAY_FIRST) ou fonctions VIP à encaissement autonome.

Prérequis : le produit a licenseEnabled activé ; dans le backend développeur, obtenir licenseApiSecret (stocké côté serveur uniquement, jamais exposé au client). Architecture :

Client                  Votre serveur                     Plateforme PowerSoftware.net
  │                       │                                 │
  │ L’utilisateur paie    │                                 │
  │ (votre paiement)      │                                 │
  ├──────────────────────→│                                 │
  │                       │ generateForSoftware(            │
  │                       │   machineCode, edition,         │
  │                       │   clientOrderId)                │
  │                       │ (signature HMAC + timestamp)    │
  │                       ├───────────────────────────────→│
  │                       │ ← retourne licenseCode          │
  │ ← retourne licenseCode│                                 │
  │                       │                                 │
  │ activate(licenseCode, machineCode)                     │
  ├───────────────────────────────────────────────────────→│
  │ ← retourne activationToken                             │
  │                       │                                 │
  │ verifyCached(...)     │                                 │
  ├───────────────────────────────────────────────────────→│
  │ ← { valid, edition, expiryTime }                       │

Serveur (conserve le secret de licence licenseApiSecret, émet les codes) :

from ps_license_sdk import LicenseClient, machine_code

server_client = LicenseClient(
    product_unique_code="PRO-2026-001",
    api_secret="VOTRE_SECRET_EMISSION_FROM_DEVELOPER_CONSOLE",
)

def issue_license(user_machine_code, edition="PRO", order_id=""):
    """Après paiement de l’utilisateur, le serveur appelle la plateforme pour émettre le code"""
    result = server_client.generate_for_software(
        machine_code_value=user_machine_code,
        edition=edition,
        expiry_days=365,
        client_order_id=order_id,
    )
    return result["licenseCode"]

Client (pas besoin de licenseApiSecret, activation et vérification) :

client = LicenseClient(product_unique_code="PRO-2026-001", api_secret="")

def activate(license_code):
    mc = machine_code()
    result = client.activate(license_code, mc)
    save_cred({"licenseCode": license_code,
               "activationToken": result["activationToken"]})

À implémenter : côté serveur generateForSoftware (émission) + upgradeForSoftware (mise à niveau/renouvellement) ; côté client activate / verifyCached + persistance locale des identifiants + traitement des codes d’erreur LicenseError.

2.3.4 Référence des méthodes du SDK

Méthode Scénario A Scénario B Signature Description
machine_code() Générer le code machine (cohérent entre langages)
claim_trial(mc) Obtenir la licence d’essai (produits Essayer avant d’acheter uniquement)
activate(code, mc) Activer le code de licence, lier à la machine
verify(code, mc, token) Vérifier l’état de la licence
verify_cached(code, mc, token) Vérification avec cache local (60s)
deactivate(code, mc) Délier la machine (connexion requise, scénario navigateur)
purchase_url(mc) Générer l’URL de la page d’achat plateforme
generate_for_software(mc, edition, ...) HMAC Émission de code dans le logiciel (serveur uniquement)
upgrade_for_software(code, edition, ...) HMAC Mise à niveau/renouvellement dans le logiciel (serveur uniquement)

Note sur les champs retournés : les réponses de succès de activate / verify / claimTrial contiennent toutes licenseUpgradeMode (politique de mise à niveau du produit : SAME_CODE = la clé reste inchangée ; NEW_CODE = la clé est re-liée). Le client s’en sert pour décider d’afficher ou non le champ « Lier une clé de licence » : avec SAME_CODE, la clé ne change jamais, inutile de demander une nouvelle saisie ; avec NEW_CODE, une nouvelle clé est émise lors de la mise à niveau / du renouvellement — remplacez le licenseCode stocké localement par celui renvoyé. Par défaut SAME_CODE si absente ; les résultats de verify sont mis en cache ~60 s, un changement prend effet sous 60 s au plus. Les réponses contiennent aussi trialExpiryTime (instantané de l’expiration d’essai, chaîne ISO 8601 ; null si la licence ne provient pas d’un essai). Le client peut l’utiliser comme période de grâce : si l’utilisateur teste la version complète puis achète une édition inférieure, les fonctions de l’édition supérieure restent déverrouillées jusqu’à trialExpiryTime. Les réponses contiennent aussi trialExpiryTime (instantané de l’expiration d’essai, chaîne ISO 8601 ; null si la licence ne provient pas d’un essai). Le client peut l’utiliser comme période de grâce : si l’utilisateur teste la version complète puis achète une édition inférieure, les fonctions de l’édition supérieure restent déverrouillées jusqu’à trialExpiryTime. Les réponses contiennent aussi trialExpiryTime (instantané de l’expiration d’essai, chaîne ISO 8601 ; null si la licence ne provient pas d’un essai). Le client peut l’utiliser comme période de grâce : si l’utilisateur teste la version complète puis achète une édition inférieure, les fonctions de l’édition supérieure restent déverrouillées jusqu’à trialExpiryTime.

Le débogage à double environnement est totalement transparent pour les deux scénarios :

  • Scénario A : sur les machines de débogage, claimTrial / les paiements sur la page d’achat passent automatiquement par l’environnement Test (voir chapitre 4)
  • Scénario B : lorsqu’une machine de débogage appelle generateForSoftware, la plateforme route également par code machine vers l’environnement Test et retourne un code préfixé T- ; le code serveur ne nécessite aucune modification
  • Les appels SDK sont identiques pendant le débogage et après la mise en ligne — aucun paramètre d’environnement ni branche de code nécessaire ; le routage d’environnement est effectué automatiquement par le serveur de la plateforme

3. Détails de l’intégration de licence (communs aux deux scénarios)

3.1 Spécification de stockage local des identifiants

Le SDK lui-même ne gère pas la persistance — c’est au développeur de l’implémenter. Contenu stocké :

{
  "licenseCode": "XXXXXXXXXXXX",
  "activationToken": "YYYYYYYYYYYY",
  "lastVerify": {
    "valid": true,
    "edition": "ULTIMATE",
    "expiryTime": 1735689600000,
    "trialExpiryTime": 1735000000000,
    "trialExpiryTime": 1735000000000,
    "trialExpiryTime": 1735000000000,
    "cachedAt": 1735689600000
  }
}

Principes :

  • Ne stocker que licenseCode + activationToken + le dernier résultat de verify
  • Ne pas stocker d’informations de licence complètes déchiffrables (la protection anti-rétro-ingénierie est inutile ; sert uniquement de cache)
  • Le cache de 60s de verifyCached réside dans le processus SDK, expire après redémarrage et nécessite un nouvel appel verify

3.2 Comparaison des niveaux d’édition (edition)

Les développeurs définissent eux-mêmes les codes d’édition (p. ex. BASIC / PRO / ULTIMATE) et les configurent sur la page de publication de la plateforme. Tous les types de produits (client/serveur/promotion seule) peuvent personnaliser leurs éditions après activation des codes de licence. Le client vérifie par comparaison de niveaux :

EDITION_LEVEL = {"BASIC": 0, "PRO": 1, "ULTIMATE": 2, "TRIAL": 99}

def edition_sufficient(user_edition, required_edition):
    return EDITION_LEVEL.get(user_edition, 0) >= EDITION_LEVEL.get(required_edition, 0)

Correspondance courante (référence) :

Niveau de fonction Code d’édition Niveau Fonctions typiques
Basique BASIC 0 Retouche de base, conversion de formats
Pro PRO 1 Traitement par lots, agrandissement HD
Ultime ULTIMATE 2 Restauration IA, assistant de couverture

Les noms et codes d’édition sont librement définis par le développeur sur la plateforme — BASIC/PRO/ULTIMATE n’est pas obligatoire. Les prix des éditions et les listes de fonctionnalités ne s’affichent sur la page d’achat que si « La plateforme encaisse les frais de licence » est coché.

3.3 Traitement des codes d’erreur (LicenseError)

Le SDK lève LicenseError avec la propriété error_code :

from ps_license_sdk import LicenseError

try:
    result = client.verify_cached(...)
except LicenseError as e:
    if e.error_code == "expired":
        open_purchase_page()
    elif e.error_code == "revoked":
        show_message("La licence a été révoquée, veuillez contacter le support")
    elif e.error_code == "machineLimit":
        show_message("Limite de machines liées atteinte, veuillez délier l’ancien appareil dans l’espace personnel")
    elif e.error_code == "NETWORK_ERROR":
        show_message("Erreur réseau, veuillez vérifier la connexion et réessayer")
    else:
        show_message(f"Échec de la vérification : {e}")
Code d’erreur Signification Traitement recommandé côté client
codeNotFound Le code de licence n’existe pas Vérifier la saisie
revoked Révoqué Inviter à contacter le support
expired Expiré Orienter vers l’achat/le renouvellement
machineLimit Limite de machines liées atteinte Orienter vers la déliaison dans l’espace personnel
tooManyAttempts Limitation de débit déclenchée Inviter à réessayer plus tard
trialNotEnabled Le produit n’a pas activé l’essai Vérifier la configuration plateforme
trialAlreadyPurchased Produit déjà acheté Signaler l’achat existant et rediriger vers la page d’achat
trialAlreadyPurchased Produit déjà acheté Signaler l’achat existant et rediriger vers la page d’achat
trialAlreadyPurchased Produit déjà acheté Signaler l’achat existant et rediriger vers la page d’achat
NETWORK_ERROR Réseau/délai dépassé Tolérance hors ligne ou invitation à réessayer

3.4 Redirection vers la page d’achat (scénario A uniquement)

3.4.1 URL de la page d’achat

https://www.powersoftware.app/product/license/purchase?productUniqueCode={productUniqueCode}&machineCode={machineCode}

Méthode SDK :

url = client.purchase_url(mc)

Lorsqu’une machine de débogage accède à cette page, le badge « Mode débogage (environnement de test) » apparaît en haut ; le paiement passe par le canal de test (voir chapitre 4). La langue est détectée automatiquement par la page d’achat selon le navigateur de l’utilisateur (préfixe d’URL / Accept-Language) — le SDK n’a pas à s’en occuper.

3.4.2 Sites : utiliser uniformément le site international .app, le développeur n’a pas à choisir le site d’achat

powersoftware.app (international) powersoftware.cn (Chine)
Moyens de paiement Waffo (carte / Apple Pay / Google Pay, etc.) + PayPal + Alipay Alipay uniquement
Pays/devise Cloudflare détecte automatiquement par IP (CN→CNY, autres→USD) Fixe country=CN, CNY
Langue Automatique par préfixe d’URL / Accept-Language Fixe zh-CN
Positionnement Seule entrée d’achat que le développeur doit utiliser Site de relais pour les paiements Alipay du site international

Le développeur n’a pas à choisir le site d’achat : purchaseUrl pointe uniformément vers le site international .app. Les utilisateurs à l’étranger effectuent directement leurs paiements Waffo / PayPal sur .app ; lorsque les utilisateurs chinois choisissent Alipay sur .app, la plateforme redirige automatiquement vers le site chinois .cn pour le paiement Alipay (l’état de connexion est synchronisé automatiquement, pas besoin de se reconnecter) et revient au parcours de licence après paiement réussi. Toute la chaîne est transparente pour l’utilisateur et le développeur.

# Correct : utiliser fixement le site international, ne pas changer de base selon la région/langue
url = client.purchase_url(mc)

# Déconseillé : détecter soi-même la région et passer une base .cn — la redirection Alipay
# est déjà gérée par la plateforme, et coder .cn en dur fait perdre les paiements Waffo / PayPal

4. Phase de débogage (double environnement, nouveau en v4)

La validation la plus fiable avant la mise en ligne : enregistrer l’ordinateur que vous utilisez au quotidien pour le développement comme « machine de débogage » et parcourir tout le processus avec la véritable chaîne de paiement.

4.1 Enregistrer le code machine

  1. Espace personnel → « Mes codes machine » → enregistrer le code machine de l’ordinateur de débogage
    • Le code machine peut être généré avec machine_code() du SDK (même machine, trois langages, même résultat)
  2. Noter ce code machine

4.2 Enregistrer la machine de débogage

  1. Developer Center → liste des produits → bouton « Machines de débogage » du produit cible
  2. Dans la boîte de dialogue, choisir parmi les codes machine enregistrés et ajouter au produit (note possible)
  3. Limite : 3 machines de débogage maximum par produit ; interrupteur (désactiver temporairement le routage) et suppression pris en charge

4.3 Ce qui se passe sur la machine de débogage

Sur une machine de débogage enregistrée et activée, toute la chaîne de ce produit bascule automatiquement vers l’environnement Waffo Test :

Machine de débogage (votre PC)   Plateforme PowerSoftware.net (le serveur détermine l’environnement automatiquement)
    │                  │
    │ claimTrial(machineCode)
    ├─────────────────→│ Cette machine est une machine de débogage de ce produit → chemin Test
    │                  │
    │ ← licence d’essai (code préfixé T-, écrit dans la table de licences test)
    │                  │
    │ purchaseUrl(machineCode)
    ├─────────────────→│ La page d’achat affiche le badge « Mode débogage (environnement de test) »
    │                  │ → paiement avec carte test Waffo (pas d’argent réel)
    │                  │ → commande dans la table de commandes test, la plateforme émet un code test (code T-)
    │ ← la plateforme émet le code (code T-)
    │                  │
    │ activate(code T-, machineCode)
    ├─────────────────→│ Le préfixe T- localise directement la table test
    │ ← activationToken│
    │                  │
    │ verifyCached(...)
    ├─────────────────→│ Vérification réussie
    │ ← { valid, edition, expiryTime }

Points clés :

  • Identification : un code de licence préfixé T- est une licence test ; le badge « Mode débogage (environnement de test) » apparaît en haut de la page d’achat
  • Paiement : passe par le checkout Waffo Test avec des cartes de test (p. ex. 4576 ... 0110) ; aucun débit réel
  • Zéro modification de code : le client ne nécessite aucune modification — le même code se comporte de manière identique sur la machine de débogage et sur les machines des utilisateurs réels (seules les tables backend diffèrent)

4.4 Liste de débogage recommandée

  • Premier lancement de la machine de débogage → claimTrial réussi, code d’essai préfixé T- obtenu
  • Pendant l’essai, verifyCached retourne valid, les fonctions payantes sont autorisées
  • purchaseUrl ouvre la page d’achat, le badge « Mode débogage » apparaît
  • Paiement avec carte test terminé → code de licence test reçu (e-mail/page)
  • activate réussi → verifyCached passe
  • Blocage des éditions correct (un code inférieur est bloqué sur une fonction supérieure)
  • Limite de liaison machine (machineLimit) et parcours de déliaison fonctionnels
  • (scénario B uniquement) generateForSoftware sur la machine de débogage retourne un code préfixé T-, activation/vérification normales ; le même appel avec une machine non enregistrée retourne un code officiel
  • Sur un ordinateur non enregistré, répéter claimTrial et confirmer que la chaîne de production est utilisée (vérification de contrôle)

4.5 Précautions de débogage

Sujet Description
Nettoyage des données test Les licences/commandes test n’affectent pas la production, aucun nettoyage nécessaire ; pour réinitialiser, retirer l’appareil du panneau des machines de débogage puis le réajouter
Interrupteur de débogage Pour ne pas passer temporairement par la chaîne test, désactiver l’interrupteur dans le panneau des machines de débogage — inutile de supprimer l’appareil
Produits en promotion seule Les produits de type « promotion seule » ne sont pas synchronisés dans le catalogue de produits Waffo ; pas de chaîne d’achat de débogage
Aucun prix valide Si le prix principal/secondaire et toutes les éditions de licence n’ont aucun prix normal, la synchronisation du produit test échoue (alerte DingTalk) — veuillez configurer au moins un prix d’édition

5. Phase de mise en ligne

5.1 Soumettre la revue

  1. Une fois tous les points de la liste de débogage validés, cliquer sur « Enregistrer et soumettre la revue » dans le formulaire produit
  2. Le produit entre dans la file de revue (PENDING_RELEASE)

Pour les produits enregistrés en brouillon pendant la phase de débogage, le contenu soumis correspond au dernier brouillon ; toute modification pendant la revue repasse automatiquement au statut brouillon (empêche les changements de contenu pendant la revue) — une nouvelle soumission est nécessaire.

5.2 Revue approuvée → synchronisation automatique en production

Après approbation par l’équipe d’exploitation de la plateforme :

  1. Le statut du produit passe à publié et listé
  2. La plateforme synchronise automatiquement le produit vers l’environnement de production Waffo (réécrit waffo_product_id), crée/restaure les produits du checkout de production
  3. La page de détail du produit et les résultats de recherche sont visibles par tous les utilisateurs

5.3 Chaîne des utilisateurs réels (production)

La chaîne des utilisateurs réels (machines non-débogage) est identique au débogage — elle est simplement entièrement située dans les tables de production :

Premier lancement → claimTrial obtenir l’essai (code de licence officiel, sans préfixe T-)
        → essai expiré → purchaseUrl vers la page d’achat (paiement réel Alipay / PayPal)
        → la plateforme émet automatiquement le code après paiement réussi + envoi par e-mail
        → activate activer → vérification verifyCached autorisation

Les utilisateurs du scénario B (encaissement autonome) ne passent pas par la page d’achat plateforme : après paiement via votre canal, votre serveur appelle generateForSoftware pour émettre un code de licence officiel ; la chaîne d’activation/vérification ultérieure est identique au scénario A.

5.4 Liste de vérification de mise en ligne

  • Accéder à la page de détail du produit avec un ordinateur non enregistré comme machine de débogage et confirmer l’affichage normal
  • La page d’achat n’affiche aucun badge « Mode débogage »
  • Paiement réel de petit montant → émission du code → activation réussie
  • La commande apparaît dans la liste des commandes du Developer Center (les commandes test n’y apparaissent pas)

6. Exploitation après la mise en ligne

Action Entrée Description
Consulter les commandes Developer Center → Mes commandes Commandes de production uniquement ; les commandes test ne participent ni au partage de revenus ni à la réconciliation
Délier un utilisateur Espace personnel de l’utilisateur / licence manuelle par le développeur Quota de réattribution : après déliaison, aucune nouvelle déliaison possible pendant 30 jours
Itération de version Modifier le produit → enregistrer le brouillon / soumettre la revue La modification synchronise à nouveau asynchroniquement vers Waffo Test ; les nouvelles versions peuvent continuer à être validées sur la machine de débogage
Remboursement Waffo Dashboard L’acheteur ouvre un ticket, le marchand examine dans le Dashboard ; les remboursements de commandes test révoquent seulement la licence test
Retirer le débogage Retirer l’appareil du panneau des machines de débogage Une fois la version stable, il est recommandé de retirer la machine de débogage pour éviter l’utilisation accidentelle de la chaîne test

7. Questions fréquentes (FAQ)

Q1 : Le débogage nécessite-t-il de modifier le code client ou la configuration ? Non. Le routage d’environnement est déterminé automatiquement par le serveur de la plateforme selon que le code machine figure ou non dans la liste des machines de débogage ; les appels SDK sont identiques.

Q2 : Le code de licence obtenu sur la machine de débogage peut-il servir à de vrais utilisateurs ? Non, et ce n’est pas recommandé. Les codes T- ne sont valides que dans les tables test, et les données de débogage ne participent à aucune logique de production ; donner des codes test à de vrais utilisateurs les empêcherait d’obtenir un support après-vente via le parcours de vérification normal.

Q3 : Le débogage coûte-t-il de l’argent ? Non. Le canal de paiement test utilise des cartes de test ; aucun débit réel ; les commandes test ne participent pas au partage de revenus/règlement.

Q4 : Le débogage affecte-t-il la revue de mon produit ? Non. Les données de débogage sont totalement découplées de la revue ; le statut brouillon suffit pour déboguer, la soumission est à votre discrétion.

Q5 : Que faire si je veux déboguer sur plusieurs ordinateurs ? Jusqu’à 3 machines de débogage peuvent être enregistrées par produit ; il suffit d’ajouter/retirer dans le panneau des machines de débogage.

Q6 : Si le produit est de type « promotion seule » ou sans prix configuré, puis-je déboguer l’achat ? Non. Les produits en promotion seule ne sont pas synchronisés dans le catalogue Waffo ; sans prix valide, la synchronisation du produit test échoue. Pour ces produits, seuls l’essai et la chaîne de vérification peuvent être débogués.

Q7 : Que se passe-t-il si j’oublie de désactiver l’interrupteur de débogage avant la mise en ligne ? L’impact se limite à la machine que vous avez enregistrée — elle continue de passer par la chaîne test ; tous les utilisateurs réels ne sont pas affectés. Une fois la stabilité confirmée, il suffit de la retirer du panneau des machines de débogage.

8. Liste d’intégration (à vérifier point par point avant la mise en ligne)

Scénario A (chaîne complète de la plateforme)

  • Publier le produit sur PowerSoftware.net, choisir le modèle de vente « Essayer avant d’acheter »
  • Configurer les jours d’essai (recommandé 7~14 jours)
  • Configurer les éditions de licence (code d’édition + nom + prix + liste de fonctionnalités)
  • Confirmer que « La plateforme encaisse les frais de licence » est coché (obligatoire pour Essayer avant d’acheter)
  • Noter le productUniqueCode
  • Copier le code source du SDK dans le projet (voir 2.3.1)
  • Implémenter claimTrial → obtenir l’essai au premier lancement
  • Implémenter activate → activation par saisie du code par l’utilisateur
  • Implémenter verifyCached → vérification au clic sur une fonction payante
  • Implémenter purchaseUrl → redirection vers la page d’achat sans licence (site international .app uniforme, pas de choix de site)
  • Implémenter la persistance locale des identifiants (licenseCode + activationToken)
  • Implémenter la logique de comparaison des niveaux d’édition (voir 3.2)
  • Implémenter le traitement des codes d’erreur LicenseError (voir 3.3)
  • Enregistrer la machine de débogage et parcourir la liste de débogage à double environnement (voir 4.4)
  • Soumettre la revue → revue approuvée → vérification de mise en ligne (voir 5.4)

Scénario B (commandes hors plateforme)

  • Publier le produit sur PowerSoftware.net, activer licenseEnabled
  • Configurer les éditions de licence (code d’édition + nom) ; si l’encaissement plateforme est souhaité, cocher « La plateforme encaisse les frais de licence » et renseigner les prix
  • Obtenir licenseApiSecret dans le backend développeur
  • Noter le productUniqueCode
  • Mettre en place un serveur qui conserve le secret de licence licenseApiSecret et implémente l’interface d’émission (le secret ne doit pas être distribué au client)
  • Côté client, copier le code source du SDK dans le projet
  • Côté serveur, implémenter generateForSoftware (émission)
  • Côté serveur, implémenter upgradeForSoftware (mise à niveau/renouvellement)
  • Côté client, implémenter activate / verifyCached
  • Implémenter la persistance locale des identifiants
  • Implémenter la logique de comparaison des niveaux d’édition (voir 3.2)
  • Implémenter le traitement des codes d’erreur LicenseError (voir 3.3)
  • Enregistrer la machine de débogage et vérifier la chaîne des codes T- (voir 4.4)
  • Soumettre la revue → revue approuvée → vérification de mise en ligne (voir 5.4)

Annexe : dépôt SDK (GitHub)

github.com/mizhanchengxi/powersoftware-license-sdk
├── node/      code source SDK (ESM, sans dépendances, un seul fichier)
├── python/    code source SDK (py3, sans dépendances, 3 fichiers)
├── java/      code source SDK (Java 8+, sans dépendances, 3 fichiers)
└── docs/      documents de spécification du SDK

Les trois paquets fournissent : machineCode() / sign() / LicenseClient (comprenant activate / verify / deactivate / claimTrial / generateForSoftware / upgradeForSoftware / verifyCached / purchaseUrl).

Ce document est la mise à jour v4 du Guide d’intégration de licence des logiciels clients (CLIENT_SOFTWARE_GUIDE) ; il couvre l’intégralité de son contenu et ajoute le débogage à double environnement ainsi que les capacités de brouillon/soumission de revue.