netbox-inventree-sync 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. netbox_inventree_sync-0.1.0/LICENSE +21 -0
  2. netbox_inventree_sync-0.1.0/PKG-INFO +356 -0
  3. netbox_inventree_sync-0.1.0/README.md +333 -0
  4. netbox_inventree_sync-0.1.0/netbox_inventree_sync/__init__.py +42 -0
  5. netbox_inventree_sync-0.1.0/netbox_inventree_sync/api/__init__.py +8 -0
  6. netbox_inventree_sync-0.1.0/netbox_inventree_sync/api/exceptions.py +19 -0
  7. netbox_inventree_sync-0.1.0/netbox_inventree_sync/api/serializers.py +253 -0
  8. netbox_inventree_sync-0.1.0/netbox_inventree_sync/api/urls.py +25 -0
  9. netbox_inventree_sync-0.1.0/netbox_inventree_sync/api/views.py +185 -0
  10. netbox_inventree_sync-0.1.0/netbox_inventree_sync/choices.py +28 -0
  11. netbox_inventree_sync-0.1.0/netbox_inventree_sync/filtersets.py +104 -0
  12. netbox_inventree_sync-0.1.0/netbox_inventree_sync/forms.py +194 -0
  13. netbox_inventree_sync-0.1.0/netbox_inventree_sync/graphql/__init__.py +18 -0
  14. netbox_inventree_sync-0.1.0/netbox_inventree_sync/graphql/filters.py +31 -0
  15. netbox_inventree_sync-0.1.0/netbox_inventree_sync/graphql/schema.py +19 -0
  16. netbox_inventree_sync-0.1.0/netbox_inventree_sync/graphql/types.py +51 -0
  17. netbox_inventree_sync-0.1.0/netbox_inventree_sync/jobs.py +114 -0
  18. netbox_inventree_sync-0.1.0/netbox_inventree_sync/management/__init__.py +0 -0
  19. netbox_inventree_sync-0.1.0/netbox_inventree_sync/management/commands/__init__.py +0 -0
  20. netbox_inventree_sync-0.1.0/netbox_inventree_sync/management/commands/inventree_sync.py +167 -0
  21. netbox_inventree_sync-0.1.0/netbox_inventree_sync/management/commands/seed_starter_mappings.py +198 -0
  22. netbox_inventree_sync-0.1.0/netbox_inventree_sync/migrations/0001_initial.py +140 -0
  23. netbox_inventree_sync-0.1.0/netbox_inventree_sync/migrations/0002_field_validators_and_help_text.py +17 -0
  24. netbox_inventree_sync-0.1.0/netbox_inventree_sync/migrations/__init__.py +0 -0
  25. netbox_inventree_sync-0.1.0/netbox_inventree_sync/models.py +310 -0
  26. netbox_inventree_sync-0.1.0/netbox_inventree_sync/navigation.py +51 -0
  27. netbox_inventree_sync-0.1.0/netbox_inventree_sync/search.py +37 -0
  28. netbox_inventree_sync-0.1.0/netbox_inventree_sync/signals.py +258 -0
  29. netbox_inventree_sync-0.1.0/netbox_inventree_sync/sync/__init__.py +13 -0
  30. netbox_inventree_sync-0.1.0/netbox_inventree_sync/sync/client.py +237 -0
  31. netbox_inventree_sync-0.1.0/netbox_inventree_sync/sync/compatibility.py +60 -0
  32. netbox_inventree_sync-0.1.0/netbox_inventree_sync/sync/engine.py +671 -0
  33. netbox_inventree_sync-0.1.0/netbox_inventree_sync/sync/fields.py +203 -0
  34. netbox_inventree_sync-0.1.0/netbox_inventree_sync/sync/payload.py +47 -0
  35. netbox_inventree_sync-0.1.0/netbox_inventree_sync/sync/validation.py +295 -0
  36. netbox_inventree_sync-0.1.0/netbox_inventree_sync/tables.py +322 -0
  37. netbox_inventree_sync-0.1.0/netbox_inventree_sync/template_content.py +102 -0
  38. netbox_inventree_sync-0.1.0/netbox_inventree_sync/tests/__init__.py +0 -0
  39. netbox_inventree_sync-0.1.0/netbox_inventree_sync/tests/test_api.py +589 -0
  40. netbox_inventree_sync-0.1.0/netbox_inventree_sync/tests/test_builder_ui.py +264 -0
  41. netbox_inventree_sync-0.1.0/netbox_inventree_sync/tests/test_client.py +377 -0
  42. netbox_inventree_sync-0.1.0/netbox_inventree_sync/tests/test_compatibility.py +158 -0
  43. netbox_inventree_sync-0.1.0/netbox_inventree_sync/tests/test_engine.py +452 -0
  44. netbox_inventree_sync-0.1.0/netbox_inventree_sync/tests/test_extras.py +285 -0
  45. netbox_inventree_sync-0.1.0/netbox_inventree_sync/tests/test_fields.py +106 -0
  46. netbox_inventree_sync-0.1.0/netbox_inventree_sync/tests/test_jobs.py +470 -0
  47. netbox_inventree_sync-0.1.0/netbox_inventree_sync/tests/test_models.py +241 -0
  48. netbox_inventree_sync-0.1.0/netbox_inventree_sync/tests/test_pointer_resolution.py +624 -0
  49. netbox_inventree_sync-0.1.0/netbox_inventree_sync/tests/test_ui.py +531 -0
  50. netbox_inventree_sync-0.1.0/netbox_inventree_sync/tests/test_validation.py +382 -0
  51. netbox_inventree_sync-0.1.0/netbox_inventree_sync/urls.py +33 -0
  52. netbox_inventree_sync-0.1.0/netbox_inventree_sync/views.py +630 -0
  53. netbox_inventree_sync-0.1.0/netbox_inventree_sync.egg-info/PKG-INFO +356 -0
  54. netbox_inventree_sync-0.1.0/netbox_inventree_sync.egg-info/SOURCES.txt +57 -0
  55. netbox_inventree_sync-0.1.0/netbox_inventree_sync.egg-info/dependency_links.txt +1 -0
  56. netbox_inventree_sync-0.1.0/netbox_inventree_sync.egg-info/requires.txt +5 -0
  57. netbox_inventree_sync-0.1.0/netbox_inventree_sync.egg-info/top_level.txt +1 -0
  58. netbox_inventree_sync-0.1.0/pyproject.toml +36 -0
  59. netbox_inventree_sync-0.1.0/setup.cfg +4 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Eduardo Soares
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,356 @@
1
+ Metadata-Version: 2.4
2
+ Name: netbox-inventree-sync
3
+ Version: 0.1.0
4
+ Summary: Synchronize NetBox inventory data to InvenTree
5
+ Author-email: Eduardo Soares <edurbs@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/edurbs/netbox-inventree-sync
8
+ Project-URL: Documentation, https://github.com/edurbs/netbox-inventree-sync/tree/main/docs
9
+ Project-URL: Changelog, https://github.com/edurbs/netbox-inventree-sync/releases
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: System Administrators
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Topic :: System :: Systems Administration
15
+ Requires-Python: >=3.12
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: requests
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest; extra == "dev"
21
+ Requires-Dist: responses; extra == "dev"
22
+ Dynamic: license-file
23
+
24
+ # netbox-inventree-sync
25
+
26
+ A NetBox plugin that synchronizes NetBox inventory data to
27
+ [InvenTree](https://inventree.org).
28
+
29
+ NetBox is the source of truth: mapped objects are pushed to InvenTree on
30
+ every change (create/update via a background job, delete via remote
31
+ deactivation — InvenTree objects are never deleted), and a recurring
32
+ reconcile pass re-verifies every link against the live InvenTree state and
33
+ repairs drift. Mappings pair NetBox fields with InvenTree endpoint fields
34
+ through a type-compatibility matrix, with pointer→related pairs resolving
35
+ depth-first through pairing mappings (e.g. Inventory Item Role → Part
36
+ Category before the part that references it).
37
+
38
+ ## Development environment
39
+
40
+ One-time setup:
41
+
42
+ ```bash
43
+ ./scripts/setup_netbox.sh # clone NetBox v4.7.4, build netbox/venv, migrate, seed admin+token, install this plugin
44
+ ./scripts/setup_inventree.sh # InvenTree 1.7 stack (docker compose), seed admin+token
45
+ ```
46
+
47
+ Daily start (idempotent — re-running restarts the detached processes and
48
+ picks up code changes):
49
+
50
+ ```bash
51
+ ./scripts/start.sh # docker compose up -d + NetBox runserver + rqworker (supervised, logs under /tmp/opencode/netbox-inventree-sync/)
52
+ ```
53
+
54
+ After that:
55
+
56
+ - NetBox at <http://localhost:8000> (admin / admin); its API token is
57
+ written to `.env` as `NETBOX_TOKEN`.
58
+ - InvenTree at <http://localhost:1337>; its API token is written to `.env`
59
+ as `INVENTREE_TOKEN`.
60
+ - The RQ worker must be running for signal-driven syncs and reconciles
61
+ (`start.sh` starts it; check `/api/core/background-workers/`).
62
+
63
+ Requires: Python 3.12 (a uv-managed install works — see
64
+ `scripts/setup_netbox.sh`), Docker with compose v2.
65
+
66
+ ## Installing into a running production environment
67
+
68
+ The development setup above builds a throwaway stack. This section is for
69
+ adding the plugin to NetBox and InvenTree installations that already run
70
+ with real data.
71
+
72
+ **What the plugin touches — and what it never touches:**
73
+
74
+ - In NetBox, the plugin creates **only its own tables**
75
+ (`netbox_inventree_sync_*`: connections, mappings, field pairs, the
76
+ link table, the sync log). It never modifies, migrates or deletes any
77
+ existing NetBox table, and it never writes to NetBox objects — the
78
+ engine only *reads* mapped objects.
79
+ - InvenTree is contacted **exclusively through its REST API** with a
80
+ token you configure. The plugin never connects to InvenTree's database.
81
+ - The InvenTree side is never deleted from: removing a NetBox object
82
+ *deactivates* its remote counterpart. Existing InvenTree parts are
83
+ adopted through match keys only when the match is unambiguous
84
+ (`name`→`name` by default); anything ambiguous or blank is flagged for
85
+ manual review and left untouched.
86
+
87
+ Consequently, installing — or removing — the plugin cannot lose data in
88
+ either system. Still, take a standard backup before any production
89
+ change (`pg_dump` of the NetBox database at minimum).
90
+
91
+ Steps:
92
+
93
+ 1. **Backup** — `pg_dump` the NetBox database (and InvenTree's, if you
94
+ want the extra comfort).
95
+ 2. **Create an InvenTree API token** for a dedicated service user with
96
+ write access limited to what you plan to sync (parts, companies,
97
+ categories). The token is stored in NetBox's database (plaintext at
98
+ rest, write-only over the API — treat your DB backups accordingly).
99
+ 3. **Install the package into NetBox's Python environment** (the same
100
+ virtualenv/containers that run NetBox):
101
+
102
+ ```bash
103
+ pip install netbox-inventree-sync
104
+ ```
105
+
106
+ To track the project's development instead of a PyPI release, install
107
+ from the repository directly:
108
+ `pip install git+https://github.com/edurbs/netbox-inventree-sync.git`.
109
+
110
+ For containerized NetBox (e.g. netbox-docker), install the package
111
+ inside the image build (a custom `Dockerfile` extending the official
112
+ image with the `pip install` above) so it survives recreation.
113
+ 4. **Enable the plugin** in `configuration.py` (no plugin settings are
114
+ required):
115
+
116
+ ```python
117
+ PLUGINS = ['netbox_inventree_sync']
118
+ ```
119
+
120
+ 5. **Migrate and collect static files** — this only creates the plugin's
121
+ own tables:
122
+
123
+ ```bash
124
+ python manage.py migrate
125
+ python manage.py collectstatic --no-input
126
+ ```
127
+
128
+ 6. **Restart every NetBox process — including the RQ worker(s)**. The
129
+ web processes serve the plugin's UI; the workers execute the sync
130
+ jobs. A worker that was not restarted will not know the plugin
131
+ exists.
132
+ 7. **Roll out gradually**: create the connection, run
133
+ `seed_starter_mappings --connection <name> --validate` (everything is
134
+ created *disabled*), review the pairs in the builder, then enable one
135
+ mapping and watch *Synced Objects* / *Sync Log*. Be aware of the
136
+ first-reconcile note below: enabling a mapping publishes every
137
+ mapped-but-unlinked NetBox object, so on a large catalog the first
138
+ pass is long.
139
+
140
+ **Rollback / removal:** disable all mappings (this cancels their
141
+ recurring schedules and stops event-driven pushes), remove the plugin
142
+ from `PLUGINS`, restart the processes. Optionally drop the plugin's
143
+ tables or simply delete its rows — no NetBox inventory data is involved.
144
+ InvenTree keeps whatever was synced (deactivated items stay
145
+ deactivated); simply delete or reactivate them there if you retire the
146
+ integration.
147
+
148
+ ## Usage walkthrough
149
+
150
+ 1. **Create a connection** — *Plugins → InvenTree Sync → InvenTree
151
+ Instances → Add*: base URL (e.g. `http://localhost:1337`) and an API
152
+ token of a InvenTree user with write access. The token is stored
153
+ server-side and never returned by the API. The edit form offers a
154
+ *Test connection* probe (the token field stays blank on edit —
155
+ leaving it blank keeps the stored token):
156
+
157
+ ![NetBox: connection edit form with the Test connection button](docs/screenshots/netbox-connection-form.png)
158
+
159
+ 2. **Seed the starter mappings** (or add mappings by hand):
160
+
161
+ ```bash
162
+ netbox/venv/bin/python netbox/netbox/manage.py seed_starter_mappings --connection <id-or-name> --validate
163
+ ```
164
+
165
+ This creates three *disabled* mappings: Inventory Item → `/api/part/`
166
+ (name→name, part_id→IPN, description→description,
167
+ `manufacturer.name`→keywords), Manufacturer → `/api/company/`, and
168
+ Inventory Item Role → `/api/part/category/`, each with name→name as
169
+ its match (adopt) key. `--validate` checks every pair against the
170
+ live InvenTree field metadata. After seeding, the Mappings list shows
171
+ all three (✔/✗ in the *Enabled* column):
172
+
173
+ ![NetBox: the seeded starter mappings, all disabled except one](docs/screenshots/netbox-seeded-mappings.png)
174
+
175
+ 3. **Enable a mapping** — edit it in the UI (or `PATCH .../mappings/<id>/`
176
+ `{"enabled": true}`). Enabling schedules a recurring reconcile job at
177
+ the mapping's `reconcile_interval_minutes` (default 60); the interval
178
+ schedule is replaced whenever the mapping is saved with a new interval
179
+ and removed when the mapping is disabled:
180
+
181
+ ![NetBox: mapping edit form with the Enabled checkbox](docs/screenshots/netbox-mapping-enable.png)
182
+
183
+ 4. **Open the mapping builder** — the *Field pairs* tab of a mapping
184
+ renders both field lists (NetBox content-type fields incl. custom
185
+ fields and tags; the InvenTree endpoint's writable fields) with
186
+ incompatible pairings greyed out. Saving validates server-side
187
+ through the same compatibility gate as the REST API:
188
+
189
+ ![NetBox: the field-pair builder with both field lists](docs/screenshots/netbox-mapping-builder.png)
190
+
191
+ 5. **Sync now** — the *Sync now* button on a mapping (or
192
+ `POST /api/plugins/netbox_inventree_sync/mappings/<id>/sync/`)
193
+ enqueues a one-shot reconcile in addition to the recurring schedule.
194
+ This works on *disabled* mappings too (deliberate): the action runs
195
+ regardless of the `enabled` flag, so a mapping can be exercised once
196
+ before its schedule and event-driven pushes are turned on:
197
+
198
+ ![NetBox: mapping detail page with the Sync now button](docs/screenshots/netbox-sync-now.png)
199
+
200
+ From then on, saving a mapped NetBox object enqueues a push, and deleting
201
+ one deactivates (never deletes) the remote counterpart. Status per object:
202
+ *Plugins → InvenTree Sync → Synced Objects*; every push attempt is logged
203
+ in *Sync Log*.
204
+
205
+ ## Seeing it in action
206
+
207
+ The screenshots below show how the application works, taken from the
208
+ live dev stack. First, the mapping's **field-pair builder**: NetBox
209
+ fields on the left, the InvenTree endpoint's fields on the right, linked
210
+ pairs with type badges — and options whose types don't accept the
211
+ selected NetBox field are greyed out (the helper line under the selects
212
+ says so; the server enforces it on save). This example is the starter
213
+ Inventory Item → Part mapping (name→name, part_id→IPN,
214
+ description→description, and the manufacturer pointer rendered as text
215
+ into keywords):
216
+
217
+ ![NetBox: the field-pair builder with linked pairs and type badges](docs/screenshots/netbox-mapping-builder.png)
218
+
219
+ Next, one complete round trip of a sync under the Inventory Item → Part
220
+ mapping (starter field pairs: name→name, part_id→IPN,
221
+ description→description, `manufacturer.name`→keywords).
222
+
223
+ **1. The modification is made in the NetBox UI** — editing the
224
+ `Demo SFP+ 10G` inventory item and changing its *Description* to
225
+ "Transceptor SFP+ 10G, 850nm — alcance 300m em OM3 (revisado no NetBox)":
226
+
227
+ ![NetBox: editing an inventory item's description](docs/screenshots/netbox-edit-inventory-item.png)
228
+
229
+ **2. Saving enqueues the push** — the object's detail page now shows the
230
+ *InvenTree* panel (added by the plugin) with the link's status: the part
231
+ was pushed and is *Synced*, with the InvenTree object (`Part #83`) one
232
+ click away:
233
+
234
+ ![NetBox: object detail with the InvenTree sync panel showing Synced](docs/screenshots/netbox-sync-panel.png)
235
+
236
+ **3. The change is reflected in the InvenTree UI** — opening that part in
237
+ InvenTree shows the description exactly as saved in NetBox (and the other
238
+ mapped fields: IPN, name, and keywords carrying the manufacturer name).
239
+ No one touched InvenTree — the background job pushed the edit within
240
+ seconds of the save:
241
+
242
+ ![InvenTree: the part page showing the updated description](docs/screenshots/inventree-part-updated.png)
243
+
244
+ The same happens on create (a new mapped object publishes a new InvenTree
245
+ part) and on delete (the InvenTree object is deactivated, never deleted);
246
+ manual edits made directly in InvenTree are overwritten by the next push
247
+ or reconcile, since NetBox is the source of truth.
248
+
249
+ Every link is visible under *Plugins → InvenTree Sync → Synced Objects*,
250
+ with per-object status, the InvenTree counterpart one click away, and the
251
+ last error (if any) — here showing green *Synced* rows alongside orange
252
+ *Orphaned* ones (links whose NetBox object was deleted):
253
+
254
+ ![NetBox: the Synced Objects list with status badges](docs/screenshots/netbox-synced-objects.png)
255
+
256
+
257
+ > **Sync log retention**: `SyncLogEntry` grows unboundedly — one row per
258
+ > push attempt, reconcile included. There is no automatic retention in
259
+ > v1; prune old rows manually if the table grows too large
260
+ > (e.g. `SyncLogEntry.objects.filter(created__lt=...)` in a shell).
261
+
262
+ ### Deterministic sync from the CLI
263
+
264
+ The `inventree_sync` management command runs the production job classes
265
+ inline (no worker round-trip) — the E2E determinism tool:
266
+
267
+ ```bash
268
+ netbox/venv/bin/python netbox/netbox/manage.py inventree_sync --mapping '<name>' # every pending/failed link
269
+ netbox/venv/bin/python netbox/netbox/manage.py inventree_sync --mapping '<name>' --object dcim.inventoryitem:42
270
+ netbox/venv/bin/python netbox/netbox/manage.py inventree_sync --mapping '<name>' --reconcile
271
+ ```
272
+
273
+ Exit code 1 when any processed object ended `failed`.
274
+
275
+ ### Reconcile intervals
276
+
277
+ Each enabled mapping carries `reconcile_interval_minutes` (default 60).
278
+ The recurring `ReconcileJob` authoritatively re-verifies every synced
279
+ link (drift in InvenTree is overwritten, vanished remotes re-created),
280
+ retries failed links, publishes unlinked NetBox objects through the
281
+ mapping's match/adopt policy, and orphans links whose NetBox object is
282
+ gone. Keep the interval short for busy catalogs (each pass GETs every
283
+ linked remote object).
284
+
285
+ Note on scale: the **first** reconcile after a mapping starts working
286
+ publishes every mapped NetBox object that has no link yet — on a large
287
+ catalog that is one InvenTree create per object, so expect a long first
288
+ pass (and a correspondingly large first-pass sync log).
289
+
290
+ ## Running plugin tests
291
+
292
+ Unit suite (Django test runner, own database; hermetic — InvenTree is
293
+ stubbed):
294
+
295
+ ```bash
296
+ NETBOX_CONFIGURATION=netbox.configuration_test \
297
+ netbox/venv/bin/python netbox/netbox/manage.py test netbox_inventree_sync -v 1 --keepdb --noinput
298
+ ```
299
+
300
+ `setup_netbox.sh` provisions `netbox/netbox/netbox/configuration_test.py`
301
+ for this: it mirrors the dev config but disables `DEBUG`, so the Django
302
+ debug toolbar is not installed (with `DEBUG = True` every `manage.py test`
303
+ run fails at the `debug_toolbar.E001` system check before any test
304
+ executes).
305
+
306
+ E2E suite (pytest, `tests/e2e/`) against the **live** pair — prerequisites:
307
+ the full stack from `./scripts/start.sh` (runserver *and* rqworker) plus
308
+ the InvenTree containers, and `NETBOX_TOKEN` / `INVENTREE_TOKEN` in `.env`
309
+ (both written by the setup scripts):
310
+
311
+ ```bash
312
+ cd netbox && ./venv/bin/python -m pytest ../tests/e2e -v
313
+ ```
314
+
315
+ URLs/tokens can be overridden with `NETBOX_URL`, `NETBOX_TOKEN`,
316
+ `INVENTREE_URL`, `INVENTREE_TOKEN` environment variables. Every test
317
+ cleans up what it created in both systems (engine-created InvenTree
318
+ objects included) and isolates itself with unique `e2e-<run>` name
319
+ prefixes, so the suite can be re-run back-to-back. One scenario stops and
320
+ restarts the `inventree-web` compose service (~90 s); the async-path
321
+ scenario needs the RQ worker. Expect a full run to take 3–4 minutes
322
+ (each deterministic sync boots Django once).
323
+
324
+ ## Troubleshooting
325
+
326
+ - **Ports**: NetBox dev server on :8000, InvenTree on :1337, NetBox
327
+ Postgres on :15432 and Redis on :16379 (InvenTree's own Postgres/Redis
328
+ are not published). `docker compose ps` shows the backing services.
329
+ - **Tokens**: both API tokens live in `.env` (written by the setup
330
+ scripts). The plugin connection stores its own copy of the InvenTree
331
+ token; if you regenerate the InvenTree token, update the connection.
332
+ - **"Jobs cannot be assigned to this object type (… Sync Mapping)"** when
333
+ enabling a mapping right after a code update: NetBox caches each
334
+ model's supported features in the `core_objecttype` table, refreshed
335
+ only by the `post_migrate` signal. Run
336
+ `netbox/venv/bin/python netbox/netbox/manage.py migrate` once (a no-op
337
+ migrate is enough) to refresh it.
338
+ - **Worker**: signal-driven syncs and reconciles need the rqworker
339
+ (`./scripts/start.sh`; verify via `/api/core/background-workers/`).
340
+ Without it, changes only sync on the next `inventree_sync` run or
341
+ reconcile.
342
+ - **A mapping's field pairs don't validate**: `POST /mappings/` and the
343
+ builder validate against the endpoint's live OPTIONS metadata; an
344
+ unreachable InvenTree fails the request (502 from the builder view)
345
+ rather than accepting an unvalidated mapping.
346
+
347
+ ## Support
348
+
349
+ Issues: https://github.com/edurbs/netbox-inventree-sync/issues
350
+
351
+ Before opening an issue, check [COMPATIBILITY.md](COMPATIBILITY.md) for
352
+ the supported NetBox / InvenTree / Python version matrix.
353
+
354
+ ## License
355
+
356
+ Released under the MIT license — see [LICENSE](LICENSE).