Preview locally
@revenexx/studio-commerce-devkit is published on the public npm registry and boots the same Commerce Studio module the Cockpit runs, against mock data generated from your app's schema.json. No platform, no backend, no auth, no account.
This is the loop that is fully available to you today.
Install and run
cd my-commerce-app # the directory holding cockpit.json
npm i -D @revenexx/studio-commerce-devkit
npx commerce-studio
Open http://localhost:3030/commerce. The sidebar lists your app; open it and its list, detail, form and widget views render from cockpit.json.
pnpm and yarn work the same way — pnpm add -D @revenexx/studio-commerce-devkit && pnpm commerce-studio.
| Environment variable | Effect |
|---|---|
PORT | Change the port. Default 3030. |
APPS_DIR | Which directory the apps are read from. Defaults to your current directory. |
NUXT_STUDIO_BUILDDIR | Where the preview's build output goes. Defaults to .commerce-studio/ in your project — gitignore it. |
Preview a whole set of apps at once by pointing APPS_DIR at their parent:
APPS_DIR=/path/to/apps npx commerce-studio
The loop
- Edit
cockpit.json— navigation, list, detail, form or widget views. - Edit
schema.json— entities and columns, which drive the mock data. - Reload the page. The manifests are re-read from disk per request, so there is no rebuild and no restart.
- Iterate. The same
cockpit.jsonrenders identically in the real Cockpit, because this host runs the exact same module.
What the mock data is built from
The preview reads your schema.json and generates plausible rows generically:
| Declaration | Becomes |
|---|---|
A column type | A value of that shape — text, number, boolean, timestamp, uuid, jsonb |
A check with an in (…) list | The set of values that column cycles through — so a badge column and a select field show real options |
A references entry | A real id taken from the referenced entity's own mock rows, so relation columns and pickers resolve |
notNull and default | Whether a value is present, and what it starts as |
{
"$schema": "https://schemas.revenexx.com/schema.schema.json",
"entities": {
"suppliers": {
"columns": {
"id": { "type": "uuid", "pk": true, "default": "gen_random_uuid()" },
"code": { "type": "text", "notNull": true },
"name": { "type": "text", "notNull": true },
"status": { "type": "text", "notNull": true, "default": "'active'",
"check": "status in ('active', 'paused', 'retired')" },
"created_at": { "type": "timestamptz", "notNull": true, "default": "now()" }
}
}
}
}
Creates, edits and deletes persist in memory for the session and are regenerated when the server restarts. It is for seeing the UI, not for persistence.
The functions console
Open /functions from the top strip to run your app's server-side code locally against a simulated API gateway.
It lists your app's routes from manifest.capabilities.json. Pick one, fill in the path params, the query and a JSON body — prefilled from the request schema — and Send. You get the real response: status, JSON, timing, and the function's log output.
How it works:
- Each app is one function at
src/main.js. The simulated gateway builds a request context, requires the module and invokes it. - The function's data adapter is pointed at the same mock store the views read. So you create a supplier through
POST /suppliersin the console, then see it in the/commercelist. - Cross-app calls run locally too. A function's gateway client is pointed back at this host and the real
/v1/<app>/…path scheme is served, so a multi-app flow is forwarded to the other apps' functions against the same store.
Two requirements:
- The app's own dependencies must be installed, since the preview
requires your function. - Every participating app in a cross-app flow needs its dependencies installed too, since each one is required and run.
Edits to src/main.js are picked up on the next run.
What is stubbed
The standalone host has no Storage or import/export service behind it, so two things are deliberately inert:
| Surface | Standalone behaviour |
|---|---|
A media / media-collection field | The picker does nothing. The real Storage picker is Cockpit-only. |
A view's io (import/export) block | Not offered. |
Both work in the real Cockpit. Do not treat their absence here as a manifest error.
Troubleshooting
| Symptom | Cause |
|---|---|
| Empty sidebar, no apps | APPS_DIR points somewhere without a cockpit.json. |
| A list view renders but is empty | The entity has no columns in schema.json, or a check / references the generator could not satisfy. |
| A nav entry does not appear | The entry has neither a route nor children, so it has nothing to show and is dropped. |
| A nav entry appears in the wrong section | group is not one of the four recognised keys — see Navigation. |
| An icon is a generic box | The Solar icon name did not resolve. A typo shows as the fallback icon rather than as a blank sidebar. |
An api action returns 404 | The endpoint has no matching capability in manifest.capabilities.json. |
Where to go next
- Getting started — the same loop as a guided ten-minute path.
- cockpit.json reference — what to write next.
- Actions and writes — wiring a button to your function.
- From manifest to installed — what happens after the preview.