Skip to content

feat(api): bulk-create endpoints for 5 direct-compId entities (P3-H)#81

Merged
CryptoJones merged 1 commit into
masterfrom
feat/bulk-direct-compid
May 18, 2026
Merged

feat(api): bulk-create endpoints for 5 direct-compId entities (P3-H)#81
CryptoJones merged 1 commit into
masterfrom
feat/bulk-direct-compid

Conversation

@CryptoJones
Copy link
Copy Markdown
Owner

Part of architect audit issue #73 — iteration P3-H.

Summary

  • New POST /v1/<entity>/bulk on Worker, BillingType, InventoryItem, InventoryTransaction, PurchaseOrderVendor.
  • Mirrors POST /v1/customer/bulk: 500-entry cap, zod-strict whitelist, all-or-nothing transactional insert, per-entry master/non-master scoping.
  • Shared app/controllers/_bulk-helpers.js#makeBulkCreate factory keeps the five controllers ~10 LOC each instead of ~80.
  • Customer's pre-existing bulkCreate left alone for now — unification is a mechanical follow-up.
  • /bulk routes mounted BEFORE /:id so 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.
  • Full suite: 357 pass / 4 skip (was 327/4).
  • Integration coverage for transactional roll-back + master scoping waits on P5-M.

This code proudly made in Nebraska. GO BIG RED! 🌽 https://xkcd.com/2347/

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>
@CryptoJones CryptoJones merged commit e68b5bd into master May 18, 2026
3 checks passed
@CryptoJones CryptoJones deleted the feat/bulk-direct-compid branch May 18, 2026 04:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant