The standalone registry + storefront that serves official and community Miabi application & database templates. It is the producer side of the marketplace; Miabi is the consumer (it syncs the catalog into a local cache and serves it in the console).
- Stateless: git is the database. Templates under
official/+community/are embedded at build time; merging tomainregenerates the catalog so it always matches the repo. - Two ways to consume it — Miabi works with either:
- Hosted (recommended): point
MIABI_MARKETPLACE_URLathttps://marketplace.miabi.io— the live API + storefront, updated on every merge tomain, ETag/304-capable. Nothing to host, and you get the storefront and/docsalongside the bundle. - Static or self-hosted: CI also commits
export.json(the full bundle), so you can sync straight from git — e.g.https://cdn.jsdelivr.net/gh/miabi-io/marketplace@main/export.json— or run the Okapi service below on your own domain and pointMIABI_MARKETPLACE_URLat its base URL. Useful for air-gapped installs and private forks.
- Hosted (recommended): point
official/<name>/<version>/template.yaml curated, CODEOWNERS-protected (source of truth for official)
official/<name>/metadata.yaml optional storefront metadata (featured, screenshots, …)
official/<name>/README.md optional long description (detail page)
community/<name>/... contributed, same shape; open PRs
export.json GENERATED full bundle (every manifest inline) — what /v1/export serves, also syncable from git
registry/index.json GENERATED lightweight machine index (CI checks for drift)
manifest/ the miabi.io/v1 manifest module: parse + validate + digest
schema/template.schema.json JSON Schema for editors + CI
internal/{catalog,api,seo,web} the Okapi service (web embeds the built storefront, seo serves the crawler surface)
web/ the storefront SPA (Vue 3 + Pinia + Vite)
cmd/marketplace server + generate-index + lint
<name> is the template handle — lowercase ^[a-z0-9][a-z0-9-]*$, matching
the manifest's metadata.name and unique across official/ + community/. The
manifest also carries a metadata.displayName (the free-text label shown in the
storefront and console) and a metadata.version.
The service mirrors the Miabi/Posta stack (Go + Okapi, {success,data,error}
envelope on client routes). Machine routes (/v1/export, /v1/index) return
their raw document so a consumer can decode it directly; /v1/export is Miabi's
primary sync call.
The full reference — every route, parameters, and schemas — is served live and interactive:
| Path | Purpose |
|---|---|
/docs |
Interactive API documentation (browse and try every endpoint). |
/openapi.json |
The raw OpenAPI spec behind /docs. |
/healthz · /metrics |
Health probe + Prometheus metrics. |
/v1/version |
Running build: catalog version (the release tag, without its v), commit and build date. |
/robots.txt · /sitemap.xml |
Crawler surface; the sitemap is generated from the catalog. |
A Vue 3 + Pinia SPA (web/) served by the same binary over Okapi's WebFS, at
/, /templates/{name} and /about. Search is instant — results follow typing, with no
submit button — and every filter is mirrored into the URL, so any result set is
a shareable link.
Because it renders client-side, a crawler that indexes the served HTML would see
one generic head on every URL — which is how a template page ends up listed as a
bare link with no title. The shell therefore carries a marked-off block of head
tags (<!-- seo:start --> … <!-- seo:end --> in web/index.html) that
internal/seo rewrites per request with the page's own title, description,
canonical URL, Open Graph tags and JSON-LD. Titles are kept identical to the ones
the SPA sets client-side, so the served HTML and the rendered DOM agree. The same
package serves /robots.txt and a /sitemap.xml listing every template.
Canonical URLs and the sitemap need an absolute origin, and a request's Host
header is not trustworthy, so it comes from MARKETPLACE_BASE_URL (default
https://marketplace.miabi.io). Set it when hosting a fork.
make build-ui builds it with Vite and stages the output into
internal/web/dist, where go build embeds it; make dev-ui runs the Vite dev
server on :3100 with /v1 proxied to a local make run. Only a .gitkeep is
committed under internal/web/dist, so a clean checkout still builds — the API
serves, and the storefront 404s until the UI is built.
go run ./cmd/marketplace # serve on :8088 (MARKETPLACE_PORT to override)
go run ./cmd/marketplace lint # validate every embedded template
go run ./cmd/marketplace generate # rewrite export.json + registry/index.json (CI runs + diffs this)Miabi does a conditional GET (ETag) of the bundle — this service's /v1/export
or a static export.json — caches it in Redis, and merges it with its embedded
official floor and per-workspace custom imports, serving Official / Community /
Custom tabs locally (search + pagination are done client-side, so no server
round-trips are needed).
Set MIABI_MARKETPLACE_URL to enable the sync; empty means embedded-only
(air-gapped). The recommended value is the hosted registry:
MIABI_MARKETPLACE_URL=https://marketplace.miabi.ioA server base URL and a static export.json URL are both accepted, so a fork or
an internal mirror drops in the same way.
See CONTRIBUTING.md. Community templates are a fast
PR-to-live path; official templates are maintainer-gated via CODEOWNERS. You
can also test a template live before contributing by importing it into the Miabi
console (Marketplace → Import) and installing it.

