Skip to content

The ERP as the KiCad library

Make the ERP the only source of placeable parts: KiCad's symbol chooser lists ERP parts, and placing one brings the IPN, description, footprint, value and datasheet along. A part that is not in the ERP cannot be placed. Owner idea, 2026-10-06. Related: KiCad, embeddedera-app, SOP-001, SOP-002, SOP-008.

How it works

  • KiCad HTTP libraries (KiCad 8 and newer; this server runs 10.0.5) read parts from a web address instead of a symbol file. Format: https://dev-docs.kicad.org/en/apis-and-binding/http-libraries/.
  • The InvenTree KiCad plugin (afkiwers/inventree_kicad, MIT, release 2.1.0 on 2026-09-20, needs InvenTree 1.2+; ours is newer) serves the ERP parts in that format at /plugin/kicad-library-plugin/.
  • The ERP stores pointers, not drawings. Drawings stay in the KiCad libraries we already have:
In KiCad Comes from Example
Symbol drawing default symbol per ERP category Resistors → Device:R
Reference letter default per category Resistors → R
Footprint a part parameter (or a mapping table) Resistor_SMD:R_0603_1608Metric
Value a chosen part parameter 1K
Description, IPN the part itself RES 1K 1% 0603, EE-C-0163
Extra fields part parameters, visibility configurable MPN, manufacturer, design note
Datasheet not yet from the part link (open plugin issue #170); a parameter works URL
  • Categories become the chooser's folders, so the ERP category tree matters (Resistors, Capacitors, ICs/MCU, Connectors…).
  • One generic drawing serves many parts; only chips and special parts need their own drawing (EmbeddedEra:STM32G0B1_LQFP48).
  • Board features with nothing to buy (mounting holes, test points, solder jumpers, programming pads) stay ordinary KiCad symbols with no IPN and excluded from the BOM.
  • Placed symbols are copied into the schematic, so old designs open offline or after a part is archived (expected, to be tested).

Login through Cloudflare

KiCad sends only Authorization: Token <ERP token>; it cannot send Cloudflare Access headers. Options, in order: 1. A Cloudflare Access bypass for /plugin/kicad-library-plugin/* only, gated by a read-only ERP token for KiCad. Check first that those endpoints expose only part metadata. 2. A LAN-only hostname for the plugin (works only at the shop). 3. A small local proxy on the laptop that adds the Cloudflare service-token headers.

Steps

Status 2026-10-06 (owner approved the plan with all recommended options; phases 1 and 2 done on the sandbox ERP, production untouched).

  1. Sandbox first: DONE. Plugin 2.1.0 installed on the sandbox (pinned in the sandbox plugins.txt, restart), migrations clean (8 of 8), plugin active. Source read; facts below. Demo passes: erp-library/httplib_check.py in branch erp-httplib of ~/kicad-lib lists 7 categories and 175 parts, resolves a resistor (EE-C-0163) and an STM32 (EE-C-0097), places them into a schematic and kicad-cli exports a BOM and netlist carrying IPN, Footprint, Value, Manufacturer and MPN. Finding: production is already ahead of this plan. It already runs plugin 2.0.4 (active), the Symbol/Footprint/Reference/Value templates, default symbol and reference on 7 categories, a kicad-library reader user, a LAN httplib at ~/torrentvpn/inventree/kicad/EmbeddedEra-ERP.kicad_httplib, and 141 parts with all four parameters (inventree card). What is new is 2.1.0, the narrower token user, the repo template and the Cloudflare path.
  2. ERP data: DRAFTED, not applied. Proposal Sheet in the Shared Drive Documents folder (https://docs.google.com/spreadsheets/d/1zQM6SUKdlRZvnzNmMWaYzbCdJu_AKqzXe0CEH4hv3Hw/edit). 189 active production parts: 154 from the library or existing parameters, 11 by rule, 19 not placeable, and 5 left blank (AM90, RGB LED TZ-5050, coin vibration motor, two LiPo cells) because both free models (nemotron-3.5-lightning, ling-3.1-flash) spent their whole token budget thinking and returned no answer, so Engineering fills those by hand. Production already has the categories and templates, so what remains is filling about 30 parts and the category split.
  3. Access: prepared, not applied. Read-only assistant-kicad user and token created on the sandbox only (group KiCad read-only: part and part_category view, nothing else). Cloudflare script ~/assistant-sandbox/scripts/erp-kicad-public-path.py (dry run by default, --apply, --remove, --verify). Required before applying: strip the login header at the origin (see security assessment below).
  4. KiCad: PARTLY DONE. erp-library/EmbeddedEra-ERP.kicad_httplib (token placeholder, sandbox URL) and the check script are committed on branch erp-httplib (not pushed, not merged). Still to test by hand in the KiCad GUI: the symbol chooser listing and opening an old project offline (a placed symbol is embedded in the schematic, and the BOM export in the demo needs no ERP).
  5. Production: not started; waits for the owner to see the demo. The plugin upgrade is 2.0.4 to 2.1.0 (add the pin to production plugins.txt, restart).
  6. SOP-008 rewrite: draft section 8 in SOP-008 v2.2 (draft): placing ERP parts, two cases, board features, cache timing.

Plugin facts (read from 2.1.0 source, confirmed against the sandbox)

  • Symbol: a per-part parameter (plugin setting KICAD_SYMBOL_PARAMETER, here template Symbol) overrides the default symbol of the deepest selected category the part sits under; if neither, the setting DEFAULT_FOR_MISSING_SYMBOL. Extra colons in a name are replaced by underscores.
  • Footprint: the category's own footprint template, else the global KICAD_FOOTPRINT_PARAMETER (Footprint), mapped through the optional per-category mapping table, else the category default footprint. Value: KICAD_VALUE_PARAMETER, else the category default value template, else the part Name (this is why resistors named by MPN show the MPN until Value is filled). Reference: per-part parameter, else category default, else X.
  • Fields emitted: value, footprint, datasheet, reference, description, keywords; InvenTree (part id) and Part URL (hidden); IPN only when KICAD_INCLUDE_IPN is set (production: include_visible); every other part parameter as an extra field (units included); with KICAD_ENABLE_MANUFACTURER_DATA (production: on) Manufacturer_n, MPN_n, Supplier_n, SPN_n. exclude_from_bom, exclude_from_board, exclude_from_sim come only from parameters named in the plugin settings (not configured; default False). Datasheet is the first part attachment whose comment is datasheet (not the Link field). Stock count in the description is optional (production: on).
  • Caching: none on the server (only per-request lookups). KiCad caches by the httplib file: timeout_parts_seconds, timeout_categories_seconds. Inactive and (setting) template parts are hidden from category lists; sub-category parts are included in the parent (a part shows under Components and under Components/Passives).
  • Hazards found: /v1/parts/ (no category) lists every part including assemblies and consumables; the list is not limited to the selected categories. Parameters beyond the KiCad ones are all exposed as fields.

Endpoints (for the Cloudflare review), sandbox, 2026-10-06

Base /plugin/kicad-library-plugin/. Without any token every one returns 401. With the read-only token (part and part_category view only):

Path Method Returns Read-only token
v1/ (and any unknown path) GET links to categories and parts 200
v1/categories/ GET selected categories: id, path name, description 200
v1/parts/category/<id>.json GET parts: id, name, description (+stock), symbol, all fields above, exclude flags 200
v1/parts/<id>.json GET one part, same 200
v1/parts/ GET every part in the ERP, same fields (about 166 KB) 200
api/category/ (+ <pk>/) GET, POST, PUT, PATCH, DELETE KiCad category settings; creates, edits, deletes them 403 (needs part_category change rights; an Owner or Engineering token could write)
upload.json POST imports a KiCad XML netlist into part parameters 403 for the read-only user (CSRF page); writes for a user with rights
progress_bar_status GET import progress of the caller 200, harmless

Not exposed: prices, suppliers' prices, customers, orders, stock locations, BOMs. Exposed: part names, descriptions, IPNs, MPNs and manufacturers, supplier names and SKUs, stock counts, all part parameters, internal part URLs. The same token can still read /api/part/, /api/user/ and /api/settings/global/ if it can reach them (any authenticated user can on this InvenTree); those stay behind Access.

Cloudflare security assessment

  • Scope the bypass to /plugin/kicad-library-plugin/v1/*, not /*. KiCad only calls v1/; this keeps upload.json and the category write API behind Google login.
  • Blocker: forged login header. Production uses INVENTREE_REMOTE_LOGIN=True with header HTTP_CF_ACCESS_AUTHENTICATED_USER_EMAIL. On a bypassed path Access does not authenticate, so a client can send that header itself, and InvenTree would trust it unless the origin strips it (reasoned from the config, not tested live). Mitigation: in the ERP Caddyfile :80 block drop the header for the path (@kicad path /plugin/kicad-library-plugin/* then request_header @kicad -Cf-Access-Authenticated-User-Email), then run the script's --verify, whose spoof test must return 401. Not checked on the live host because that needs the production change. Production config was not edited.
  • Residual risk once done: the read-only token is the only guard, on the public internet; part data (not prices, no customer data) is readable by whoever holds it. Mitigations: dedicated narrow user (not the existing kicad-library, whose Read-only group can also view admin, stock and purchase orders), token rotation (erp-token flow), Cloudflare rate-limit on the path, and --remove rolls back in one call. Option 2 (LAN-only) stays the zero-exposure choice.

Open questions for the owner

  • Programming header (EE-C-0065, -0067): footprint only, or a connector we buy?
  • Bypass (option 1) acceptable, or keep the ERP fully behind Google login and use option 2 or 3?

Not checked yet

Placing from the real KiCad GUI chooser (the demo emulates the HTTP client and places through a generated schematic); behaviour of KiCad with the ERP unreachable at chooser time; the live Cloudflare header-strip test (needs the production Caddy change).