A minimal, working example of a customer deployment built on top of the published Lambda ERP packages. It depends on the published artifacts — it does not fork or vendor the core repo:
| Layer | Depends on | From |
|---|---|---|
| Backend | lambda-erp==0.2.2 |
PyPI |
| Frontend | @lambda-development/erp-core@^0.2.2 |
npm |
It doubles as the template a real (private) customer repo copies. Core fixes
arrive via a version bump in pyproject.toml / frontend/package.json — never a
merge into a fork.
Scaffolded as Phase D of the core's packaging plan (
docs/packaging-distribution-plan.mdin the core repo). See Status below for what's verified vs. still TODO.
All overrides go through the public extension seams — zero core files touched.
Backend (acme/, loaded via LAMBDA_ERP_PLUGINS=acme):
acme/sales_invoice.py—AcmeSalesInvoice(SalesInvoice)overriding_get_gl_entries(the replace seam).acme/plugin.py—register()wires it up withregister_doctype("Sales Invoice", AcmeSalesInvoice)and adds aregister_hook("Sales Invoice:after_submit", …)side-effect (the extend seam).acme/pdf_templates/document.html— a custom invoice/document PDF template, wired viaregister_pdf_template_dir(…)inregister()(the PDF override seam). It started as a copy of the core template and gets the same render context, so you just restyle the same data (logo, letterhead, CSS). Requires alambda-erprelease that includesregister_pdf_template_dir(bump the pin to that version).
Frontend (frontend/src/):
plugin.tsx—configureBranding(name + brand colour),configureApiBase,registerComponent("Dashboard", AcmeDashboard), and aregisterNavItem.dashboard.tsx— the replacement dashboard.brand.css— overrides the--brandCSS token for first paint.
lambda-erp-example/
pyproject.toml # lambda-erp==0.2.2 (the backend core)
app.py # ASGI entry: core app + serves THIS frontend build
acme/
plugin.py # register() — overrides + hooks + PDF template dir
sales_invoice.py # AcmeSalesInvoice(SalesInvoice)
pdf_templates/
document.html # custom PDF (register_pdf_template_dir)
frontend/
package.json # @lambda-development/erp-core ^0.2.2 + its peers
tailwind.config.ts # scans the core dist + uses its preset
src/{main,plugin,dashboard}.tsx, brand.css
Dockerfile # one container: builds frontend, serves via backend
.env.example
# 1) Backend — installs lambda-erp from PyPI + the acme plugin
python -m venv .venv && source .venv/bin/activate
pip install -e .
cp .env.example .env # LAMBDA_ERP_PLUGINS=acme is the key line
export $(grep -v '^#' .env | xargs) # or use your preferred env loader
uvicorn app:app --reload --port 8000
# 2) Frontend — installs the core npm lib + peers, proxies /api to :8000
cd frontend
npm install
npm run dev # http://localhost:5173docker build -t acme-erp .
docker run -p 8000:8000 -v acme-data:/data acme-erp # http://localhost:8000The image builds the frontend (core npm package + overrides) and serves it from the backend (core pip package + the acme plugin) at one origin.
Going to production? Read docs/deploying.md first — it covers the one thing that bites: persistence. SQLite needs a real disk (it can't get file locks on a network share like Azure Files), so on a managed container platform you point
LAMBDA_ERP_DBat PostgreSQL instead. Also covers the single-replica constraint and the stableJWT_SECRET_KEY.
- Plugin loading: the core reads
LAMBDA_ERP_PLUGINSon startup and calls each module'sregister(). That's the single entry point for backend overrides + hooks. - Serving the frontend: the core only auto-serves a frontend that sits next
to its own installed package, so this repo's
app.pyimports the core FastAPIappand mounts this repo'sfrontend/dist(with an SPA fallback). Run the backend from the repo root so the relative path resolves. - Styling ("consumer scans source"): our own Tailwind build generates the
utilities, scanning the core's built JS (
tailwind.config.tscontent) and using its sharedtailwind-preset. We import the core'sstyles.css(tokens- base layers) and override the
--brandtoken.
- base layers) and override the
MIT. See LICENSE for the full text.
Lambda ERP and lambda.dev are product and trade names of TORUS INVESTMENTS AG. It is not affiliated with, endorsed by, or sponsored by OpenAI, Anthropic, SAP, Oracle, Microsoft, or any other company named in this repository. SAP, Business One, S/4HANA, Oracle, NetSuite, Microsoft, Dynamics, OpenAI, GPT, Anthropic, and Claude are trademarks of their respective owners and are referenced here only for descriptive and comparative purposes (nominative fair use). We interoperate with OpenAI and Anthropic APIs as a customer like anyone else; you supply your own API keys.