Lizenzcode: Leitfaden für Entwicklung, Debugging und Release

v1.0.0

Client-Software Entwicklung → Debugging → Release: Gesamtprozess-Leitfaden (v4)

Gilt für: Entwickler, die Client-Software auf PowerSoftware.net veröffentlichen und das Lizenzcode-System integrieren. Dieses Dokument deckt den gesamten Lebenszyklus von „Produkt erstellen" bis „Kauf durch echte Nutzer" ab. Der Schwerpunkt liegt auf der in v4 neuen Dual-Environment-Debugging-Fähigkeit: Vor dem Release den vollständigen Ablauf mit einer echten Zahlungspipeline (Waffo Test Environment) auf dem eigenen Rechner als Debug-Maschine durchlaufen.

1. Gesamtprozess-Überblick

┌──────────────┐   ┌──────────────┐   ┌──────────────┐   ┌──────────────┐
│ ① Entwicklung│ → │ ② Debugging  │ → │ ③ Release    │ → │ ④ Betrieb    │
│              │   │              │   │              │   │              │
│ Entwurf      │   │ Debug-       │   │ Review       │   │ Bestellungen │
│ SDK einbinden│   │ Maschine     │   │ einreichen   │   │ lösen/erstatten│
│ Entwurf      │   │ echte Pipeline│  │ genehmigt    │   │ Versionen    │
│ speichern    │   │ (Test-Env)   │   │ Prod-Sync    │   │ iterieren    │
└──────────────┘   └──────────────┘   └──────────────┘   └──────────────┘
Phase Produktstatus Wo liegen Lizenzen/Bestellungen Echte Einnahmen?
① Entwicklung Entwurf (DRAFT) Nein
② Debugging Entwurf / im Review Test-Tabellen (Lizenzcodes mit T- Präfix) Nein (Test-Zahlungskanal)
③ Release Veröffentlicht Produktions-Tabellen Ja

Kernregel: Debugging und Produktion sind vollständig isoliert. Alles, was auf Debug-Maschinen passiert (Testversionen, Bestellungen, Zahlungen, Code-Ausstellung, Aktivierung, Erstattungen), betrifft nur die Test-Tabellen — es fließt nicht in die Umsatzbeteiligung oder Abrechnung ein und beeinflusst keine echten Nutzer; Zugriffe von Nicht-Debug-Maschinen laufen immer über die Produktions-Pipeline.

2. Entwicklungsphase

2.1 Produkt erstellen

  1. Im PowerSoftware.net Developer Center anmelden → Produkt veröffentlichen, Produkttyp „Client-Software" wählen
  2. Als Verkaufsmodell Try-Before-You-Buy wählen und Testtage eintragen (empfohlen 7~14 Tage)
  3. Lizenz-Editionen konfigurieren: standardmäßig drei Stufen BASIC / PRO / ULTIMATE; Code, Name, Preis und Funktionsliste sind anpassbar
  4. „Plattform zieht Lizenzgebühren ein" aktivieren (bei Try-Before-You-Buy Pflicht)
  5. Softwarepaket und Vorstellungsmaterial hochladen

2.2 Entwurf speichern (neue Fähigkeit)

Am unteren Rand des Produktformulars gibt es zwei Schaltflächen:

Schaltfläche Verhalten
Entwurf speichern Produkt wird als DRAFT gespeichert, kommt nicht in die Review-Warteschlange und kann jederzeit weiter bearbeitet werden
Speichern & Review einreichen Produkt gelangt in die Review-Warteschlange (PENDING_RELEASE)

Nach dem Speichern als Entwurf / Einreichen zum Review synchronisiert die Plattform das Produkt asynchron in die Waffo Test Environment (Fehler lösen nur Alarme aus und blockieren das Speichern nicht). Dies ist die Voraussetzung für Bestellungen in der Debug-Phase. Empfehlung: Während der Entwicklung genügt das Speichern eines Entwurfs, um mit dem Debugging zu beginnen — kein Review nötig.

Nach dem Speichern den productUniqueCode notieren (auf der Veröffentlichungsseite sichtbar, kein Geheimnis).

2.3 Lizenz-SDK integrieren (zwei Integrationsszenarien)

PowerSoftware.net bietet zwei Lizenz-Integrationswege für Client-Software. Wählen Sie je nach Situation:

Szenario A: Vollständige Plattform-Pipeline (Try-Before-You-Buy) Szenario B: Bestellungen außerhalb der Plattform
Geeignete Produkte Client-Software + Verkaufsmodell Try-Before-You-Buy Nur-Promotion-Software (Selbstinkasso); oder Server-/Client-Software mit Pay-First (PAY_FIRST) oder selbst abgerechneten VIP-Funktionen
Wer regelt die Zahlung PowerSoftware.net Plattform (Waffo, Alipay, PayPal); Debugging nutzt die Waffo Test Environment als Zahlungskanal Entwickler selbst (In-App-Zahlung oder andere Kanäle)
Wer stellt Codes aus Plattform stellt nach erfolgreicher Zahlung automatisch aus Software ruft die Plattform-API zur Ausstellung auf (HMAC-signiert)
Lizenz-Geheimnis licenseApiSecret nötig? ❌ Nein ✅ Ja (nur serverseitig, niemals im Client)
Server nötig? ❌ Nein, rein clientseitig ausreichend ✅ Ja (verwahrt licenseApiSecret, leitet Ausstellungsanfragen weiter)
Test-Lizenz ✅ Unterstützt (claimTrial) ❌ Keine Testversion (Test nur bei Try-Before-You-Buy)
Kaufseite Von der Plattform bereitgestellt, SDK-Weiterleitung in einer Zeile Keine Plattform-Kaufseite, Entwickler regelt es selbst

Zur Edition-Konfiguration: Alle Produkttypen (Client/Server/Nur-Promotion) können Lizenzcodes aktivieren und Editionen anpassen (BASIC/PRO/ULTIMATE usw.). Editionspreise und Funktionslisten werden nur auf der Kaufseite angezeigt, wenn der Entwickler „Plattform zieht Lizenzgebühren ein" (licensePlatformPayment) aktiviert; andernfalls regelt der Entwickler die Abrechnung selbst und die Plattform bietet nur Code-Ausstellung und -Verifizierung.

Wie wählen:

  • Indie-Entwickler / kleines Team ohne eigenen Server → Szenario A (Kapitel 4 und 5 dieses Dokuments nutzen Szenario A als Hauptlinie)
  • Bereits Zahlungskanäle vorhanden (z. B. WeChat-/Alipay-Merchant), nur Code-Ausstellung und -Verifizierung der Plattform gewünscht → Szenario B

2.3.1 SDK-Installation

Alle drei Sprachen (Node.js / Python / Java) sind ohne Abhängigkeiten — Quellcode direkt kopieren in Ihr Projekt, kein Paketmanager nötig. Der Maschinen-Code-Algorithmus ist sprachübergreifend konsistent (gleiche Maschine erzeugt gleichen machineCode). SDK-Repository: github.com/mizhanchengxi/powersoftware-license-sdk

2.3.2 Szenario A: Vollständige Plattform-Pipeline (Try-Before-You-Buy)

Voraussetzungen: Verkaufsmodell des Produkts ist Try-Before-You-Buy, Testtage und Lizenz-Editionen sind konfiguriert, „Plattform zieht Lizenzgebühren ein" ist aktiviert. Das Lizenz-Geheimnis licenseApiSecret wird NICHT benötigt:

# Python
from ps_license_sdk import LicenseClient, machine_code

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

const client = new LicenseClient({ productUniqueCode: 'PRO-2026-001', apiSecret: "" });  // Szenario A: Geheimnis leer lassen
const mc = machineCode();
// Java
import com.powersoftware.sdk.LicenseClient;

LicenseClient client = new LicenseClient("PRO-2026-001", "");  // Szenario A: Geheimnis leer lassen
String mc = LicenseClient.machineCode();

Vollständiger Integrationsablauf:

Erster Start
    │
    ├─ claimTrial(machineCode) ────────────→ Testlizenz beziehen
    │     ↓ Rückgabe { licenseCode, activationToken, licenseUpgradeMode }
    │     ↓ lokal persistent speichern
    │
    ├─ Innerhalb der Testphase: alle Funktionen verfügbar
    │     │
    │     └─ Klick auf Bezahl-Funktion → verifyCached() 60s-Cache-Prüfung → Freigabe
    │
    └─ Testphase abgelaufen / nicht aktiviert
          │
          ├─ verifyCached() gibt invalid/expired zurück
          ├─ Dialog: „Lizenz zum Aktivieren kaufen erforderlich"
          └─ purchaseUrl(machineCode) → Weiterleitung zur Plattform-Kaufseite
                │
                ↓ Nutzer zahlt auf der Plattform → Plattform stellt Code aus + E-Mail-Zustellung
                │
          Nutzer kehrt zur Software zurück und gibt den Lizenzcode ein
                │
                ├─ activate(licenseCode, machineCode)
                │     ↓ Rückgabe { activationToken, licenseUpgradeMode }, lokal persistent speichern
                │
                └─ Weitere Nutzung → verifyCached() Prüfung → Freigabe

Zu implementieren: claimTrial (Testlizenz beim ersten Start beziehen) → verifyCached (Prüfung bei Bezahl-Funktionen) → purchaseUrl (ohne Lizenz zur Kaufseite weiterleiten) → activate (Aktivierung, wenn der Nutzer den Lizenzcode eingibt) → lokale Persistenz von licenseCode + activationTokenLicenseError-Fehlercode-Behandlung.

Kern-Code (Python):

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

# ---------- Initialisierung ----------
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))

# ---------- Erster Start: Testlizenz beziehen ----------
def claim_trial():
    mc = machine_code()
    try:
        result = client.claim_trial(mc)
        save_cred({
            "licenseCode": result["licenseCode"],
            "activationToken": result["activationToken"],
        })
        print(f"Testlizenz aktiviert, Lizenzcode: {result['licenseCode']}")
    except Exception as e:
        print(f"Bezug der Testlizenz fehlgeschlagen: {e}")

# ---------- Lizenz prüfen (bei Klick auf Bezahl-Funktion) ----------
def check_license(required_edition="PRO"):
    cred = load_cred()
    if not cred.get("licenseCode"):
        return {"valid": False, "reason": "Nicht aktiviert"}

    mc = machine_code()
    try:
        result = client.verify_cached(
            cred["licenseCode"], mc, cred["activationToken"]
        )
        if not result.get("valid"):
            return {"valid": False, "reason": "Lizenz ungültig oder abgelaufen"}

        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"Edition {required_edition} oder höher erforderlich"}

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

# ---------- Lizenzcode aktivieren (nach Kauf durch Nutzer) ----------
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"Aktivierung fehlgeschlagen: {e}")
        return False

# ---------- Zur Kaufseite weiterleiten ----------
def open_purchase_page():
    mc = machine_code()
    url = client.purchase_url(mc)
    import webbrowser
    webbrowser.open(url)

Beispiel für Funktions-Sperre:

# Editions-Anforderungen je Funktion definieren
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"Diese Funktion ist nicht verfügbar: {result['reason']}")
        open_purchase_page()

2.3.3 Szenario B: Bestellungen außerhalb der Plattform (Selbstinkasso)

Geeignete Produkte: Nur-Promotion-Software (Selbstinkasso) oder Server-/Client-Software mit Pay-First-Verkaufsmodell (PAY_FIRST) bzw. selbst abgerechneten VIP-Funktionen.

Voraussetzungen: Produkt hat licenseEnabled aktiviert; im Developer-Backend wird licenseApiSecret bezogen (nur serverseitig speichern, niemals an den Client ausliefern). Architektur:

Client                  Ihr Server                        PowerSoftware.net Plattform
  │                       │                                 │
  │ Nutzer zahlt (Ihre    │                                 │
  │ Zahlung)              │                                 │
  ├──────────────────────→│                                 │
  │                       │ generateForSoftware(            │
  │                       │   machineCode, edition,         │
  │                       │   clientOrderId)                │
  │                       │ (HMAC-Signatur + timestamp)     │
  │                       ├───────────────────────────────→│
  │                       │ ← Rückgabe licenseCode          │
  │ ← Rückgabe licenseCode│                                 │
  │                       │                                 │
  │ activate(licenseCode, machineCode)                     │
  ├───────────────────────────────────────────────────────→│
  │ ← Rückgabe activationToken                             │
  │                       │                                 │
  │ verifyCached(...)     │                                 │
  ├───────────────────────────────────────────────────────→│
  │ ← { valid, edition, expiryTime }                       │

Server (verwahrt das Lizenz-Geheimnis licenseApiSecret, stellt Codes aus):

from ps_license_sdk import LicenseClient, machine_code

server_client = LicenseClient(
    product_unique_code="PRO-2026-001",
    api_secret="IHR_AUSSTELLUNGS_SCHLÜSSEL_FROM_DEVELOPER_CONSOLE",
)

def issue_license(user_machine_code, edition="PRO", order_id=""):
    """Nach Zahlung des Nutzers ruft der Server die Plattform zur Code-Ausstellung auf"""
    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 (benötigt kein licenseApiSecret, Aktivierung und Prüfung):

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"]})

Zu implementieren: serverseitig generateForSoftware (Code-Ausstellung) + upgradeForSoftware (Upgrade/Verlängerung); clientseitig activate / verifyCached + lokale Persistenz der Zugangsdaten + LicenseError-Fehlercode-Behandlung.

2.3.4 SDK-Methoden-Referenz

Methode Szenario A Szenario B Signatur Beschreibung
machine_code() Maschinen-Code erzeugen (sprachübergreifend konsistent)
claim_trial(mc) Testlizenz beziehen (nur Try-Before-You-Buy-Produkte)
activate(code, mc) Lizenzcode aktivieren, an Maschine binden
verify(code, mc, token) Lizenzstatus prüfen
verify_cached(code, mc, token) Prüfung mit lokalem Cache (60s)
deactivate(code, mc) Maschinen-Bindung lösen (Login erforderlich, Browser-Szenario)
purchase_url(mc) URL der Plattform-Kaufseite erzeugen
generate_for_software(mc, edition, ...) HMAC Code-Ausstellung in der Software (nur Server)
upgrade_for_software(code, edition, ...) HMAC Upgrade/Verlängerung in der Software (nur Server)

Hinweis zu den Rückgabefeldern: Die Erfolgsantworten von activate / verify / claimTrial enthalten alle zusätzlich licenseUpgradeMode (Upgrade-Richtlinie des Produkts: SAME_CODE = Lizenzschlüssel bleibt unverändert; NEW_CODE = Schlüssel wird neu gebunden). Der Client entscheidet daran, ob ein Eingabefeld „Lizenzschlüssel binden“ angezeigt wird: Bei SAME_CODE ändert sich der Schlüssel nie, eine erneute Eingabe ist nicht nötig; bei NEW_CODE wird beim Upgrade/Verlängerung ein neuer Schlüssel ausgestellt — der lokal gespeicherte licenseCode muss durch den zurückgegebenen ersetzt werden. Ohne Konfiguration gilt SAME_CODE; verify-Ergebnisse werden ca. 60 s gecacht, eine Änderung wirkt spätestens nach 60 s. Die Antworten enthalten zusätzlich trialExpiryTime (Snapshot des Testablaufs, ISO-8601-Zeichenkette; null, wenn die Lizenz nicht aus einer Testphase hervorging). Clients können dies als Kulanzfenster nutzen: Hat der Nutzer die Vollversion getestet und kauft danach eine niedrigere Edition, bleiben die Funktionen der höheren Edition bis trialExpiryTime freigeschaltet. Die Antworten enthalten zusätzlich trialExpiryTime (Snapshot des Testablaufs, ISO-8601-Zeichenkette; null, wenn die Lizenz nicht aus einer Testphase hervorging). Clients können dies als Kulanzfenster nutzen: Hat der Nutzer die Vollversion getestet und kauft danach eine niedrigere Edition, bleiben die Funktionen der höheren Edition bis trialExpiryTime freigeschaltet. Die Antworten enthalten zusätzlich trialExpiryTime (Snapshot des Testablaufs, ISO-8601-Zeichenkette; null, wenn die Lizenz nicht aus einer Testphase hervorging). Clients können dies als Kulanzfenster nutzen: Hat der Nutzer die Vollversion getestet und kauft danach eine niedrigere Edition, bleiben die Funktionen der höheren Edition bis trialExpiryTime freigeschaltet. Die Antworten enthalten zusätzlich trialExpiryTime (Snapshot des Testablaufs, ISO-8601-Zeichenkette; null, wenn die Lizenz nicht aus einer Testphase hervorging). Clients können dies als Kulanzfenster nutzen: Hat der Nutzer die Vollversion getestet und kauft danach eine niedrigere Edition, bleiben die Funktionen der höheren Edition bis trialExpiryTime freigeschaltet.

Das Dual-Environment-Debugging ist für beide Szenarien vollständig transparent:

  • Szenario A: Auf Debug-Maschinen laufen claimTrial / Zahlungen über die Plattform-Kaufseite automatisch über die Test-Environment (siehe Kapitel 4)
  • Szenario B: Ruft eine Debug-Maschine generateForSoftware auf, routet die Plattform ebenfalls anhand des Maschinen-Codes in die Test-Environment und gibt Lizenzcodes mit T--Präfix zurück; der Server-Code benötigt keinerlei Änderungen
  • Die SDK-Aufrufe sind während des Debuggings und nach dem Release völlig identisch — keine Umgebungsparameter oder Code-Verzweigungen nötig; das Umgebungs-Routing erfolgt automatisch durch den Plattform-Server

3. Details der Lizenz-Integration (für beide Szenarien gültig)

3.1 Spezifikation für lokale Zugangsdaten-Speicherung

Das SDK übernimmt selbst keine Persistenz — dies implementiert der Entwickler selbst. Gespeicherte Inhalte:

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

Prinzipien:

  • Nur licenseCode + activationToken + letztes verify-Ergebnis speichern
  • Keine vollständigen, entschlüsselbaren Lizenzinformationen speichern (Reverse-Engineering-Schutz ist sinnlos; dient nur als Cache)
  • Der 60s-Cache von verifyCached liegt im SDK-Prozess, verfällt nach Neustart und erfordert einen erneuten verify-Aufruf

3.2 Ebenen-Vergleich der Editionen (edition)

Entwickler definieren Edition-Codes selbst (z. B. BASIC / PRO / ULTIMATE) und konfigurieren sie auf der Veröffentlichungsseite der Plattform. Alle Produkttypen (Client/Server/Nur-Promotion) können nach Aktivierung von Lizenzcodes ihre Editionen frei anpassen. Der Client prüft per Ebenen-Vergleich:

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)

Übliche Zuordnung (Referenz):

Funktionsstufe Edition-Code Ebene Typische Funktionen
Basis BASIC 0 Grundlegende Bildbearbeitung, Formatkonvertierung
Pro PRO 1 Stapelverarbeitung, HD-Vergrößerung
Ultimate ULTIMATE 2 KI-Restauration, Cover-Assistent

Editions-Namen und -Codes werden vom Entwickler auf der Plattform frei definiert — BASIC/PRO/ULTIMATE sind keine Pflicht. Editionspreise und Funktionslisten werden nur auf der Kaufseite angezeigt, wenn „Plattform zieht Lizenzgebühren ein" aktiviert ist.

3.3 Fehlercode-Behandlung (LicenseError)

Das SDK wirft LicenseError mit der Eigenschaft 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("Die Lizenz wurde widerrufen, bitte kontaktieren Sie den Support")
    elif e.error_code == "machineLimit":
        show_message("Maschinen-Bindungslimit erreicht, bitte altes Gerät im Nutzercenter entbinden")
    elif e.error_code == "NETWORK_ERROR":
        show_message("Netzwerkfehler, bitte prüfen Sie die Verbindung und versuchen Sie es erneut")
    else:
        show_message(f"Prüfung fehlgeschlagen: {e}")
Fehlercode Bedeutung Empfohlene Client-Behandlung
codeNotFound Lizenzcode existiert nicht Eingabe prüfen
revoked Widerrufen Hinweis, den Support zu kontaktieren
expired Abgelaufen Zum Kauf/zur Verlängerung leiten
machineLimit Maschinen-Bindungslimit erreicht Zur Entbindung im Nutzercenter leiten
tooManyAttempts Ratenbegrenzung ausgelöst Hinweis, später erneut zu versuchen
trialNotEnabled Produkt hat Testphase nicht aktiviert Plattform-Konfiguration prüfen
trialAlreadyPurchased Produkt bereits gekauft Hinweis „bereits gekauft“ anzeigen und zur Kaufseite führen
trialAlreadyPurchased Produkt bereits gekauft Hinweis „bereits gekauft“ anzeigen und zur Kaufseite führen
trialAlreadyPurchased Produkt bereits gekauft Hinweis „bereits gekauft“ anzeigen und zur Kaufseite führen
trialAlreadyPurchased Produkt bereits gekauft Hinweis „bereits gekauft“ anzeigen und zur Kaufseite führen
NETWORK_ERROR Netzwerk/Timeout Offline-Kulanz oder Wiederholungs-Hinweis

3.4 Weiterleitung zur Kaufseite (nur Szenario A)

3.4.1 Kaufseiten-URL

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

SDK-Methode:

url = client.purchase_url(mc)

Wenn eine Debug-Maschine diese Seite aufruft, erscheint oben das Abzeichen „Debug-Modus (Testumgebung)"; die Zahlung läuft über den Testkanal (siehe Kapitel 4). Die Sprache wird von der Kaufseite anhand des Nutzer-Browsers automatisch erkannt (URL-Präfix / Accept-Language) — das SDK muss sich nicht darum kümmern.

3.4.2 Seiten: einheitlich die internationale Seite .app, Entwickler müssen keine Kaufseite wählen

powersoftware.app (international) powersoftware.cn (China)
Zahlungsmethoden Waffo (Karte / Apple Pay / Google Pay usw.) + PayPal + Alipay Nur Alipay
Land/Währung Cloudflare erkennt automatisch per IP (CN→CNY, übrige→USD) Fest country=CN, CNY
Sprache Automatisch per URL-Präfix / Accept-Language Fest zh-CN
Positionierung Einziger Kauf-Einstieg, den Entwickler verwenden müssen Auffangseite für Alipay-Zahlungen der internationalen Seite

Entwickler müssen keine Kaufseite wählen: purchaseUrl zeigt einheitlich auf die internationale Seite .app. Überseeische Nutzer schließen Waffo-/PayPal-Zahlungen direkt auf .app ab; wählen chinesische Nutzer auf .app Alipay, leitet die Plattform automatisch auf die chinesische Seite .cn zur Alipay-Zahlung weiter (Login-Status wird automatisch synchronisiert, kein erneuter Login nötig) und kehrt nach erfolgreicher Zahlung in den Lizenzablauf zurück. Die gesamte Kette ist für Nutzer und Entwickler transparent.

# Richtig: fest die internationale Seite verwenden, base nicht nach Region/Sprache wechseln
url = client.purchase_url(mc)

# Nicht empfohlen: Region selbst prüfen und .cn base übergeben — die Alipay-Weiterleitung
# übernimmt bereits die Plattform, und hartkodiertes .cn verliert Waffo-/PayPal-Zahlungsmethoden

4. Debugging-Phase (Dual-Environment, neu in v4)

Die zuverlässigste Abnahme vor dem Release: Den eigenen, täglich für die Entwicklung genutzten Rechner als „Debug-Gerät" registrieren und den vollständigen Ablauf über die echte Zahlungspipeline durchlaufen.

4.1 Maschinen-Code registrieren

  1. Nutzercenter → „Meine Maschinen-Codes" → Maschinen-Code des Debug-Rechners registrieren
    • Der Maschinen-Code kann mit machine_code() des SDK erzeugt werden (gleiche Maschine, drei Sprachen, gleiches Ergebnis)
  2. Diesen Maschinen-Code notieren

4.2 Debug-Gerät registrieren

  1. Developer Center → Produktliste → Schaltfläche „Debug-Geräte" des Zielprodukts
  2. Im Dialog aus den registrierten Maschinen-Codes auswählen und zum Produkt hinzufügen (Notiz möglich)
  3. Limit: maximal 3 Debug-Geräte pro Produkt; Schalter (Routing temporär deaktivieren) und Entfernen werden unterstützt

4.3 Was auf der Debug-Maschine passiert

Auf einer registrierten und aktivierten Debug-Maschine wechselt die gesamte Pipeline dieses Produkts automatisch in die Waffo Test Environment:

Debug-Maschine (Ihr Rechner)   PowerSoftware.net Plattform (Server ermittelt Umgebung automatisch)
    │                  │
    │ claimTrial(machineCode)
    ├─────────────────→│ Diese Maschine ist Debug-Maschine dieses Produkts → Test-Pfad
    │                  │
    │ ← Testlizenz (Lizenzcode mit T- Präfix, wird in Test-Lizenz-Tabelle geschrieben)
    │                  │
    │ purchaseUrl(machineCode)
    ├─────────────────→│ Kaufseite zeigt Abzeichen „Debug-Modus (Testumgebung)"
    │                  │ → Zahlung mit Waffo-Test-Karte (kein echtes Geld)
    │                  │ → Bestellung in Test-Bestell-Tabelle, Plattform stellt Test-Code aus (T- Code)
    │ ← Plattform stellt Code aus (T- Code)
    │                  │
    │ activate(T-Code, machineCode)
    ├─────────────────→│ T- Präfix führt direkt zur Test-Tabelle
    │ ← activationToken│
    │                  │
    │ verifyCached(...)
    ├─────────────────→│ Prüfung bestanden
    │ ← { valid, edition, expiryTime }

Kernpunkte:

  • Erkennung: Lizenzcode mit T--Präfix ist eine Test-Lizenz; oben auf der Kaufseite erscheint das Abzeichen „Debug-Modus (Testumgebung)"
  • Zahlung: läuft über den Waffo-Test-Checkout mit Testkarten (z. B. 4576 ... 0110); es erfolgt keine echte Abbuchung
  • Null Code-Änderungen: Der Client benötigt keinerlei Änderungen — derselbe Code verhält sich auf Debug-Maschine und echten Nutzerrechnern identisch (nur die Backend-Tabellen unterscheiden sich)

4.4 Empfohlene Debugging-Checkliste

  • Erster Start der Debug-Maschine → claimTrial erfolgreich, Testcode mit T--Präfix erhalten
  • Innerhalb der Testphase gibt verifyCached valid zurück, Bezahl-Funktionen werden freigegeben
  • purchaseUrl öffnet die Kaufseite, Abzeichen „Debug-Modus" erscheint
  • Zahlung mit Testkarte abgeschlossen → Test-Lizenzcode erhalten (E-Mail/Seite)
  • activate erfolgreich → verifyCached bestanden
  • Editions-Sperre korrekt (niedriger Code wird bei höherer Funktion blockiert)
  • Maschinen-Bindungslimit (machineLimit) und Entbindungspfad funktionieren
  • (nur Szenario B) generateForSoftware auf der Debug-Maschine gibt Lizenzcode mit T--Präfix zurück, Aktivierung/Prüfung normal; derselbe Aufruf mit nicht registrierter Maschine gibt regulären Code zurück
  • Auf einem nicht registrierten Rechner claimTrial wiederholen und bestätigen, dass die Produktions-Pipeline genutzt wird (Kontrollprüfung)

4.5 Debugging-Hinweise

Thema Beschreibung
Testdaten bereinigen Test-Lizenzen/-Bestellungen beeinflussen die Produktion nicht, keine Bereinigung nötig; zum Zurücksetzen Gerät im Debug-Geräte-Panel entfernen und erneut hinzufügen
Debug-Schalter Wer temporär nicht über die Test-Pipeline gehen möchte, schaltet den Schalter im Debug-Geräte-Panel aus — Gerät muss nicht gelöscht werden
Nur-Promotion-Produkte Produkte vom Typ „Nur-Promotion" werden nicht in den Waffo-Produktkatalog synchronisiert; keine Debug-Kauf-Pipeline
Kein gültiger Preis Haben Haupt-/Sekundärpreis und alle Lizenz-Editionen keinen regulären Preis, schlägt die Test-Produktsynchronisation fehl (DingTalk-Alarm) — bitte mindestens einen Editions-Preis konfigurieren

5. Release-Phase

5.1 Review einreichen

  1. Nachdem alle Punkte der Debugging-Checkliste bestanden sind, im Produktformular „Speichern & Review einreichen" klicken
  2. Das Produkt gelangt in die Review-Warteschlange (PENDING_RELEASE)

Für Produkte, die während der Debug-Phase als Entwurf gespeichert wurden, entspricht der eingereichte Inhalt dem neuesten Entwurf; erneutes Bearbeiten während des Reviews setzt den Status automatisch auf Entwurf zurück (verhindert Inhaltsänderungen während des Reviews) — erneutes Einreichen erforderlich.

5.2 Review bestanden → automatische Produktions-Synchronisation

Nach Freigabe durch den Plattform-Betrieb:

  1. Produktstatus wechselt zu veröffentlicht und gelistet
  2. Die Plattform synchronisiert das Produkt automatisch in die Waffo-Produktionsumgebung (schreibt waffo_product_id zurück), erstellt/stellt Produktions-Checkout-Produkte wieder her
  3. Produktdetailseite und Suchergebnisse sind für alle Nutzer sichtbar

5.3 Echte Nutzer-Pipeline (Produktion)

Die Pipeline für echte Nutzer (Nicht-Debug-Maschinen) ist mit dem Debugging völlig identisch — sie liegt nur vollständig in den Produktions-Tabellen:

Erster Start → claimTrial Testlizenz beziehen (regulärer Lizenzcode, ohne T- Präfix)
        → Testphase abgelaufen → purchaseUrl zur Kaufseite (Alipay / PayPal echte Zahlung)
        → Plattform stellt nach erfolgreicher Zahlung automatisch Code aus + E-Mail-Zustellung
        → activate aktivieren → verifyCached Prüfung Freigabe

Nutzer in Szenario B (Selbstinkasso) nutzen nicht die Plattform-Kaufseite: Nachdem der Nutzer über Ihren Kanal gezahlt hat, ruft Ihr Server generateForSoftware auf und stellt einen regulären Lizenzcode aus; die anschließende Aktivierungs-/Prüfungspipeline ist identisch mit Szenario A.

5.4 Release-Verifikations-Checkliste

  • Mit einem nicht als Debug-Maschine registrierten Rechner die Produktdetailseite aufrufen und normale Anzeige bestätigen
  • Auf der Kaufseite erscheint kein Abzeichen „Debug-Modus"
  • Echte Kleinstzahlung → Code-Ausstellung → Aktivierung erfolgreich
  • Die Bestellung ist in der Bestellliste des Developer Centers sichtbar (Test-Bestellungen erscheinen dort nicht)

6. Betrieb nach dem Release

Aktion Einstieg Beschreibung
Bestellungen ansehen Developer Center → Meine Bestellungen Nur Produktions-Bestellungen; Test-Bestellungen nehmen nicht an Umsatzbeteiligung und Abrechnung teil
Nutzer-Entbindung Nutzercenter des Nutzers / manuelle Lizenz durch Entwickler Umbindungs-Kontingent: nach Entbindung 30 Tage keine erneute Entbindung möglich
Versions-Iteration Produkt bearbeiten → Entwurf speichern / Review einreichen Bearbeitung synchronisiert erneut asynchron in Waffo Test; neue Versionen können weiter mit der Debug-Maschine geprüft werden
Erstattung Waffo Dashboard Käufer eröffnet Ticket, Händler prüft im Dashboard; Erstattungen von Test-Bestellungen widerrufen nur die Test-Lizenz
Debugging offline nehmen Gerät im Debug-Geräte-Panel entfernen Empfohlen, die Debug-Maschine nach Stabilisierung der Version zu entfernen, um versehentliche Nutzung der Test-Pipeline zu vermeiden

7. Häufige Fragen (FAQ)

F1: Muss ich während des Debuggings Client-Code oder Konfiguration ändern? Nein. Das Umgebungs-Routing ermittelt der Plattform-Server automatisch anhand der Frage, ob der Maschinen-Code in der Debug-Geräte-Liste steht; die SDK-Aufrufe sind völlig identisch.

F2: Kann ich den auf der Debug-Maschine erhaltenen Lizenzcode echten Nutzern geben? Nein, und es ist auch nicht empfehlenswert. T--Codes sind nur in den Test-Tabellen gültig, und Debug-Daten nehmen an keinerlei Produktionslogik teil; Test-Codes an echte Nutzer auszugeben führt dazu, dass diese über den regulären Prüfungspfad keinen Support erhalten können.

F3: Kostet das Debugging Geld? Nein. Der Test-Zahlungskanal nutzt Testkarten; es erfolgt keine echte Abbuchung; Test-Bestellungen nehmen nicht an Umsatzbeteiligung/Abrechnung teil.

F4: Beeinflusst das Debugging das Review meines Produkts? Nein. Debug-Daten sind vom Review vollständig entkoppelt; bereits im Entwurfsstatus kann debuggt werden, ob eingereicht wird entscheiden Sie.

F5: Was, wenn ich auf mehreren Rechnern debuggen möchte? Pro Produkt sind maximal 3 Debug-Geräte registrierbar; im Debug-Geräte-Panel hinzufügen/entfernen genügt.

F6: Kann ich Käufe debuggen, wenn der Produkttyp „Nur-Promotion" ist oder kein Preis konfiguriert wurde? Nein. Nur-Promotion-Produkte werden nicht in den Waffo-Produktkatalog synchronisiert; ohne gültigen Preis schlägt die Test-Produktsynchronisation fehl. Bei solchen Produkten können nur Testphase und Prüfungs-Pipeline debuggt werden.

F7: Was passiert, wenn ich den Debug-Schalter vergesse und veröffentliche? Der Einfluss beschränkt sich auf den von Ihnen registrierten Rechner — er läuft weiter über die Test-Pipeline; alle echten Nutzer sind nicht betroffen. Nach bestätigter Stabilität einfach im Debug-Geräte-Panel entfernen.

8. Integrations-Checkliste (vor Release Punkt für Punkt prüfen)

Szenario A (vollständige Plattform-Pipeline)

  • Produkt auf PowerSoftware.net veröffentlichen, Verkaufsmodell „Try-Before-You-Buy" wählen
  • Testtage konfigurieren (empfohlen 7~14 Tage)
  • Lizenz-Editionen konfigurieren (Edition-Code + Name + Preis + Funktionsliste)
  • Bestätigen, dass „Plattform zieht Lizenzgebühren ein" aktiviert ist (bei Try-Before-You-Buy Pflicht)
  • productUniqueCode notieren
  • SDK-Quellcode ins Projekt kopieren (siehe 2.3.1)
  • claimTrial implementieren → Testlizenz beim ersten Start beziehen
  • activate implementieren → Aktivierung, wenn der Nutzer den Lizenzcode eingibt
  • verifyCached implementieren → Prüfung bei Klick auf Bezahl-Funktionen
  • purchaseUrl implementieren → ohne Lizenz zur Kaufseite weiterleiten (einheitlich internationale Seite .app, keine Seitenwahl nötig)
  • Lokale Persistenz der Zugangsdaten implementieren (licenseCode + activationToken)
  • Ebenen-Vergleichslogik der Editionen implementieren (siehe 3.2)
  • LicenseError-Fehlercode-Behandlung implementieren (siehe 3.3)
  • Debug-Maschine registrieren und Dual-Environment-Debugging-Checkliste durchlaufen (siehe 4.4)
  • Review einreichen → Review bestanden → Release-Verifikation (siehe 5.4)

Szenario B (Bestellungen außerhalb der Plattform)

  • Produkt auf PowerSoftware.net veröffentlichen, licenseEnabled aktivieren
  • Lizenz-Editionen konfigurieren (Edition-Code + Name); falls Plattform-Inkasso gewünscht, „Plattform zieht Lizenzgebühren ein" aktivieren und Preise eintragen
  • licenseApiSecret im Developer-Backend beziehen
  • productUniqueCode notieren
  • Server aufbauen, der das Lizenz-Geheimnis licenseApiSecret verwahrt und die Ausstellungs-Schnittstelle implementiert (Schlüssel darf nicht an den Client ausgeliefert werden)
  • Clientseitig SDK-Quellcode ins Projekt kopieren
  • Serverseitig generateForSoftware implementieren (Code-Ausstellung)
  • Serverseitig upgradeForSoftware implementieren (Upgrade/Verlängerung)
  • Clientseitig activate / verifyCached implementieren
  • Lokale Persistenz der Zugangsdaten implementieren
  • Ebenen-Vergleichslogik der Editionen implementieren (siehe 3.2)
  • LicenseError-Fehlercode-Behandlung implementieren (siehe 3.3)
  • Debug-Maschine registrieren und T--Code-Pipeline verifizieren (siehe 4.4)
  • Review einreichen → Review bestanden → Release-Verifikation (siehe 5.4)

Anhang: SDK-Repository (GitHub)

github.com/mizhanchengxi/powersoftware-license-sdk
├── node/      SDK-Quellcode (ESM, ohne Abhängigkeiten, eine Datei)
├── python/    SDK-Quellcode (py3, ohne Abhängigkeiten, 3 Dateien)
├── java/      SDK-Quellcode (Java 8+, ohne Abhängigkeiten, 3 Dateien)
└── docs/      SDK-Spezifikationsdokumente

Alle drei Pakete bieten: machineCode() / sign() / LicenseClient (einschließlich activate / verify / deactivate / claimTrial / generateForSoftware / upgradeForSoftware / verifyCached / purchaseUrl).

Dieses Dokument ist die v4-Aktualisierung des Client-Software-Lizenz-Integrationsleitfadens (CLIENT_SOFTWARE_GUIDE), deckt dessen gesamten Inhalt ab und ergänzt das Dual-Environment-Debugging sowie die Entwurfs-/Review-Einreichungs-Fähigkeiten.