Sidebar Plugin Onboarding Guide
A practical guide for adding WMS, Finance, or any app into a Framework M shell sidebar.
This guide is based on the same flow used for Finance plugin onboarding.
Who This Is For
Use this guide if you have:
- A shell app (for example,
apps/business-m/frontend) - One or more domain apps (for example,
libs/finance,libs/wms) - A goal to show plugin pages and DocTypes in the shell UI sidebar
Core Idea: Two Discovery Paths
Sidebar items come from two different systems:
- Frontend plugin discovery (plugin menu/routes)
- Source: each plugin frontend package
src/plugin.config.ts - Discovery: pnpm workspace +
@framework-m/vite-plugin - Use for: dashboard pages, custom routes, custom menu groups
- Backend DocType discovery (metadata-driven modules)
- Source: Python app entry points under
framework_m.apps - Discovery:
MetaRegistry.load_installed_apps() - Use for:
/app/:doctype/listentries fromGET /api/meta/doctypes
If frontend plugin works but DocTypes do not appear, backend discovery or DocType Meta flags are usually missing.
Prerequisites
- Shell frontend uses
frameworkMPlugin()invite.config.ts - Shell app actually consumes discovered plugins (menu and routes)
- Workspace has a
pnpm-workspace.yaml - Python workspace has a root
pyproject.tomlwith uv workspace members
See also:
- plugin-architecture-implementation.md
- plugin-composition-guide.md
- framework-entry-points.md
- ../rfcs/rfc-0007-sidebar-architecture.md
Part A: Add WMS or Any App as a Frontend Sidebar Plugin
1) Scaffold plugin frontend package
If the app already exists as Python package (for example libs/wms), scaffold only frontend plugin structure:
uv run python -c "from pathlib import Path; from framework_m_studio.cli.new import scaffold_frontend_plugin; scaffold_frontend_plugin('wms', Path('libs/wms'))"
This creates:
libs/wms/frontend/package.jsonlibs/wms/frontend/src/plugin.config.tslibs/wms/frontend/src/pages/*
2) Register plugin frontend in pnpm workspace
In pnpm-workspace.yaml:
packages:
- "apps/business-m/frontend"
- "libs/finance/frontend"
- "libs/wms/frontend"
3) Ensure plugin package metadata is correct
In plugin package.json, verify this key exists exactly (kebab-case):
"framework-m": {
"plugin": "./src/plugin.config.ts",
"type": "frontend-module"
}
4) Define sidebar menu + routes in plugin.config.ts
Minimal WMS example:
import type { FrameworkMPlugin } from "@framework-m/plugin-sdk";
const plugin: FrameworkMPlugin = {
name: "wms",
version: "0.1.0",
menu: [
{
name: "wms.dashboard",
label: "WMS Dashboard",
route: "/wms/dashboard",
module: "WMS",
order: 1,
},
{
name: "wms.stock-entry",
label: "Stock Entries",
route: "/app/stock_entry/list",
module: "WMS",
order: 2,
},
],
routes: [
{
path: "/wms/dashboard",
element: () => import("./pages/Dashboard"),
},
],
};
export default plugin;
5) Install JS deps and run shell frontend
pnpm install
cd apps/business-m/frontend
pnpm dev
Expected result:
- Plugin menu items appear under sidebar plugin section
- Custom route (for example
/wms/dashboard) loads from plugin page
Part B: Make Finance/WMS DocTypes Appear in Sidebar Modules
Plugin menus and DocType modules are different. For DocTypes to appear in sidebar module list, do all of the following.
1) Install domain apps into shell runtime environment
In shell app pyproject.toml (example: apps/business-m/pyproject.toml):
[project]
dependencies = [
"framework-m>=0.4.15",
"finance>=0.1.0",
"wms>=0.1.0",
]
[tool.uv.sources]
finance = { workspace = true }
wms = { workspace = true }
Then sync from shell app directory:
cd apps/business-m
uv sync
2) Ensure each domain app exports framework_m.apps entry point
In each app pyproject.toml:
[project.entry-points."framework_m.apps"]
finance = "finance:app"
[project.entry-points."framework_m.apps"]
wms = "wms:app"
3) Enable DocType API and desk visibility in DocType Meta
In each DocType you want in Desk:
class Meta:
api_resource = True
show_in_desk = True
Notes:
api_resourcedefaults toFalseif not setshow_in_deskdefaults toTrue- If
api_resourceisFalse, DocType will not be available in/api/meta/doctypeslist used by shell module menu
4) Run migrations and restart backend
cd apps/business-m
uv run m migrate
uv run m dev
5) Verify discovery quickly
Check installed backend apps:
uv run python -c "import importlib.metadata as im; print([e.name for e in im.entry_points(group='framework_m.apps')])"
Check metadata endpoint:
curl http://127.0.0.1:8888/api/meta/doctypes
Expected result:
- Finance/WMS DocTypes show up with
api_resource: true - Shell sidebar module list includes those DocTypes
Recommended Dev Loop
Use two terminals:
- Backend terminal
cd apps/business-m
uv run m dev
- Shell frontend terminal
cd apps/business-m/frontend
pnpm dev
Why both:
- Backend serves metadata and CRUD APIs
- Frontend composes plugin menus/routes from workspace plugins
Troubleshooting
Plugin page not visible in sidebar
Check:
vite.config.tsincludesframeworkMPlugin()- Plugin package is included in
pnpm-workspace.yaml - Plugin package has
"framework-m"metadata (notframeworkM) - Shell app code renders discovered plugin menus and plugin routes
DocTypes not visible but plugin menu is visible
Check:
- App appears in
framework_m.appsentry points at runtime - DocType has
Meta.api_resource = True - Backend restarted after dependency/meta changes
/api/meta/doctypesincludes the expected DocType
WMS app has no frontend yet
Create plugin frontend first (Part A, Step 1), then add menu/routes.
Minimal Checklist for New Plugin App
- Python app exists under
libs/<app_name>orapps/<app_name> -
framework_m.appsentry point is defined - Frontend plugin scaffold exists at
<app>/frontend - Plugin
package.jsoncontainsframework-mplugin metadata - App frontend path is added to
pnpm-workspace.yaml - Shell frontend uses
frameworkMPlugin()and renders plugin menu/routes - Target DocTypes set
Meta.api_resource = True -
uv sync,m migrate, backend restart completed -
/api/meta/doctypesreturns target DocTypes
If you follow this guide, adding Finance, WMS, or any new plugin app becomes a repeatable process with clear separation between frontend plugin composition and backend DocType discovery.