Files
platform/docs/kiosk-ecosystem.md
T

4.9 KiB

Kiosk — the store, and what it replaces

Decided in conversation on 2026-08-18. Direction, not a work order: none of it is built, and the parts that touch third parties are months out. Recorded so the shape is not re-argued.

The commercial reasoning is BUSINESS-MODEL.md in the officer-oas repository; this file is the technical half.


One brand, two halves

Kiosk is what a person sees. kiosk.officer.dev is the public hub: a searchable catalogue of everything in the Officer ecosystem — plugins, apps, the plugins that have companion apps, the apps that have plugins. Nothing happens there. It stores metadata and exposes an API, so a platform can embed it.

Underneath, two separate plugins with separate repositories:

ships to holds is
the storefront every instance no database, no sidecar free infrastructure
the apps engine whoever distributes builds 4 tables, a sidecar, artefacts, Apple credentials the paid product

They are split on that last column rather than on any technical boundary. Bundled, every server would carry app-distribution machinery it will never run, and the commercial half would live inside the plugin that can never be uninstalled. That is the wrong seam.

Brand is not appName. label is what a person reads; appName is the directory name and the route. Both can be "Kiosk" to a human while being distinct identifiers underneath — the same way email's label is "Email".


/marketplace goes away

Replaced by /kiosk, and the screen moves out of the platform into the storefront plugin, which mounts exactly the way every other plugin does.

The install machinery does NOT move. src/servers/plugins/ — discover, mount, install, schema, ecosystem — is how any plugin gets mounted, including Kiosk itself, so it cannot live inside one. It is already API-shaped (/api/plugins: what is on this machine, what is installed, and the four verbs that change it), which is what makes this a UI move rather than a refactor.

So: the platform keeps the mechanism, the plugin owns the shop window.

Because a first-party plugin mounts at /<appName> (mountPrefix, verified), the storefront must be appName: 'kiosk'. That settles the identifier by way of the route.

The storefront is a privileged plugin

Not a normal one, and the differences are deliberate:

  • installed on every instance, as a setup step rather than a marketplace action — you cannot install the installer with the installer;
  • not listed among installed plugins;
  • no uninstall UI;
  • and removing it must not brick the server. A user can always stop or delete the PM2 service by hand, so the platform has to survive the storefront being absent. The install verbs are the platform's and stay reachable without it; that is what makes this true rather than hoped.

Two calls to action, one catalogue

The hub is a discovery surface for people who do not have a server yet — someone browses it and asks their admin for something. That is a funnel, and it means the two halves end differently:

  • a plugin can be installed — by an admin, on a server, now;
  • an app cannot be installed from the hub at all. It needs a server running the apps plugin, an account, a registered device, and somebody paying Apple.

Same catalogue, two endings. Worth designing the entry shape around, rather than discovering it when the Install button does nothing for half the listings.

The pairing is declared data, not inference. "Plugins that have apps" cannot be derived from names that happen to match; a manifest field declares the companion. It is the smallest piece of work here and the whole browsing experience hangs off it. Safe to put in the public catalogue — names, not artefacts.


Open

  • What the apps plugin is called. It cannot be kiosk, since the storefront takes that with the route. kiosk-apps is legible and obviously paired; builds describes what it manages. Currently sitting at plugins/kiosk (and gitea.officer.dev/plugins/kiosk) from the night it was started — that name is wrong and pending a decision, which is cheap now and expensive after either ships.
  • Whether marketplace.officer.dev becomes kiosk.officer.dev. Precedent says rename the screen and leave the machine endpoint alone: every installed server has the current URL baked in as its default, so a rename drops them to the bundled catalogue until they update.
  • Everything about third parties — review, pinning, confining a plugin's sidecar. See TODO.md, "Plugin ecosystem — before it opens to third parties". Months away and not a prerequisite for the rename.