Custom editors
Some work exists in no panel at all, because it is only yours: a price recalculation by your supplier's formula, reconciling the catalog with someone else's accounting system, a screen that fills in the features of a whole batch in one pass. The Custom editors section lets you write such a mini-editor yourself (or order one) and run it inside the admin panel — in a sandbox, with access to exactly the data you allowed.
Open: Admin panel → Custom editors (admin.cenaly.com/custom-editors). The section is switched on by the "Custom editors (SDK)" card in the app store — it is hidden by default. The "📌 Pin to sidebar" button on the page itself puts it into the side menu when you need it often.
What this section is#
A plugin is a built script (index.js) and its description (manifest.json). The panel loads the script into an isolated frame: it has no access to your session, to the panel's code or to the network. It can talk to data only through the bridge — a set of allowed requests, each checked against the permissions you granted.
The page consists of blocks:
| Block | What's inside |
|---|---|
| Installed editors | a card per plugin: name, "Version", "Permissions", "Placement", "Allowed network hosts", "Updated", the source (repository and tag as a link). Actions: "Open", "Enable" / "Disable", checking for updates, "Remove" |
| Install an editor | installing from files on disk |
| Install from GitHub | installing by the address of a public repository and a tag |
| 🤖 Build with AI (vibe coding) | a project template, a prompt for an AI agent and a catalog snapshot as test data |
| 👩💻 Developer access | temporary grants of developer mode to a contractor |
| 🛠️ Developer mode | running a plugin straight from your computer, without installing |
An open editor takes the whole screen, and the address gains a ?app=<id> marker — such a link can be shared with anyone who has access.
What you need to start#
| What | Why |
|---|---|
| The "Custom editors (SDK)" card in the app store | the section is niche and switched off by default |
| You are the account owner | only the owner can install, enable, remove plugins and issue grants; employees see the list read-only |
A built plugin: index.js + manifest.json |
yours, a developer's, or a release in a public GitHub repository |
| For development — an employee account for the developer | developer mode is granted by the email of their work login |
Step 1. Decide who writes the editor#
There are three routes, and they differ in who holds the code:
| Route | Who it suits | How |
|---|---|---|
| An AI agent on our template | an owner ready to explain the task in words | the "Build with AI" block: template + prompt → the agent assembles a release → you install it |
| Your own or a hired developer | there is a contractor or a developer on the team | issue them a grant for developer mode, they write and debug against the live account, you install the finished release |
| A ready release from GitHub | the plugin already exists (yours or made for you) | "Install from GitHub": the repository address and a tag |
In all three cases installation stays with the owner: even a developer with a grant can only run their own code in developer mode, not put it into the account.
Step 2. Build with AI (vibe coding)#
The "🤖 Build with AI (vibe coding)" block gives four things, so that you can hand the task to an AI agent (Claude Code, Cursor and the like) without explaining the contract from scratch:
- "⬇️ Download the project template (zip)" — a ready skeleton of a plugin: the manifest, the entry point, the contract description (
GUIDE.en.md) and instructions for the agent. The archive is assembled right in the browser, nothing external is downloaded. - "📋 Copy the prompt for the agent" — the task text in English: start from the template, follow the guide, and here is how to verify the result.
- A tool configuration for the agent — with it the agent builds the plugin, launches a local copy of the sandbox, takes screenshots and state snapshots, and finally assembles a release: a zip for manual installation or a GitHub release.
- "⬇️ Download a catalog snapshot (test fixture)" — your categories and items as a file, so the agent tests against real data instead of invented data.
⚠️ The custom fields of other plugins are cut out of the snapshot entirely: data that a third-party extension keeps on your cards does not leave the account with the fixture.
Step 3. Install the editor#
From files. The "Install an editor" block: pick the "Bundle (index.js)" and the "Manifest (manifest.json)" → "Validate and install". The panel first checks the manifest — identifier, localised name, version, minimum SDK version, placements, permissions and the list of network hosts — and then shows the consent screen: "This editor requests:" and the list of permissions in plain language. Until you press "Install", nothing is installed.
From GitHub. The "Install from GitHub" block: the "Repository (URL or owner/repo)" field, the "Tag (empty = latest release)" field and the "Check repository" button. The convention is simple: manifest.json in the repository root, the built dist/index.js in the tag, the tag named v{version}. The manifest and the bundle are fetched straight from your browser. In both cases the bundle fingerprint (sha256) is computed and stored at install time: if the file is swapped later, execution is blocked and the panel asks you to reinstall the editor.
Permissions and placement#
Permissions (also called scopes) are requested by the plugin in its manifest and confirmed by you at install time. Here is the full list — the bridge can do nothing else:
| Permission | What it opens |
|---|---|
| Read the catalog | categories, items, features and the custom fields of cards |
| Create and change catalog items | creating and editing items, batch import, own fields and feature definitions |
| Change prices, availability and stop lists per location | the same thing the panel does in a location's menu |
| Read the stock item reference | the inventory nomenclature, read-only |
| Keep its settings in your storage | the plugin's own keys inside your account (up to 1 MB per key) |
| The extension's server side | calls to the plugin's code on our server — its only way to reach the internet |
Whatever is not on that list the plugin will never get, by any setting: guests and customers, orders, receipts, finance, employees, chats and calls are not exposed by the bridge at all.
There are three placements (slots):
| Slot | Where it appears |
|---|---|
| Its own page | an item inside the "Custom editors" section, opened full screen |
| A button on the catalog page | a tool next to the item catalog |
| A tab of the "Inventory" section | the plugin is rendered as an inventory tab — that is how our built-in "VetIS" extension is packaged |
Developer mode and contractor access#
Developer mode (the "🛠️ Developer mode" block) mounts a plugin live from your computer: the "Bundle URL" field accepts only localhost / 127.0.0.1 addresses, next to it is "Manifest JSON" and the "Start dev session" button. No fingerprint is pinned, and the session lives until the tab is closed; "Stop dev session" ends it at once.
Developer grants (the "👩💻 Developer access" block) are for when the author is not the owner. The developer gets an ordinary employee account, and then the owner issues a grant: "Developer email (their staff login)", "Allowed permissions", "Validity (days)" and an optional note → "Grant access". It can be revoked at any moment with "Revoke".
What a grant does and does not do:
- it does give developer mode only, with the permissions you ticked (14 days by default, 90 at most);
- permissions are cut down to the intersection: what the manifest requests and what the grant allows — the plugin gets nothing extra even if it asks for it in the manifest;
- it does not give installing, enabling or removing plugins: that stays with the owner.
Updating, enabling and removing#
| Action | How |
|---|---|
| Open | the "Open" button on the card (or a link with ?app=…) |
| Disable temporarily | "Disable" — the plugin stays installed but does not run and does not appear in its placements |
| Update | for plugins from GitHub — "Check for updates" and then "Update to …"; if the version is current, the panel says "The latest version is installed". Plugins from files are updated by installing again |
| Remove | "Remove" with a confirmation: settings and the menu item go, uploaded releases stay in storage |
There is no auto-update on purpose: a new version of someone else's code means a new fingerprint and possibly new permissions, so updating is always a deliberate act of the owner.
Built-in extensions#
Some of our own modules are packaged in the same format — you can tell by how they behave — but you do not install them: they ship with the panel and are switched on by a card in the app store, not in this section.
There is one such module today — "Mercury/VetIS" for Russia: it lives as a tab of the Inventory section, runs in the same sandbox and with the same fingerprint checks. Built-in extensions do not appear in the list of installed editors.
What an editor can and cannot do#
| It can | It cannot |
|---|---|
| Read and change the catalog within the granted permissions | learn your password or use your session |
| Show its own interface, notifications and confirmation prompts | open the code or data of the admin panel around it |
| Open the panel's native item editor | reach the internet directly from the plugin window |
| Keep its settings inside your account | see another plugin's data on your cards |
| Reach the internet through its server side — and only at the https addresses listed in the manifest (no more than eight) | run after the file has been swapped: a fingerprint mismatch blocks execution |
Third-party plugins carry a warning on their card: "A third-party app in a sandbox — it never asks for your password." If a plugin asks for your panel login, payment details or an SMS code, that is fraud, not how an extension works.
Limitations#
- The section is off by default and is meant for people who write code (or commission it): an ordinary owner has nothing to do here.
- Everything except viewing is owner-only. An employee sees the hub read-only; developer mode requires a live grant.
- Private GitHub repositories are not supported — the repository must be public, and installation goes by tag.
- There is no auto-update: updating a plugin is always started by the owner.
- There is no marketplace of third-party plugins. Ready extensions are neither published nor sold through the panel — the source is your file or your repository.
- There are three slots (own page, catalog button, inventory tab) — a plugin cannot embed itself into an arbitrary screen of the panel.
- The bridge exposes no guests, orders, finance, employees or chats — permissions cannot change that, such requests simply do not exist.
- There is no separate "the plugin did this" log. Permissions are visible on the card and catalog edits land in the ordinary item history; if you need control, start with a plugin granted read-only access.
- Technical ceilings: a bundle up to 4 MB, up to 8 network addresses in the manifest, up to 1 MB per storage key; a server run lasts up to 30 seconds and makes up to 50 outbound calls.
- The plugin's data stays in your brand's cloud: for an account on
cenaly.ruthe server side's state lives in the Russian circuit.
Troubleshooting#
| Symptom | Check |
|---|---|
| There is no section in the menu | whether the "Custom editors (SDK)" card is switched on in the app store; whether the section was pinned with "📌 Pin to sidebar" |
| An employee sees no install controls | that is by design: installing, removing and grants are owner-only |
| "The stored bundle does not match the pinned fingerprint. Execution blocked" | the plugin file was swapped after installation — reinstall the editor to record the new fingerprint |
| "The editor did not start in time (no connect() within 10 s)" | the plugin never came online: an error in its code or the wrong file was built |
| "Failed to load the editor bundle" | the release is unavailable or the file is damaged — reinstall |
"Editor not found or disabled" when following a ?app=… link |
the plugin was removed or disabled on its card |
| "Failed to fetch the editor from GitHub" | the repository is private, there is no manifest.json in the root, no dist/index.js in the tag, or the tag is not named v{version} |
| "Only localhost / 127.0.0.1 addresses are allowed" | developer mode deliberately refuses external addresses — serve the build locally |
| The plugin does not see the data it needs | check "Permissions" on the card; for a developer with a grant, permissions are further cut to the intersection with the grant |
| The plugin cannot reach an external service | there is no direct network in the sandbox: the call is made by the server side, and the address must be in the manifest |
| "The editor reports unsaved changes. Close anyway?" | the plugin itself reported a draft — save your work inside it before closing |
FAQ#
Do I need to know how to program?#
To install a ready release — no. To get that release — yes: it is written by a developer or by an AI agent on our template from the "Build with AI" block. The section is a tool for code, not a drag-and-drop builder.
Can a third-party plugin see my customers or my revenue?#
No. A plugin runs in a sandbox and receives data only through the bridge, and the bridge does exactly six things: the catalog, prices and stop lists, the stock reference, its own storage, calling its own server side and interface elements. Guests, orders, receipts, finance, employees and chats are not there at all. What a particular plugin is allowed is always visible on its card in the "Permissions" line.
How do I let a contractor develop without giving them the whole account?#
Create an employee account for them and then issue a grant in the "Developer access" block: tick only the permissions needed and set an expiry (14 days by default, 90 at most). They get developer mode and nothing else; installing the plugin still stays with you. The grant is revoked with one button.
Will a plugin update itself when the author ships a new version?#
No. Updating is started by the owner: "Check for updates" → "Update to …". This way a new version never appears in the account behind your back — the permissions it requests may have changed along with it.
Where does a plugin keep its settings and data?#
Inside your account, in separate storage under its identifier (up to 1 MB per key), plus — if it uses them — in the custom fields of your cards; each plugin sees only its own space. For an account on cenaly.ru the server side and its state remain in the Russian circuit.
How is this different from the API and MCP?#
The developer API and MCP are for programs that work outside: your own website, someone else's accounting system, an AI agent. A custom editor is the opposite — an interface inside the panel: an employee opens it like any other admin page and never leaves their working window.
Related articles#
- App store — where the section and the built-in extensions are switched on
- Inventory — the tab extensions like "VetIS" live in, and the stock reference
- Catalog import — the standard way to load items, if that is the whole task
- Headless storefront — the open data contract for an external website
- MCP Server and Guest API for AI agents — working outside the panel, not inside it
- Employees and shifts — an account for the developer, and roles
- Security and data — what is stored where and who has access
- Support — where to write if a plugin behaves suspiciously