Skip to main content

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:

  1. 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
  1. Backend DocType discovery (metadata-driven modules)
  • Source: Python app entry points under framework_m.apps
  • Discovery: MetaRegistry.load_installed_apps()
  • Use for: /app/:doctype/list entries from GET /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() in vite.config.ts
  • Shell app actually consumes discovered plugins (menu and routes)
  • Workspace has a pnpm-workspace.yaml
  • Python workspace has a root pyproject.toml with uv workspace members

See also:

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.json
  • libs/wms/frontend/src/plugin.config.ts
  • libs/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_resource defaults to False if not set
  • show_in_desk defaults to True
  • If api_resource is False, DocType will not be available in /api/meta/doctypes list 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

Use two terminals:

  1. Backend terminal
cd apps/business-m
uv run m dev
  1. 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.ts includes frameworkMPlugin()
  • Plugin package is included in pnpm-workspace.yaml
  • Plugin package has "framework-m" metadata (not frameworkM)
  • Shell app code renders discovered plugin menus and plugin routes

DocTypes not visible but plugin menu is visible

Check:

  • App appears in framework_m.apps entry points at runtime
  • DocType has Meta.api_resource = True
  • Backend restarted after dependency/meta changes
  • /api/meta/doctypes includes 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> or apps/<app_name>
  • framework_m.apps entry point is defined
  • Frontend plugin scaffold exists at <app>/frontend
  • Plugin package.json contains framework-m plugin 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/doctypes returns 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.