@spinekit/manufacturing
The arc composition wrapper over
the @classytic/manufacturing
kernel — bills of material and work orders as one arc module.
The kernel carries the hard parts and this package exposes them: immutable BOM
revisions (only draft is editable — the kernel fences active/superseded/
archived at the data layer), the work-order FSM
(draft → planned → released → in_progress → completed | cancelled), the
CAS-first stock saga (pendingStock stamp + healPendingStock crash
re-fire), and the append-only production ledger. Reads are adapter-backed;
every write routes through a kernel domain verb.
Install
npm i @spinekit/manufacturing @classytic/manufacturing @classytic/arc
Peers: @classytic/arc (>=2.23), @classytic/manufacturing (0.5.x),
@classytic/mongokit, @classytic/primitives, mongoose, zod.
Compose
import { createApp } from '@classytic/arc/factory';
import { createManufacturingModule } from '@spinekit/manufacturing';
import { requireRoles } from '@classytic/arc/permissions';
const app = await createApp({
modules: [
createManufacturingModule({
connection: mongoose.connection,
permissions: {
view: requireRoles(['inventory_staff', 'branch_manager']),
manage: requireRoles(['branch_manager']),
},
bridges: { stock: flowStockAdapter }, // optional WMS back-end
eventTransport, // optional — kernel publishes here
}),
],
});
// Layer-2 export for cross-module wiring (cost posting, heal sweeps):
const engine = app.arc.modules.manufacturing;
The module constructs the kernel with defineManufacturing(shape).bind(connection, runtime)
— shape = tenant / modules / autoIndex; runtime = bridges /
eventTransport / outbox. bind is SYNCHRONOUS (the capability assertion runs
in-line); bootstrap stays async only so a host may pass the engine as an async
thunk. On a fresh database call ensureManufacturingReady(engine) once at
startup to materialise collections before the first transactional write.
Routes
Mounted under prefix (default /manufacturing):
| Method + path | Kernel verb | Notes |
|---|---|---|
GET /boms, GET /boms/:id |
adapter reads | filter productSku, status, type, isDefault |
POST /boms |
createBom |
head + first draft revision (one txn) |
POST /boms/:id/action create-revision |
createRevision |
direct / cloned / engineering change |
POST /boms/:id/action activate-revision |
activateRevision |
supersede + activate + repoint |
POST /boms/:id/action set-default |
setDefault |
exclusive per product |
POST /boms/:id/action archive |
archiveBom |
FSM exit (no DELETE) |
GET /bom-revisions, GET /bom-revisions/:id |
adapter reads (read-only) | revision history; filter bomId, status |
GET /work-orders, GET /work-orders/:id |
adapter reads | filter status, productSku, bomId, reference |
POST /work-orders |
createWorkOrder |
by BOM head id or product SKU |
POST /work-orders/:id/action plan |
plan |
explode active revision |
POST /work-orders/:id/action release |
release |
reserve components (StockPort) |
POST /work-orders/:id/action start |
start |
→ in_progress |
POST /work-orders/:id/action complete |
complete |
consume + produce |
POST /work-orders/:id/action cancel |
cancel |
release reservations |
POST /work-orders/:id/action start-operation | complete-operation | skip-operation |
routed ops | { sequence } |
Tenancy
Tenancy defaults to organizationId (= branch, matching the commerce
convention); the arc resource tenantField derives to match. For a company-wide
deployment pass tenant: false and tenantField: false.
Host seams
- Stock — inject
bridges.stock(a@classytic/flowadapter) for closed-loop work orders. Absent ⇒ open-loop transitions, no inventory moves. - Accounting / cost — subscribe to the kernel's events on your
eventTransport. - Heal sweep — re-firing stranded
pendingStock(findStalePendingStock+healPendingStock) is a host cron/arm.
The acting user is always the authenticated principal (scopeFirstCtx), never
trusted from the request body.