Zum Inhalt springen

Signieren und der Weg in den Katalog

Was an einem Release liegt, sha256 und Ed25519-Signatur, die Politik am Gerät, Kanäle canary → beta → stable — und wer heute Releases anlegt.

16 Minuten LesezeitApps-SDKStand: 25.10.2026

Auf dieser Seite

Bevor Sie loslegen

Für wen
Entwickler, die wissen wollen, was mit ihrer App zwischen Bau und Bildschirm geschieht, und Betreiber, die Releases führen.
Voraussetzung
zum Lesen keine; die Aufrufe unter /v1/platform/app-catalog/… und die Befehle app-release … verlangen einen Betreiber-Ausweis mit den Rechten platform.app-catalog.list, import, promote, retire oder update.

Ein Release friert Version, Manifest und Bytes einer App ein und wandert durch die Kanäle bis stable. Diese Seite nennt, was an einem Release liegt, wie eine Fassung als signiertes Artefakt in den Katalog kommt, die Regeln der Kanäle und die Aufrufe und Befehle, mit denen der Plattformbetrieb den Katalog führt.

Jede Fassung entsteht genau einmal: Die CI baut sie aus ihrem Tag als signiertes, unveränderliches Artefakt <appId>-<version>.szapp mit Manifest, den Bündeln für Anzeige und Editor, Bildern und Texten für den Store und den Release-Notizen, und jede Umgebung holt dieses eine Artefakt aus der Registry. Dieselbe Fassung trägt damit in jeder Umgebung dieselben Bytes.

Was an einem Release liegt

Im Objektspeicher liegt eine Fassung unter platform/apps/<appId>/<version>/:

Ablage Inhalt
bundle.zip Das Artefakt unverändert. Seine sha256 ist der Digest seiner Schicht in der Registry.
manifest.json Das Manifest der Fassung in kanonischem JSON — der Katalog speichert es eingebettet, sein Hash ist der manifestHash.
runtime/ Die entpackten Dateien des runtime-Bündels, das der Player lädt.
authoring/ Das entpackte authoring-Bündel mit dem Konfigurationsformular für den Szenen-Editor, falls die App eines trägt.
store/ Symbol und Aufnahmen für den Store.

Am Release stehen dazu sizeBytes und sha256 (64 hexadezimale Zeichen in Kleinschreibung) der abgelegten Bytes und die Herkunft: source (registry für ein Artefakt aus der Registry, seed-placeholder für eine Zeile ohne Bytes, die der Seed ohne Zugang zur Registry angelegt hat), unter artifact der Hash des Index, der Release-Schlüssel, dessen Signatur geprüft ist, die Signatur selbst und der Digest in der Registry, dazu importedAt und importedById. Manifest und Bytes sind nach dem Holen unveränderlich; das einzige nachträglich änderbare Feld sind die Notizen. Sie stehen unter notes je Zielgruppe — customer („Neu in dieser Fassung“), operator und developer — und je Sprache (de-DE, en-US, …), wie der Index des Artefakts sie mitbringt. Daneben trägt jedes Release weiter die eine Notiz von früher, releaseNotes (max. 2000 Zeichen): den Text für den Betrieb in de-DE, sonst den für Kunden.

Geräte und Clients erreichen eine Fassung über vier Routen. Manifest und Bündel verlangen das Zertifikat eines Geräts oder eine Sitzung, anmeldefrei ist allein die entpackte Laufzeit. Die Spezifikation führt dieselben Ausweise unter security, mit den Namen aus der Spalte Ausweis:

Route Ausweis Antwort
GET /v1/apps/{appId}/{version}/manifest.json deviceCertificate oder sessionJwt Das gespeicherte Manifest; sein Hash ist der ETag. Ein passendes If-None-Match ergibt 304.
GET /v1/apps/{appId}/{version}/bundle.zip deviceCertificate oder sessionJwt Eine Weiterleitung auf eine Presigned-URL — die Bytes laufen nicht durch die API. Bei einer Fassung aus der Registry ist es das Artefakt.
GET /v1/apps/{appId}/{version}/runtime/{pfad} keiner Eine Datei des entpackten runtime-Bündels, unveränderlich und ein Jahr zwischenspeicherbar. Darüber importiert ein Display ohne Agent die Einstiegsdatei index.js und die Teile, die sie relativ nachlädt (./chunks/…). Ein Platzhalter ohne Bytes geht mit no-cache hinaus, er bekommt seine Bytes erst noch. Eine unbekannte Fassung oder Datei ergibt 404.
GET /v1/apps/{appId}/{version}/authoring/index.mjs sessionJwt, apiKey oder oauthAccessToken Eine Weiterleitung auf eine Presigned-URL, bei einer Fassung aus der Registry auf das entpackte authoring/index.js; deklariert die App kein authoring-Bündel, antwortet die Route mit 404. Der Szenen-Editor des Portals lädt das Bündel angemeldet.

Die beiden Kataloge über alle Apps

Neben der einzelnen Fassung liefert die Schnittstelle zwei Übersichten über den ganzen Katalog. Beide nehmen je App die geltende Fassung im Kanal stable — die mit dem jüngsten Eintritt dorthin, nicht die höchste Nummer — und zerlegen deren Manifest: die eine in Widget-Definitionen, die andere in Ressourcentypen. Der Widget-Katalog führt zusätzlich die sechs eingebauten Bausteine (Text, Bild, Video, Form, Grafik, Dokument); sie gehören zu keiner App und tragen deshalb die reservierte Kennung core. Was nur in canary oder beta steht, kommt in keiner von beiden vor, und beide antworten unabhängig davon, was eine Organisation installiert hat: Sie beschreiben das Angebot, nicht den Bestand.

Route Was die Antwort enthält
GET /v1/widget-catalog Unter entries je Widget ein Eintrag mit appId, version und der vollständigen definition: id, name, description, das configSchema als JSON-Schema mit Feldtexten und Beispielen (siehe Widgets konfigurieren), size, noResolver und der preview-Block mit defaultConfig, mockData, thumbnailUrl, variants und states. Die beiden Tor-Apps ohne Widget tragen nichts bei; die sechs eingebauten Bausteine stehen unter appId: core mit darin.
GET /v1/resource-type-catalog Unter entries je Ressourcentyp ein Eintrag mit appId, version und der definition: id, slug, name, description, listEndpoint, authoringPath und die drei Schemata baseSchema, createSchema und updateSchema. Nur Apps mit resources im Manifest tragen etwas bei — unter den mitgelieferten sind das calendar, menu-board und pharmacies-on-duty.

Beide verlangen einen Ausweis, aber kein eigenes Recht: Eine gültige Anmeldung genügt, und ein API-Schlüssel erreicht sie unabhängig davon, welche Rechte in seinem scope stehen.

curl -sS "$SZENERA_API/v1/widget-catalog" \
  -H "Authorization: Bearer $SZENERA_API_KEY"

Beide Antworten sind flach: eine Liste, in der ein Eintrag die Definition trägt und daneben sagt, aus welcher Fassung welcher App sie stammt.

{
  "entries": [
    {
      "appId": "pharmacies-on-duty",
      "version": "2.0.1",
      "definition": { "id": "pharmacies-on-duty-display", "name": "Notdienst-Anzeige", "…": "…" }
    }
  ]
}

Signatur: die Aussage über die Fassung

Signiert wird in der CI, nie auf einem Server: Die CI unterschreibt die Aussage „diese App, diese Fassung, dieses Manifest, dieser Index“ mit dem Ed25519-Release-Schlüssel jeder Welt (app-release-staging für Entwicklung und Staging, app-release-prod für Produktion). Beim Holen prüft die Schnittstelle die Signatur ihrer eigenen Welt gegen deren öffentlichen Schlüssel. Ohne gültige Signatur ihrer Welt kommt keine Fassung in den Katalog, einen Rückfall auf die sha256 allein gibt es nicht. Wer ein Release holt, signiert nichts.

Am Gerät prüft die Fernwartung jedes Artefakt, bevor sie etwas entpackt: Der sha256-Wert des geladenen Archivs muss dem am Release entsprechen, dann prüft sie die signierte Aussage gegen den Anker app-release-<welt> im Abbild, danach Manifest und jede Datei gegen den Index, und sie entpackt nur runtime/, abgesichert gegen Pfade, die aus dem Zielordner hinausführen. Fehlt der Anker, lehnt sie jedes Artefakt ab. Ein Archiv ohne Index ist kein Artefakt, und die Fernwartung nimmt es nicht an. Die Angabe signing im Manifest ändert daran nichts, sie bleibt nur, weil sie in den Manifesten veröffentlichter Fassungen steht.

Ein Release holen

Ein Release entsteht durch den Import eines Artefakts aus der Registry. Die CI meldet jede Fassung, die sie abgelegt hat, Staging und Produktion. Die Fassungen der Registry listet die Schnittstelle nicht auf: Wer eine Fassung von Hand holt, nennt ihre Version selbst.

POST /v1/platform/app-catalog/imports mit dem Rumpf { "appId": "…", "version": "…" } holt die Fassung. Optional nennt digest den Digest des OCI-Manifests (sha256:…), den der Aufrufer erwartet; die CI schickt ihn immer mit. Die Schnittstelle prüft Manifest und Schicht in der Registry, dann das Archiv: jede Datei gegen ihre Prüfsumme im Index, das Manifest gegen das Schema und seinen Hash, Kennung und Fassung, und die Signatur ihrer Welt. Erst danach legt sie die Bytes ab und das Release im Kanal canary an.

curl -X POST "$SZENERA_API/v1/platform/app-catalog/imports" \
  -H "Authorization: Bearer $SZENERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "appId": "pharmacies-on-duty", "version": "1.3.0" }'

Die Antwort ist { "release": …, "created": true } mit 201, wenn die Fassung neu im Katalog steht. Lag sie dort schon mit demselben Artefakt, antwortet der Aufruf mit 200 und created: false, der Aufruf lässt sich also wiederholen. Einen Platzhalter ohne Bytes mit demselben Manifest füllt der Import, Kanal und Freigaben der Zeile bleiben. Die Notiz des Seeds, die nur den Platzhalter beschreibt, ersetzt er dabei durch die Notizen aus dem Index, außer jemand hat sie geändert.

Dabei zieht der Import die Notizen nach: Fehlt einer Fassung, die er schon im Katalog antrifft, eine Zielgruppe oder Sprache, die der Index ihres Artefakts trägt, ergänzt er sie und hält das als notes-updated mit seinem Akteur fest. So bekommt eine Fassung, die vor den Notizen je Zielgruppe in den Katalog kam, die Texte für Kunden und Entwickler. Vorhandene Texte bleiben, und Notizen, die schon einmal geändert wurden, fasst der Import nicht an. Den Index einer Fassung im Katalog liest die Schnittstelle aus ihrem eigenen Objektspeicher, in der Registry muss die Fassung dafür nicht mehr liegen.

Was beim Holen scheitern kann, nennt den genauen Grund in details.reason:

Code HTTP Auslöser
AppRelease.RegistryArtifactNotFound 404 Unter der Fassung liegt in der Registry kein Tag.
AppRelease.VersionAlreadyExists 409 Die Fassung steht hier schon mit einem anderen Artefakt oder als Platzhalter mit anderem Manifest. Eine Fassung bekommt keine zweiten Bytes.
AppRelease.RegistryImportFailed 422 Das Artefakt hat die Prüfung nicht bestanden: Digest, Typ oder Angaben des Manifests in der Registry, Prüfsummen, Aufbau des Archivs, das Manifest der App oder die Signatur der Welt. Auch eine Umgebung, der der öffentliche Schlüssel ihrer Welt fehlt, antwortet so.
AppRelease.RegistryUnavailable 503 Der Umgebung fehlt der Zugang zur Registry, oder die Registry antwortet nicht.

Die Kanäle

Ein neues Release startet immer in canary; den Startkanal wählt niemand. Jeder Aufstieg geht genau eine Stufe weiter, ein Sprung ist nicht möglich. Nach stable hebt keine Person allein: Eine Person fordert an, eine zweite bestätigt, auch bei der Rücknahme. Welche Fassung in stable gilt, entscheidet der jüngste Eintritt dorthin, nicht die höchste Nummer.

Kanal Beschriftung im Betreiber-Portal Bedeutung
canary Canary Frisch geholt — erster Erprobungs-Kanal.
beta Beta Erweiterte Erprobung.
stable Stabil Die für Organisationen empfohlene Fassung.
deprecated Veraltet Zurückgestuft, aber noch nutzbar.
retired Ausgemustert Außer Betrieb; Endzustand mit Auslauffrist.
Aufruf Rumpf Regel
POST …/releases/{id}/promote { "toChannel": "beta" }, nach stable mit "reason": "…" canary → beta hebt immer sofort. Nach stable hebt der Aufruf sofort, wenn die Plattform keine zweite Person verlangt (releaseApproval.apps auf off, die Vorgabe). Verlangt sie eine (stable), legt der Aufruf mit reason (10–500 Zeichen) eine Anfrage an, Antwort { "approval": … } statt { "release": … }, ohne reason antwortet er AppRelease.SecondPersonRequired (HTTP 409). Je Fassung und Vorgang wartet höchstens eine Anfrage (ReleaseApproval.AlreadyOpen, HTTP 409), und sie gilt sieben Tage. Alles andere: Channel.InvalidTransition (HTTP 409).
POST …/releases/{id}/restore { "reason": "…" }, Pflicht (10–500 Zeichen) Nimmt eine Fassung aus deprecated oder eine abgelöste in stable dorthin zurück, sofort oder, wenn die Plattform eine zweite Person verlangt, als Anfrage (Antwort wie bei promote). Bei der Rücknahme gilt die Fassung danach wieder, auch vor einer höheren, und die bis dahin geltende geht nach deprecated.
POST /v1/platform/ops/approvals/{id}/approve — Eine andere Person (Recht platform.ops.release.approve) bestätigt und führt den Vorgang in derselben Transaktion aus, Antwort { "approval": … }. Die anfragende Person selbst: ReleaseApproval.SamePerson (HTTP 403). Verfallen, bestätigt oder zurückgezogen: ReleaseApproval.NotOpen (HTTP 409, details.state). Dieselbe Route bestätigt auch die Anfragen der Gerätesoftware.
POST /v1/platform/ops/approvals/{id}/withdraw { "reason": "…" }, der Grund ist freiwillig Die anfragende Person zieht zurück, jede andere mit dem Recht zum Bestätigen lehnt damit ab. Die Fassung bleibt in ihrem Kanal.
GET /v1/platform/ops/approvals Abfrage state, packageKind, package Die Anfragen beider Familien (Apps und Gerätesoftware), ohne state die offenen, neueste zuerst. Für Apps packageKind=app&package=<appId>.
DELETE …/releases/{id}/artifact — Löscht die Bytes der Fassung (Recht platform.app-catalog.delete), Zeile, Manifest und Historie bleiben. Geschützt ist eine Fassung in canary, beta oder stable, mit Installation, Szenen-Pin oder offener Anfrage (AppRelease.ArtifactInUse, HTTP 409). Ein zweiter Aufruf ist wirkungslos.
POST …/apps/{appId}/releases/cleanup { "keepNewest": 5, "dryRun": true } Räumt die Bytes aller Fassungen der App jenseits der neuesten keepNewest auf, die sich löschen lassen. Ohne keepNewest gilt retention.apps.keepNewest der Plattform, mit dryRun löscht der Aufruf nichts und nennt, was er löschen würde.
POST …/releases/{id}/demote { "toChannel": "deprecated" } Der einzige Rückwärtsschritt: stable → deprecated.
POST …/releases/{id}/retire { "reason": "…", "grace": "regular" }, für eine Lücke { "reason": "…", "grace": "security", "securityAdvisory": "…" } reason ist Pflicht (1–500 Zeichen), grace ist die Wahl der Auslauffrist: regular drei Monate, security einen Monat, immediate keine. securityAdvisory (bis 2000 Zeichen) gehört genau zu security und steht danach an der Fassung. Festgehalten wird die Nachfolgerin, auf die die Plattform nach der Frist umstellt: die niedrigste stabile Fassung über der ausgemusterten. Ein zweites Ausmustern: AppRelease.AlreadyRetired (HTTP 409).
POST …/releases/{id}/extend-grace { "graceMonths": 12 } oder { "graceEndsAt": "2027-03-31T23:59:59.999Z" } Genau eines von beiden. Die Monate zählen ab dem aktuellen Fristende, nicht ab jetzt, ein Datum liegt nach dem aktuellen Ende.
POST …/releases/{id}/force-retire { "reason": "…" } Setzt das Fristende auf jetzt. Der Grund ist Pflicht (1–500 Zeichen) und steht in der Historie.
PATCH …/releases/{id} { "notes": { "customer": { "de-DE": "…", "en-US": "…" } } } oder { "releaseNotes": "…" } Ändert nur die Notizen; eine genannte Zielgruppe wird mit allen Sprachen ersetzt, die übrigen bleiben. releaseNotes setzt den Text für den Betrieb in de-DE. Bei ausgemusterten Releases gesperrt.

Nach beta hochstufen, nach stable hochstufen oder anfragen und eine Anfrage bestätigen verlangt eine Prüfliste ohne Sperre: „Neu in dieser Fassung" (notes.customer['de-DE']) steht, und kein Text für Kunden trägt ein Semikolon oder ein gesperrtes Wort. Sonst antwortet die Schnittstelle AppRelease.ReviewBlocked (HTTP 409) und nennt die sperrenden Punkte in details.blocks. Die Rücknahme und das Ausmustern sperrt die Prüfliste nicht.

Die Frist ist eine Wahl, kein Schlagwort im Grund: Ein Grund, der security enthält, verkürzt nichts. Für neue Installationen ist ein ausgemustertes Release sofort nicht mehr wählbar. Installationen mit genau dieser Fassung bekommen die Nachfolgerin als Ziel: Verlangt sie nichts Neues, übernimmt die Plattform sie sofort, sonst steht die Installation auf Update wartet mit dem Ende der Auslauffrist als Frist. Ist die Frist vorbei, stellt die Plattform Installationen und Szenen auf die Nachfolgerin um, auch ohne Zustimmung, und benachrichtigt die Organisation. Gibt es keine Nachfolgerin, bleibt alles auf der Fassung, und die Historie der Fassung vermerkt es (no-successor). Mit immediate geschieht beides im selben Aufruf. Kommt die Nachfolgerin erst nach dem Ende der Frist nach stable, bekommt die Fassung eine Frist von sieben Tagen (Eintrag grace-extended mit Grund), in der eine zustimmungspflichtige Nachfolgerin auf die Organisation wartet. Danach stellt die Plattform um.

Alle Aufrufe unter /v1/platform/app-catalog/… tragen den Hinweis „Nur Betreiber"; Lesen verlangt platform.app-catalog.list, Holen platform.app-catalog.import (auch mit einem Betreiber-Schlüssel, so meldet die CI), Hochstufen, Anfragen, Rücknahme und Zurückstufen platform.app-catalog.promote (Bestätigen und Ablehnen einer Anfrage platform.ops.release.approve), Löschen und Aufräumen platform.app-catalog.delete, Ausmustern und Fristen platform.app-catalog.retire, Notizen platform.app-catalog.update.

Die Historie einer App

Jede Bewegung eines Release steht als Eintrag in der Historie seiner App: Anlage, Holen aus der Registry, jede Freigabe in einen Kanal, Zurückstufen, Rücknahme, Ausmustern, Auslauffristen, geänderte Notizen und jeder Schritt einer Anforderung an eine zweite Person (promotion-requested, promotion-approved, promotion-withdrawn, promotion-expired). Hat eine zweite Person bestätigt, ist sie der Akteur, und requestedById nennt die Person, die angefordert hat. Jeder Eintrag nennt Kanal von und nach, den Zeitpunkt und den Akteur — einen Menschen im Betrieb (operator mit Kennung), die CI (ci), den Seed einer Umgebung (seed), die Plattform selbst (auto), die Stunde null (zero-hour) oder legacy für das, was vor der Historie geschah und aus den Zeitpunkten der Releases rekonstruiert ist.

Aufruf Für wen Was er liefert
GET /v1/platform/app-catalog/apps/{appId}/history Betrieb (platform.app-catalog.list) jeden Eintrag, neueste zuerst, in Seiten mit limit und cursor
GET /v1/apps/{appId}/history?locale=en-US jede angemeldete Organisation die Fassungen, die stable erreicht haben, jüngste zuerst: Kennung (releaseId, dieselbe wie an Installation, Nachweis und Update-Entscheidung), Nummer, seit wann sie allen offensteht (stableSince), „Neu in dieser Fassung“ in der erbetenen Sprache oder ersatzweise auf Deutsch (note, null ohne Text) und ob sie ausgemustert ist. Für eine App, die der Betrieb für die Organisation abgeschaltet hat, antwortet der Aufruf mit App.NotFound (HTTP 404).

Als Befehl der CLI

Die CLI bildet den Lebenszyklus nach dem Holen in neun Befehlen ab; das Holen selbst kennt sie nicht — die Umgebung gleicht sich alle zehn Minuten mit der Registry ab, die CI beschleunigt es mit dem Aufruf oben. Die Anfragen an eine zweite Person führt die Gruppe approval (list, approve, withdraw).

Befehl Zweck
app-release list Die Releases des App-Katalogs, filterbar mit --app und --channel.
app-release set-notes Release-Notizen ändern.
app-release promote Nach beta oder stable heben mit --channel. Nach stable hebt der Befehl sofort, oder er legt eine Anfrage an eine zweite Person an, wenn die Plattform sie verlangt, --reason ist dann Pflicht.
app-release restore Die Rücknahme einer veralteten oder abgelösten Fassung nach stable, --reason ist Pflicht. Je nach Einstellung sofort oder als Anfrage.
app-release demote Der Weg zurück, wenn ein stabiles Release doch nicht stabil war: --channel=deprecated — der einzige erlaubte Schritt, von stable aus.
app-release retire Ein Release außer Betrieb nehmen; --reason und --grace=regular|security|immediate sind Pflicht, --advisory trägt den Sicherheitsvermerk und gehört genau zu --grace=security.
app-release grace-period Die Auslauffrist verlängern (--months oder --until=<jjjj-mm-tt>) oder sofort beenden (--immediately mit --reason) — genau eines davon.
app-release delete-artifact Die Bytes einer Fassung löschen, --yes ist Pflicht.
app-release cleanup Die Bytes abgelöster Fassungen einer App aufräumen, --dry-run oder --yes, dazu --keep-newest.
szenera-ops --profile=dev-operator app-release promote arl_01K… --app=weather --channel=beta
szenera-ops --profile=dev-operator app-release promote arl_01K… --app=weather --channel=stable --reason="Drei Tage in beta ohne Meldung"
szenera-ops --profile=dev-operator approval approve rap_01K…
szenera-ops --profile=dev-operator app-release retire arl_01K… --app=weather --reason="Nachfolger da" --grace=regular

Alle gehören zum Werkzeug des Plattformbetriebs szenera-ops und verlangen einen Betreiber-Ausweis. Die Befehle mit Release-Stellung verlangen --app; list filtert damit optional. Das Release ist die Stellung id (Kennung arl_…). Das vollständige Register steht unter Befehle für den Plattformbetrieb.

Was die Organisation davon sieht

  • Neue stabile Fassung ohne neue Rechte und ohne geänderte Bedingungen: Bestehende Installationen übernehmen sie automatisch; die früheren Entscheidungen im Reiter Update der App zeigen den Eintrag still übernommen.
  • Neue stabile Fassung mit neuen Rechten oder geänderten Bedingungen: Die Installation steht auf Update wartet; die Widgets der App lassen sich im Szenen-Editor nicht einfügen, bis die Organisation im Reiter Update annimmt (siehe Datenzugriff, Rechte und Bedingungen).
  • Veröffentlichen einer Szene: Hält ein Widget eine Fassung fest, die es nicht gibt, die ausgemustert und deren Auslauffrist vorbei ist, oder gehört es zu einer App, die die Organisation nicht installiert hat, weist die Plattform das Veröffentlichen ab und nennt den Grund in einem Satz. Eine ausgemusterte Fassung in laufender Frist ist ein Hinweis.
  • Ausgemustertes Release: Für neue Installationen nicht mehr wählbar. Wer genau diese Fassung installiert hat, bekommt die Nachfolgerin, die niedrigste stabile Fassung darüber. Verlangt sie nichts Neues und hat die Organisation sie nicht abgelehnt, übernimmt die Plattform sie sofort. Sonst steht die Installation auf Update wartet, mit dem Ende der Auslauffrist als Frist, und danach stellt die Plattform um. Ohne Nachfolgerin läuft die App unverändert bis zum Fristende weiter.

Was es heute nicht gibt

Der Katalog ist rein kuratorisch: Die CI baut und signiert jede Fassung, der Plattformbetrieb holt sie in den Katalog und steuert ihren Lebenszyklus. Es gibt keine Entwickler-Einreichung, keine Prüf-Warteschlange und keine Aussage über Prüfzeiten oder Kriterien. Die 26 mitgelieferten Apps entstehen im Quellbaum der Plattform, werden aus ihrem Tag gebaut, als Artefakt signiert und in jede Umgebung geholt. Wer eine App vorbereitet, tut das mit dem Plattformbetrieb — die Seiten dieses Bereichs beschreiben den Vertrag, gegen den sie geschrieben wird.

Weiterführendes