feat(api): bulk-create endpoints for 5 direct-compId entities (P3-H)#81
Merged
Conversation
Architect audit P3-H. New `POST /v1/<entity>/bulk` on: - Worker (workerCompId) - BillingType (btCompId) - InventoryItem (invitCompId) - InventoryTransaction (invtCompanyId) - PurchaseOrderVendor (povCompId) Mirrors the shape of `POST /v1/customer/bulk` that's been in the API since the initial port: 500-entry cap, zod-strict whitelist, all-or- nothing transactional insert, master vs. non-master scoping enforced per entry (master keys MUST specify the compId column; non-master keys can omit it — it defaults to the authKey's owning company — or must match it if specified). Shared factory: `app/controllers/_bulk-helpers.js#makeBulkCreate` parameterizes over (Model, modelKey, compIdField, allowedFields, archField, bodyKey, createdKey). The 5 controllers gain ~10 lines each instead of ~80; the factory itself is ~95 LOC. Net delta: roughly +150 lines, vs. ~+400 lines if we'd hand-rolled all five. Customer's pre-existing `bulkCreate` is left alone for this PR — unifying it with the factory is a mechanical follow-up and a separate risk surface. Route order: each `/bulk` route is mounted BEFORE its `/:id` siblings so Express's matcher doesn't route the literal "bulk" segment through the :id-typed validator. Same trick as `/v1/customer/bulk` and `/v1/customer/export.csv`. Tests - `tests/api/bulk-direct-compid.test.js` (30 cases): 5 entities x 6 assertions covering auth contract, missing-outer-field 400, empty-array 400, 501-entry-cap 400, unknown-top-level-field 400, and route mounting (not 404). - Full suite: 357 pass / 4 skip (was 327/4). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of architect audit issue #73 — iteration P3-H.
Summary
POST /v1/<entity>/bulkon Worker, BillingType, InventoryItem, InventoryTransaction, PurchaseOrderVendor.POST /v1/customer/bulk: 500-entry cap, zod-strict whitelist, all-or-nothing transactional insert, per-entry master/non-master scoping.app/controllers/_bulk-helpers.js#makeBulkCreatefactory keeps the five controllers ~10 LOC each instead of ~80.bulkCreateleft alone for now — unification is a mechanical follow-up./bulkroutes mounted BEFORE/:idso Express doesn't match "bulk" as :id.Test plan
tests/api/bulk-direct-compid.test.js(30 cases): auth contract, missing/empty/501-cap/unknown-field 400s, route mounting.This code proudly made in Nebraska. GO BIG RED! 🌽 https://xkcd.com/2347/