@happyvertical/smrt-manufacturing 0.53.6 → 0.54.1
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.
- package/AGENTS.md +1 -2
- package/README.md +3 -4
- package/dist/index.js +1 -1
- package/dist/manifest.json +1 -2
- package/dist/smrt-knowledge.json +5 -7
- package/dist/svelte/components/AssemblyForm.svelte +423 -52
- package/dist/svelte/components/AssemblyForm.svelte.d.ts +17 -32
- package/dist/svelte/components/AssemblyForm.svelte.d.ts.map +1 -1
- package/dist/svelte/components/AssemblyList.svelte +18 -12
- package/dist/svelte/components/AssemblyList.svelte.d.ts +2 -13
- package/dist/svelte/components/AssemblyList.svelte.d.ts.map +1 -1
- package/dist/svelte/i18n.d.ts +23 -0
- package/dist/svelte/i18n.d.ts.map +1 -1
- package/dist/svelte/i18n.js +23 -0
- package/dist/svelte/index.d.ts +4 -4
- package/dist/svelte/index.d.ts.map +1 -1
- package/dist/svelte/index.js +4 -4
- package/dist/svelte/types.d.ts +95 -0
- package/dist/svelte/types.d.ts.map +1 -1
- package/dist/svelte/types.js +127 -0
- package/package.json +8 -9
package/AGENTS.md
CHANGED
|
@@ -52,7 +52,7 @@ Detail: [agents/multilevel-and-runs.md](agents/multilevel-and-runs.md).
|
|
|
52
52
|
|
|
53
53
|
## Svelte components (`./svelte`)
|
|
54
54
|
|
|
55
|
-
Props-driven; the host loads and persists. `AssemblyList` (
|
|
55
|
+
Props-driven; the host loads and persists. `AssemblyList` (a structural `policy` drops hidden columns), `AssemblyForm` (smrt-ui controls like `OperationForm`: `assembly`, `onsubmit`, `operations` for the default-operation picker, a retired or unlisted current operation stays selected and marked, `hiddenFields`/`readonlyFields` for the reader's field policy; price is major units in the form and integer minor units in `onsubmit`; `validateAssemblyForm` mirrors the model's whole-minutes rule). `smrt-fields` is not a dependency: never add `ObjectForm`, `BomEditor` (add/edit/remove lines through host handlers; a sub-assembly shows whether it has its own bill and expands read-only through `loadBill`), `BomStructureTree` (the read-only nested view). `ProductionRunList` (progress, status, and with `oncomplete` a quantity field per open run; rows from `toProductionRunView`), `RequirementsTree` (read-only `explode` / `planRequirements` result by level with totals; `toRequirementTree`, `toRequirementTotals`; internal `RequirementsTreeLevel`). Adapters: `toAssemblyView`, `toBomEditorLines`. Strings are under `manufacturing.` in `src/svelte/i18n.ts`; the package is strict for raw primitives, hardcoded strings and JSDoc.
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
## BomService — planning helpers
|
|
@@ -202,7 +202,6 @@ These join cleanly with the standard inventory reason codes (`receipt`, `reserva
|
|
|
202
202
|
| `@happyvertical/smrt-core` | SmrtObject / SmrtCollection / DispatchBus |
|
|
203
203
|
| `@happyvertical/smrt-inventory` | StockService, stock levels, movements (the `Sku` model itself lives in `@happyvertical/smrt-products`; inventory tracks stock motion against the id) |
|
|
204
204
|
| `@happyvertical/smrt-products` | `Product` (the `Assembly` STI base), `Material`, `Sku` for the resolve helper and cycle check |
|
|
205
|
-
| `@happyvertical/smrt-fields` | `ObjectForm` and field-policy column visibility for the Svelte components |
|
|
206
205
|
| `@happyvertical/smrt-ui` / `smrt-types` | Svelte controls, i18n, module UI slots |
|
|
207
206
|
| `@happyvertical/smrt-tenancy` | Optional tenant scoping |
|
|
208
207
|
| `@happyvertical/sql` | Database adapter |
|
package/README.md
CHANGED
|
@@ -348,17 +348,17 @@ Per-handler toggles (`installProductionPosted`, `installProductionCompleted`) le
|
|
|
348
348
|
toRequirementTree,
|
|
349
349
|
} from '@happyvertical/smrt-manufacturing/svelte';
|
|
350
350
|
|
|
351
|
-
let { assemblies, policy,
|
|
351
|
+
let { assemblies, policy, assembly, operations, lines, components, runs, plan } = $props();
|
|
352
352
|
</script>
|
|
353
353
|
|
|
354
354
|
<AssemblyList {assemblies} {policy} onselect={(id) => goto(`/assemblies/${id}`)} />
|
|
355
|
-
<AssemblyForm {
|
|
355
|
+
<AssemblyForm {assembly} {operations} hiddenFields={['price']} onsubmit={save} />
|
|
356
356
|
<BomEditor {lines} {components} onadd={addLine} loadBill={loadLines} error={saveError} />
|
|
357
357
|
<ProductionRunList {runs} oncomplete={(runId, qty) => report(runId, qty)} />
|
|
358
358
|
<RequirementsTree lines={toRequirementTree(plan)} totals={toRequirementTotals(plan)} />
|
|
359
359
|
```
|
|
360
360
|
|
|
361
|
-
`AssemblyList` and `AssemblyForm`
|
|
361
|
+
`AssemblyList` takes the resolved field `policy` for Assembly and drops the columns it hides (a hidden price is not shown). `AssemblyForm` is a plain form on smrt-ui controls: name, description, category, part reference, price (typed in major units, checked against the `currency` prop's minor-unit exponent, handed over as integer minor units; a field the reader leaves untouched keeps its stored value exactly), estimated labour (whole minutes, zero or more), a default-operation picker over the `operations` you pass (pass the active ones; a retired or unlisted current operation stays selected, marked, and can be cleared) and tags. Pass the `assembly` being edited (omit to add), and map the reader's field policy onto `hiddenFields` (not rendered) and `readonlyFields` (shown, not editable); both carry their initial value through `onsubmit` unchanged, so save only what the reader may write. `onsubmit` receives checked values and the form never persists. Build rows with `toAssemblyView` and editor lines with `toBomEditorLines(await assemblyService.getBillStructure(bomId))`. A sub-assembly line in `BomEditor` says whether it has its own bill and expands read-only through `loadBill`. `ProductionRunList` shows each run's progress and status and, with `oncomplete`, a field to report finished units (rows from `toProductionRunView`). `RequirementsTree` shows an `explode` or `planRequirements` result by level, with available and short per line for a plan.
|
|
362
362
|
|
|
363
363
|
## API
|
|
364
364
|
|
|
@@ -437,7 +437,6 @@ Per-handler toggles (`installProductionPosted`, `installProductionCompleted`) le
|
|
|
437
437
|
| `@happyvertical/smrt-core` | SmrtObject / SmrtCollection / DispatchBus |
|
|
438
438
|
| `@happyvertical/smrt-inventory` | StockService (consume / produce target) |
|
|
439
439
|
| `@happyvertical/smrt-products` | `Product` (base of `Assembly`), `Material`, `Sku` |
|
|
440
|
-
| `@happyvertical/smrt-fields` | `ObjectForm` and field-policy columns for the Svelte components |
|
|
441
440
|
| `@happyvertical/smrt-ui` | Svelte controls and i18n |
|
|
442
441
|
| `@happyvertical/smrt-tenancy` | Optional tenant scoping |
|
|
443
442
|
| `@happyvertical/smrt-ui` / `@happyvertical/smrt-types` | Operation list and form (`./svelte`), module slots (`./ui`); `svelte` is an optional peer |
|
package/dist/index.js
CHANGED
|
@@ -18,7 +18,7 @@ var __exportAll = (all, no_symbols) => {
|
|
|
18
18
|
};
|
|
19
19
|
//#endregion
|
|
20
20
|
//#region src/__smrt-register__.ts
|
|
21
|
-
ObjectRegistry.registerPackageManifest(JSON.parse("{\"version\":\"1.0.0\",\"timestamp\":0,\"packageName\":\"@happyvertical/smrt-manufacturing\",\"packageVersion\":\"0.53.6\",\"objects\":{\"@happyvertical/smrt-manufacturing:BillOfMaterialsCollection\":{\"name\":\"billofmaterialscollection\",\"className\":\"BillOfMaterialsCollection\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:BillOfMaterialsCollection\",\"collection\":\"billofmaterialses\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/collections/BillOfMaterialsCollection.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{},\"methods\":{\"findByProduct\":{\"name\":\"findByProduct\",\"async\":true,\"parameters\":[{\"name\":\"productId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<BillOfMaterials[]>\",\"isStatic\":false,\"isPublic\":true},\"findActiveForProduct\":{\"name\":\"findActiveForProduct\",\"async\":true,\"parameters\":[{\"name\":\"productId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<BillOfMaterials | null>\",\"isStatic\":false,\"isPublic\":true},\"findByStatus\":{\"name\":\"findByStatus\",\"async\":true,\"parameters\":[{\"name\":\"status\",\"type\":\"BomStatus\",\"optional\":false}],\"returnType\":\"Promise<BillOfMaterials[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_boms\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"BillOfMaterials\",\"exportName\":\"BillOfMaterialsCollection\",\"collectionExportName\":\"BillOfMaterialsCollectionCollection\",\"schema\":{\"tableName\":\"manufacturing_boms\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_boms\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"product_id\\\" TEXT NOT NULL DEFAULT '',\\n \\\"version\\\" INTEGER NOT NULL DEFAULT 1,\\n \\\"effective_date\\\" TIMESTAMP,\\n \\\"status\\\" TEXT NOT NULL DEFAULT 'draft',\\n \\\"notes\\\" TEXT DEFAULT '',\\n \\\"currency\\\" TEXT DEFAULT 'USD'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"product_id\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"version\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":1},\"effective_date\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"draft\"},\"notes\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"currency\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"USD\"}},\"indexes\":[{\"name\":\"manufacturing_boms_product_id_version_idx\",\"columns\":[\"product_id\",\"version\",\"tenant_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_boms_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"manufacturing_boms_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"b2691adc\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:BomLineCollection\":{\"name\":\"bomlinecollection\",\"className\":\"BomLineCollection\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:BomLineCollection\",\"collection\":\"bomlines\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/collections/BomLineCollection.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{},\"methods\":{\"findByBom\":{\"name\":\"findByBom\",\"async\":true,\"parameters\":[{\"name\":\"bomId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<BomLine[]>\",\"isStatic\":false,\"isPublic\":true},\"findByComponent\":{\"name\":\"findByComponent\",\"async\":true,\"parameters\":[{\"name\":\"componentSkuId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<BomLine[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_bom_lines\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"BomLine\",\"exportName\":\"BomLineCollection\",\"collectionExportName\":\"BomLineCollectionCollection\",\"schema\":{\"tableName\":\"manufacturing_bom_lines\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_bom_lines\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"bom_id\\\" TEXT NOT NULL DEFAULT '',\\n \\\"component_sku_id\\\" TEXT NOT NULL DEFAULT '',\\n \\\"qty_per_unit\\\" REAL,\\n \\\"uom\\\" TEXT DEFAULT 'each',\\n \\\"waste_percent\\\" REAL,\\n \\\"notes\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"bom_id\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"component_sku_id\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"qty_per_unit\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"uom\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"each\"},\"waste_percent\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"notes\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"manufacturing_bom_lines_bom_id_component_sku_id_idx\",\"columns\":[\"bom_id\",\"component_sku_id\",\"tenant_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_bom_lines_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"manufacturing_bom_lines_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"cfbae7e8\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:OperationCollection\":{\"name\":\"operationcollection\",\"className\":\"OperationCollection\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:OperationCollection\",\"collection\":\"operations\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/collections/OperationCollection.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{},\"methods\":{\"findByCode\":{\"name\":\"findByCode\",\"async\":true,\"parameters\":[{\"name\":\"code\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Operation | null>\",\"isStatic\":false,\"isPublic\":true},\"listOperations\":{\"name\":\"listOperations\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"boolean\"]}],\"returnType\":\"Promise<Operation[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_operations\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"Operation\",\"exportName\":\"OperationCollection\",\"collectionExportName\":\"OperationCollectionCollection\",\"schema\":{\"tableName\":\"manufacturing_operations\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_operations\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"code\\\" TEXT NOT NULL DEFAULT '',\\n \\\"name\\\" TEXT NOT NULL DEFAULT '',\\n \\\"category\\\" TEXT DEFAULT '',\\n \\\"is_active\\\" BOOLEAN DEFAULT TRUE,\\n \\\"required_qualification_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"code\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"name\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"category\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"is_active\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":true},\"required_qualification_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"manufacturing_operations_code_tenant_id_idx\",\"columns\":[\"code\",\"tenant_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_operations_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"manufacturing_operations_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"manufacturing_operations_required_qualification_id_idx\",\"columns\":[\"required_qualification_id\"]}],\"version\":\"0b3134d6\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:ProductionRunCollection\":{\"name\":\"productionruncollection\",\"className\":\"ProductionRunCollection\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:ProductionRunCollection\",\"collection\":\"productionruns\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/collections/ProductionRunCollection.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{},\"methods\":{\"findByBom\":{\"name\":\"findByBom\",\"async\":true,\"parameters\":[{\"name\":\"bomId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ProductionRun[]>\",\"isStatic\":false,\"isPublic\":true},\"findByStatus\":{\"name\":\"findByStatus\",\"async\":true,\"parameters\":[{\"name\":\"status\",\"type\":\"ProductionRunStatus\",\"optional\":false}],\"returnType\":\"Promise<ProductionRun[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_production_runs\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ProductionRun\",\"exportName\":\"ProductionRunCollection\",\"collectionExportName\":\"ProductionRunCollectionCollection\",\"schema\":{\"tableName\":\"manufacturing_production_runs\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_production_runs\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"bom_id\\\" UUID NOT NULL,\\n \\\"target_qty\\\" REAL,\\n \\\"completed_qty\\\" REAL,\\n \\\"status\\\" TEXT NOT NULL DEFAULT 'planned'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"bom_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"manufacturing_boms\",\"column\":\"id\",\"onDelete\":\"RESTRICT\",\"onUpdate\":\"CASCADE\"}},\"target_qty\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"completed_qty\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"planned\"}},\"indexes\":[{\"name\":\"manufacturing_production_runs_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_production_runs_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"manufacturing_production_runs_bom_id_idx\",\"columns\":[\"bom_id\"]}],\"version\":\"2ca8147d\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:ProductionRunCompletionCollection\":{\"name\":\"productionruncompletioncollection\",\"className\":\"ProductionRunCompletionCollection\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:ProductionRunCompletionCollection\",\"collection\":\"productionruncompletions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/collections/ProductionRunCompletionCollection.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{},\"methods\":{\"findByRun\":{\"name\":\"findByRun\",\"async\":true,\"parameters\":[{\"name\":\"runId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ProductionRunCompletion[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_production_run_completions\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ProductionRunCompletion\",\"exportName\":\"ProductionRunCompletionCollection\",\"collectionExportName\":\"ProductionRunCompletionCollectionCollection\",\"schema\":{\"tableName\":\"manufacturing_production_run_completions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_production_run_completions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"run_id\\\" UUID NOT NULL,\\n \\\"qty\\\" REAL,\\n \\\"completed_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"run_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"manufacturing_production_runs\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"qty\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"completed_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"manufacturing_production_run_completions_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_production_run_completions_tenant_ea7a0d0125_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"manufacturing_production_run_completions_run_id_idx\",\"columns\":[\"run_id\"]}],\"version\":\"c940de6c\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:RoutingStepCollection\":{\"name\":\"routingstepcollection\",\"className\":\"RoutingStepCollection\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:RoutingStepCollection\",\"collection\":\"routingsteps\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/collections/RoutingStepCollection.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{},\"methods\":{\"findByBom\":{\"name\":\"findByBom\",\"async\":true,\"parameters\":[{\"name\":\"bomId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<RoutingStep[]>\",\"isStatic\":false,\"isPublic\":true},\"findByOperation\":{\"name\":\"findByOperation\",\"async\":true,\"parameters\":[{\"name\":\"operationId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<RoutingStep[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_routing_steps\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"RoutingStep\",\"exportName\":\"RoutingStepCollection\",\"collectionExportName\":\"RoutingStepCollectionCollection\",\"schema\":{\"tableName\":\"manufacturing_routing_steps\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_routing_steps\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"bom_id\\\" UUID NOT NULL,\\n \\\"operation_id\\\" UUID NOT NULL,\\n \\\"sequence\\\" INTEGER NOT NULL DEFAULT 1,\\n \\\"estimated_minutes\\\" REAL,\\n \\\"notes\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"bom_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"manufacturing_boms\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"operation_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"manufacturing_operations\",\"column\":\"id\",\"onDelete\":\"RESTRICT\",\"onUpdate\":\"CASCADE\"}},\"sequence\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":1},\"estimated_minutes\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"notes\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"manufacturing_routing_steps_bom_id_sequence_idx\",\"columns\":[\"bom_id\",\"sequence\",\"tenant_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_routing_steps_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"manufacturing_routing_steps_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"manufacturing_routing_steps_operation_id_idx\",\"columns\":[\"operation_id\"]}],\"version\":\"41ac3c66\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:Assembly\":{\"name\":\"assembly\",\"className\":\"Assembly\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:Assembly\",\"collection\":\"products\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/models/Assembly.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"generated\":true,\"source\":\"tenantScoped_decorator\",\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"autoFilter\":true,\"autoPopulate\":true,\"allowSuperAdminBypass\":false}}},\"productType\":{\"type\":\"json\",\"required\":false},\"name\":{\"type\":\"text\",\"required\":false},\"description\":{\"type\":\"text\",\"required\":false},\"category\":{\"type\":\"text\",\"required\":false},\"manufacturer\":{\"type\":\"text\",\"required\":false},\"model\":{\"type\":\"text\",\"required\":false},\"price\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"inStock\":{\"type\":\"boolean\",\"required\":true,\"default\":true},\"specifications\":{\"type\":\"json\",\"required\":false,\"default\":{}},\"tags\":{\"type\":\"json\",\"required\":false,\"default\":[]},\"estimatedLabourMinutes\":{\"type\":\"integer\",\"required\":false,\"default\":0},\"defaultOperationId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Operation\",\"_meta\":{\"nullable\":true,\"onDelete\":\"RESTRICT\"}},\"partReference\":{\"type\":\"text\",\"required\":false,\"default\":\"\"}},\"methods\":{\"getSpecification\":{\"name\":\"getSpecification\",\"async\":true,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<unknown>\",\"isStatic\":false,\"isPublic\":true},\"updateSpecification\":{\"name\":\"updateSpecification\",\"async\":true,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false},{\"name\":\"value\",\"type\":\"unknown\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getAssets\":{\"name\":\"getAssets\",\"async\":true,\"parameters\":[{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Asset[]>\",\"isStatic\":false,\"isPublic\":true},\"addAsset\":{\"name\":\"addAsset\",\"async\":true,\"parameters\":[{\"name\":\"asset\",\"type\":\"Asset\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"any\",\"optional\":true,\"default\":\"attachment\"},{\"name\":\"sortOrder\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"removeAsset\":{\"name\":\"removeAsset\",\"async\":true,\"parameters\":[{\"name\":\"assetId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"},\"tableName\":\"products\",\"tableStrategy\":\"sti\"},\"extends\":\"Product\",\"exportName\":\"Assembly\",\"collectionExportName\":\"AssemblyCollection\",\"validationRules\":[{\"field\":\"price\",\"rule\":\"required\",\"fieldType\":\"integer\"},{\"field\":\"inStock\",\"rule\":\"required\",\"fieldType\":\"boolean\"}],\"schema\":{\"tableName\":\"products\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"products\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"product_type\\\" TEXT,\\n \\\"name\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"category\\\" TEXT,\\n \\\"manufacturer\\\" TEXT,\\n \\\"model\\\" TEXT,\\n \\\"price\\\" INTEGER DEFAULT 0,\\n \\\"in_stock\\\" BOOLEAN DEFAULT TRUE,\\n \\\"specifications\\\" JSON DEFAULT '{}',\\n \\\"tags\\\" JSON DEFAULT '[]',\\n \\\"estimated_labour_minutes\\\" INTEGER DEFAULT 0,\\n \\\"default_operation_id\\\" UUID,\\n \\\"part_reference\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"product_type\":{\"type\":\"TEXT\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false},\"category\":{\"type\":\"TEXT\",\"notNull\":false},\"manufacturer\":{\"type\":\"TEXT\",\"notNull\":false},\"model\":{\"type\":\"TEXT\",\"notNull\":false},\"price\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":0},\"in_stock\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"default\":true},\"specifications\":{\"type\":\"JSON\",\"notNull\":false,\"default\":{}},\"tags\":{\"type\":\"JSON\",\"notNull\":false,\"default\":[]},\"estimated_labour_minutes\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":0},\"default_operation_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"manufacturing_operations\",\"column\":\"id\",\"onDelete\":\"RESTRICT\",\"onUpdate\":\"CASCADE\"}},\"part_reference\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"products_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"products_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"products_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"products_default_operation_id_idx\",\"columns\":[\"default_operation_id\"]}],\"version\":\"f2f2bf95\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:BillOfMaterials\":{\"name\":\"billofmaterials\",\"className\":\"BillOfMaterials\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:BillOfMaterials\",\"collection\":\"billofmaterialses\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/models/BillOfMaterials.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"productId\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"version\":{\"type\":\"integer\",\"required\":true,\"default\":1,\"_meta\":{\"required\":true}},\"effectiveDate\":{\"type\":\"datetime\",\"required\":false},\"status\":{\"type\":\"text\",\"required\":true,\"default\":\"draft\",\"_meta\":{\"required\":true}},\"notes\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"currency\":{\"type\":\"text\",\"required\":false,\"default\":\"USD\"}},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"manufacturing_boms\",\"conflictColumns\":[\"product_id\",\"version\",\"tenant_id\"],\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":true,\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"BillOfMaterials\",\"collectionExportName\":\"BillOfMaterialsCollection\",\"validationRules\":[{\"field\":\"productId\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"version\",\"rule\":\"required\",\"fieldType\":\"integer\"},{\"field\":\"status\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"manufacturing_boms\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_boms\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"product_id\\\" TEXT NOT NULL DEFAULT '',\\n \\\"version\\\" INTEGER NOT NULL DEFAULT 1,\\n \\\"effective_date\\\" TIMESTAMP,\\n \\\"status\\\" TEXT NOT NULL DEFAULT 'draft',\\n \\\"notes\\\" TEXT DEFAULT '',\\n \\\"currency\\\" TEXT DEFAULT 'USD'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"product_id\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"version\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":1},\"effective_date\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"draft\"},\"notes\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"currency\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"USD\"}},\"indexes\":[{\"name\":\"manufacturing_boms_product_id_version_idx\",\"columns\":[\"product_id\",\"version\",\"tenant_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_boms_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"manufacturing_boms_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"b2691adc\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:BomLine\":{\"name\":\"bomline\",\"className\":\"BomLine\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:BomLine\",\"collection\":\"bomlines\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/models/BomLine.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"bomId\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"componentSkuId\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"qtyPerUnit\":{\"type\":\"decimal\",\"required\":false,\"_meta\":{}},\"uom\":{\"type\":\"text\",\"required\":false,\"default\":\"each\"},\"wastePercent\":{\"type\":\"decimal\",\"required\":false,\"_meta\":{}},\"notes\":{\"type\":\"text\",\"required\":false,\"default\":\"\"}},\"methods\":{\"effectiveQtyPerUnit\":{\"name\":\"effectiveQtyPerUnit\",\"async\":false,\"parameters\":[],\"returnType\":\"number\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_bom_lines\",\"conflictColumns\":[\"bom_id\",\"component_sku_id\",\"tenant_id\"],\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"BomLine\",\"collectionExportName\":\"BomLineCollection\",\"validationRules\":[{\"field\":\"bomId\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"componentSkuId\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"manufacturing_bom_lines\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_bom_lines\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"bom_id\\\" TEXT NOT NULL DEFAULT '',\\n \\\"component_sku_id\\\" TEXT NOT NULL DEFAULT '',\\n \\\"qty_per_unit\\\" REAL,\\n \\\"uom\\\" TEXT DEFAULT 'each',\\n \\\"waste_percent\\\" REAL,\\n \\\"notes\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"bom_id\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"component_sku_id\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"qty_per_unit\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"uom\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"each\"},\"waste_percent\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"notes\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"manufacturing_bom_lines_bom_id_component_sku_id_idx\",\"columns\":[\"bom_id\",\"component_sku_id\",\"tenant_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_bom_lines_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"manufacturing_bom_lines_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"cfbae7e8\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:Operation\":{\"name\":\"operation\",\"className\":\"Operation\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:Operation\",\"collection\":\"operations\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/models/Operation.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"code\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"name\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"category\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"isActive\":{\"type\":\"boolean\",\"required\":false,\"default\":true},\"requiredQualificationId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-human-resources:Qualification\",\"_meta\":{\"nullable\":true}}},\"methods\":{\"delete\":{\"name\":\"delete\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_operations\",\"conflictColumns\":[\"code\",\"tenant_id\"],\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"Operation\",\"collectionExportName\":\"OperationCollection\",\"validationRules\":[{\"field\":\"code\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"name\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"manufacturing_operations\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_operations\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"code\\\" TEXT NOT NULL DEFAULT '',\\n \\\"name\\\" TEXT NOT NULL DEFAULT '',\\n \\\"category\\\" TEXT DEFAULT '',\\n \\\"is_active\\\" BOOLEAN DEFAULT TRUE,\\n \\\"required_qualification_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"code\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"name\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"category\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"is_active\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":true},\"required_qualification_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"manufacturing_operations_code_tenant_id_idx\",\"columns\":[\"code\",\"tenant_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_operations_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"manufacturing_operations_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"manufacturing_operations_required_qualification_id_idx\",\"columns\":[\"required_qualification_id\"]}],\"version\":\"0b3134d6\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:ProductionRun\":{\"name\":\"productionrun\",\"className\":\"ProductionRun\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:ProductionRun\",\"collection\":\"productionruns\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/models/ProductionRun.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"bomId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"BillOfMaterials\",\"_meta\":{\"required\":true,\"onDelete\":\"RESTRICT\"}},\"targetQty\":{\"type\":\"decimal\",\"required\":false,\"_meta\":{}},\"completedQty\":{\"type\":\"decimal\",\"required\":false,\"_meta\":{}},\"status\":{\"type\":\"text\",\"required\":true,\"default\":\"planned\",\"_meta\":{\"required\":true}}},\"methods\":{\"remainingQty\":{\"name\":\"remainingQty\",\"async\":false,\"parameters\":[],\"returnType\":\"number\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_production_runs\",\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"optional\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"ProductionRun\",\"collectionExportName\":\"ProductionRunCollection\",\"validationRules\":[{\"field\":\"bomId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"status\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"manufacturing_production_runs\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_production_runs\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"bom_id\\\" UUID NOT NULL,\\n \\\"target_qty\\\" REAL,\\n \\\"completed_qty\\\" REAL,\\n \\\"status\\\" TEXT NOT NULL DEFAULT 'planned'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"bom_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"manufacturing_boms\",\"column\":\"id\",\"onDelete\":\"RESTRICT\",\"onUpdate\":\"CASCADE\"}},\"target_qty\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"completed_qty\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"planned\"}},\"indexes\":[{\"name\":\"manufacturing_production_runs_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_production_runs_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"manufacturing_production_runs_bom_id_idx\",\"columns\":[\"bom_id\"]}],\"version\":\"2ca8147d\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:ProductionRunCompletion\":{\"name\":\"productionruncompletion\",\"className\":\"ProductionRunCompletion\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:ProductionRunCompletion\",\"collection\":\"productionruncompletions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/models/ProductionRunCompletion.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"runId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"ProductionRun\",\"_meta\":{\"required\":true,\"onDelete\":\"CASCADE\"}},\"qty\":{\"type\":\"decimal\",\"required\":false,\"_meta\":{}},\"completedAt\":{\"type\":\"datetime\",\"required\":false}},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"manufacturing_production_run_completions\",\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"optional\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"ProductionRunCompletion\",\"collectionExportName\":\"ProductionRunCompletionCollection\",\"validationRules\":[{\"field\":\"runId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"manufacturing_production_run_completions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_production_run_completions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"run_id\\\" UUID NOT NULL,\\n \\\"qty\\\" REAL,\\n \\\"completed_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"run_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"manufacturing_production_runs\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"qty\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"completed_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"manufacturing_production_run_completions_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_production_run_completions_tenant_ea7a0d0125_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"manufacturing_production_run_completions_run_id_idx\",\"columns\":[\"run_id\"]}],\"version\":\"c940de6c\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:RoutingStep\":{\"name\":\"routingstep\",\"className\":\"RoutingStep\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:RoutingStep\",\"collection\":\"routingsteps\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/models/RoutingStep.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"bomId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"BillOfMaterials\",\"_meta\":{\"required\":true,\"onDelete\":\"CASCADE\"}},\"operationId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Operation\",\"_meta\":{\"required\":true,\"onDelete\":\"RESTRICT\"}},\"sequence\":{\"type\":\"integer\",\"required\":true,\"default\":1,\"_meta\":{\"required\":true}},\"estimatedMinutes\":{\"type\":\"decimal\",\"required\":false,\"_meta\":{}},\"notes\":{\"type\":\"text\",\"required\":false,\"default\":\"\"}},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"manufacturing_routing_steps\",\"conflictColumns\":[\"bom_id\",\"sequence\",\"tenant_id\"],\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"RoutingStep\",\"collectionExportName\":\"RoutingStepCollection\",\"validationRules\":[{\"field\":\"bomId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"operationId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"sequence\",\"rule\":\"required\",\"fieldType\":\"integer\"}],\"schema\":{\"tableName\":\"manufacturing_routing_steps\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_routing_steps\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"bom_id\\\" UUID NOT NULL,\\n \\\"operation_id\\\" UUID NOT NULL,\\n \\\"sequence\\\" INTEGER NOT NULL DEFAULT 1,\\n \\\"estimated_minutes\\\" REAL,\\n \\\"notes\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"bom_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"manufacturing_boms\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"operation_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"manufacturing_operations\",\"column\":\"id\",\"onDelete\":\"RESTRICT\",\"onUpdate\":\"CASCADE\"}},\"sequence\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":1},\"estimated_minutes\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"notes\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"manufacturing_routing_steps_bom_id_sequence_idx\",\"columns\":[\"bom_id\",\"sequence\",\"tenant_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_routing_steps_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"manufacturing_routing_steps_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"manufacturing_routing_steps_operation_id_idx\",\"columns\":[\"operation_id\"]}],\"version\":\"41ac3c66\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"}},\"moduleType\":\"smrt\",\"smrtDependencies\":[\"@happyvertical/smrt-core\",\"@happyvertical/smrt-fields\",\"@happyvertical/smrt-inventory\",\"@happyvertical/smrt-products\",\"@happyvertical/smrt-tenancy\"]}"));
|
|
21
|
+
ObjectRegistry.registerPackageManifest(JSON.parse("{\"version\":\"1.0.0\",\"timestamp\":0,\"packageName\":\"@happyvertical/smrt-manufacturing\",\"packageVersion\":\"0.54.1\",\"objects\":{\"@happyvertical/smrt-manufacturing:BillOfMaterialsCollection\":{\"name\":\"billofmaterialscollection\",\"className\":\"BillOfMaterialsCollection\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:BillOfMaterialsCollection\",\"collection\":\"billofmaterialses\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/collections/BillOfMaterialsCollection.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{},\"methods\":{\"findByProduct\":{\"name\":\"findByProduct\",\"async\":true,\"parameters\":[{\"name\":\"productId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<BillOfMaterials[]>\",\"isStatic\":false,\"isPublic\":true},\"findActiveForProduct\":{\"name\":\"findActiveForProduct\",\"async\":true,\"parameters\":[{\"name\":\"productId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<BillOfMaterials | null>\",\"isStatic\":false,\"isPublic\":true},\"findByStatus\":{\"name\":\"findByStatus\",\"async\":true,\"parameters\":[{\"name\":\"status\",\"type\":\"BomStatus\",\"optional\":false}],\"returnType\":\"Promise<BillOfMaterials[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_boms\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"BillOfMaterials\",\"exportName\":\"BillOfMaterialsCollection\",\"collectionExportName\":\"BillOfMaterialsCollectionCollection\",\"schema\":{\"tableName\":\"manufacturing_boms\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_boms\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"product_id\\\" TEXT NOT NULL DEFAULT '',\\n \\\"version\\\" INTEGER NOT NULL DEFAULT 1,\\n \\\"effective_date\\\" TIMESTAMP,\\n \\\"status\\\" TEXT NOT NULL DEFAULT 'draft',\\n \\\"notes\\\" TEXT DEFAULT '',\\n \\\"currency\\\" TEXT DEFAULT 'USD'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"product_id\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"version\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":1},\"effective_date\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"draft\"},\"notes\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"currency\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"USD\"}},\"indexes\":[{\"name\":\"manufacturing_boms_product_id_version_idx\",\"columns\":[\"product_id\",\"version\",\"tenant_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_boms_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"manufacturing_boms_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"b2691adc\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:BomLineCollection\":{\"name\":\"bomlinecollection\",\"className\":\"BomLineCollection\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:BomLineCollection\",\"collection\":\"bomlines\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/collections/BomLineCollection.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{},\"methods\":{\"findByBom\":{\"name\":\"findByBom\",\"async\":true,\"parameters\":[{\"name\":\"bomId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<BomLine[]>\",\"isStatic\":false,\"isPublic\":true},\"findByComponent\":{\"name\":\"findByComponent\",\"async\":true,\"parameters\":[{\"name\":\"componentSkuId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<BomLine[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_bom_lines\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"BomLine\",\"exportName\":\"BomLineCollection\",\"collectionExportName\":\"BomLineCollectionCollection\",\"schema\":{\"tableName\":\"manufacturing_bom_lines\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_bom_lines\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"bom_id\\\" TEXT NOT NULL DEFAULT '',\\n \\\"component_sku_id\\\" TEXT NOT NULL DEFAULT '',\\n \\\"qty_per_unit\\\" REAL,\\n \\\"uom\\\" TEXT DEFAULT 'each',\\n \\\"waste_percent\\\" REAL,\\n \\\"notes\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"bom_id\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"component_sku_id\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"qty_per_unit\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"uom\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"each\"},\"waste_percent\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"notes\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"manufacturing_bom_lines_bom_id_component_sku_id_idx\",\"columns\":[\"bom_id\",\"component_sku_id\",\"tenant_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_bom_lines_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"manufacturing_bom_lines_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"cfbae7e8\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:OperationCollection\":{\"name\":\"operationcollection\",\"className\":\"OperationCollection\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:OperationCollection\",\"collection\":\"operations\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/collections/OperationCollection.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{},\"methods\":{\"findByCode\":{\"name\":\"findByCode\",\"async\":true,\"parameters\":[{\"name\":\"code\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Operation | null>\",\"isStatic\":false,\"isPublic\":true},\"listOperations\":{\"name\":\"listOperations\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true,\"memberTypes\":[\"boolean\"]}],\"returnType\":\"Promise<Operation[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_operations\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"Operation\",\"exportName\":\"OperationCollection\",\"collectionExportName\":\"OperationCollectionCollection\",\"schema\":{\"tableName\":\"manufacturing_operations\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_operations\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"code\\\" TEXT NOT NULL DEFAULT '',\\n \\\"name\\\" TEXT NOT NULL DEFAULT '',\\n \\\"category\\\" TEXT DEFAULT '',\\n \\\"is_active\\\" BOOLEAN DEFAULT TRUE,\\n \\\"required_qualification_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"code\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"name\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"category\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"is_active\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":true},\"required_qualification_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"manufacturing_operations_code_tenant_id_idx\",\"columns\":[\"code\",\"tenant_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_operations_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"manufacturing_operations_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"manufacturing_operations_required_qualification_id_idx\",\"columns\":[\"required_qualification_id\"]}],\"version\":\"0b3134d6\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:ProductionRunCollection\":{\"name\":\"productionruncollection\",\"className\":\"ProductionRunCollection\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:ProductionRunCollection\",\"collection\":\"productionruns\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/collections/ProductionRunCollection.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{},\"methods\":{\"findByBom\":{\"name\":\"findByBom\",\"async\":true,\"parameters\":[{\"name\":\"bomId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ProductionRun[]>\",\"isStatic\":false,\"isPublic\":true},\"findByStatus\":{\"name\":\"findByStatus\",\"async\":true,\"parameters\":[{\"name\":\"status\",\"type\":\"ProductionRunStatus\",\"optional\":false}],\"returnType\":\"Promise<ProductionRun[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_production_runs\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ProductionRun\",\"exportName\":\"ProductionRunCollection\",\"collectionExportName\":\"ProductionRunCollectionCollection\",\"schema\":{\"tableName\":\"manufacturing_production_runs\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_production_runs\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"bom_id\\\" UUID NOT NULL,\\n \\\"target_qty\\\" REAL,\\n \\\"completed_qty\\\" REAL,\\n \\\"status\\\" TEXT NOT NULL DEFAULT 'planned'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"bom_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"manufacturing_boms\",\"column\":\"id\",\"onDelete\":\"RESTRICT\",\"onUpdate\":\"CASCADE\"}},\"target_qty\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"completed_qty\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"planned\"}},\"indexes\":[{\"name\":\"manufacturing_production_runs_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_production_runs_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"manufacturing_production_runs_bom_id_idx\",\"columns\":[\"bom_id\"]}],\"version\":\"2ca8147d\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:ProductionRunCompletionCollection\":{\"name\":\"productionruncompletioncollection\",\"className\":\"ProductionRunCompletionCollection\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:ProductionRunCompletionCollection\",\"collection\":\"productionruncompletions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/collections/ProductionRunCompletionCollection.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{},\"methods\":{\"findByRun\":{\"name\":\"findByRun\",\"async\":true,\"parameters\":[{\"name\":\"runId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<ProductionRunCompletion[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_production_run_completions\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"ProductionRunCompletion\",\"exportName\":\"ProductionRunCompletionCollection\",\"collectionExportName\":\"ProductionRunCompletionCollectionCollection\",\"schema\":{\"tableName\":\"manufacturing_production_run_completions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_production_run_completions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"run_id\\\" UUID NOT NULL,\\n \\\"qty\\\" REAL,\\n \\\"completed_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"run_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"manufacturing_production_runs\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"qty\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"completed_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"manufacturing_production_run_completions_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_production_run_completions_tenant_ea7a0d0125_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"manufacturing_production_run_completions_run_id_idx\",\"columns\":[\"run_id\"]}],\"version\":\"c940de6c\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:RoutingStepCollection\":{\"name\":\"routingstepcollection\",\"className\":\"RoutingStepCollection\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:RoutingStepCollection\",\"collection\":\"routingsteps\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/collections/RoutingStepCollection.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{},\"methods\":{\"findByBom\":{\"name\":\"findByBom\",\"async\":true,\"parameters\":[{\"name\":\"bomId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<RoutingStep[]>\",\"isStatic\":false,\"isPublic\":true},\"findByOperation\":{\"name\":\"findByOperation\",\"async\":true,\"parameters\":[{\"name\":\"operationId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<RoutingStep[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_routing_steps\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"RoutingStep\",\"exportName\":\"RoutingStepCollection\",\"collectionExportName\":\"RoutingStepCollectionCollection\",\"schema\":{\"tableName\":\"manufacturing_routing_steps\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_routing_steps\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"bom_id\\\" UUID NOT NULL,\\n \\\"operation_id\\\" UUID NOT NULL,\\n \\\"sequence\\\" INTEGER NOT NULL DEFAULT 1,\\n \\\"estimated_minutes\\\" REAL,\\n \\\"notes\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"bom_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"manufacturing_boms\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"operation_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"manufacturing_operations\",\"column\":\"id\",\"onDelete\":\"RESTRICT\",\"onUpdate\":\"CASCADE\"}},\"sequence\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":1},\"estimated_minutes\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"notes\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"manufacturing_routing_steps_bom_id_sequence_idx\",\"columns\":[\"bom_id\",\"sequence\",\"tenant_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_routing_steps_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"manufacturing_routing_steps_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"manufacturing_routing_steps_operation_id_idx\",\"columns\":[\"operation_id\"]}],\"version\":\"41ac3c66\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:Assembly\":{\"name\":\"assembly\",\"className\":\"Assembly\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:Assembly\",\"collection\":\"products\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/models/Assembly.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{\"created_at\":{\"type\":\"datetime\",\"required\":false},\"updated_at\":{\"type\":\"datetime\",\"required\":false},\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"generated\":true,\"source\":\"tenantScoped_decorator\",\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"autoFilter\":true,\"autoPopulate\":true,\"allowSuperAdminBypass\":false}}},\"productType\":{\"type\":\"json\",\"required\":false},\"name\":{\"type\":\"text\",\"required\":false},\"description\":{\"type\":\"text\",\"required\":false},\"category\":{\"type\":\"text\",\"required\":false},\"manufacturer\":{\"type\":\"text\",\"required\":false},\"model\":{\"type\":\"text\",\"required\":false},\"price\":{\"type\":\"integer\",\"required\":true,\"default\":0},\"inStock\":{\"type\":\"boolean\",\"required\":true,\"default\":true},\"specifications\":{\"type\":\"json\",\"required\":false,\"default\":{}},\"tags\":{\"type\":\"json\",\"required\":false,\"default\":[]},\"estimatedLabourMinutes\":{\"type\":\"integer\",\"required\":false,\"default\":0},\"defaultOperationId\":{\"type\":\"foreignKey\",\"required\":false,\"related\":\"Operation\",\"_meta\":{\"nullable\":true,\"onDelete\":\"RESTRICT\"}},\"partReference\":{\"type\":\"text\",\"required\":false,\"default\":\"\"}},\"methods\":{\"getSpecification\":{\"name\":\"getSpecification\",\"async\":true,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<unknown>\",\"isStatic\":false,\"isPublic\":true},\"updateSpecification\":{\"name\":\"updateSpecification\",\"async\":true,\"parameters\":[{\"name\":\"key\",\"type\":\"string\",\"optional\":false},{\"name\":\"value\",\"type\":\"unknown\",\"optional\":false}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"getAssets\":{\"name\":\"getAssets\",\"async\":true,\"parameters\":[{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<Asset[]>\",\"isStatic\":false,\"isPublic\":true},\"addAsset\":{\"name\":\"addAsset\",\"async\":true,\"parameters\":[{\"name\":\"asset\",\"type\":\"Asset\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"any\",\"optional\":true,\"default\":\"attachment\"},{\"name\":\"sortOrder\",\"type\":\"any\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true},\"removeAsset\":{\"name\":\"removeAsset\",\"async\":true,\"parameters\":[{\"name\":\"assetId\",\"type\":\"string\",\"optional\":false},{\"name\":\"relationship\",\"type\":\"string\",\"optional\":true}],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"},\"tableName\":\"products\",\"tableStrategy\":\"sti\"},\"extends\":\"Product\",\"exportName\":\"Assembly\",\"collectionExportName\":\"AssemblyCollection\",\"validationRules\":[{\"field\":\"price\",\"rule\":\"required\",\"fieldType\":\"integer\"},{\"field\":\"inStock\",\"rule\":\"required\",\"fieldType\":\"boolean\"}],\"schema\":{\"tableName\":\"products\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"products\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"_meta_type\\\" TEXT NOT NULL,\\n \\\"_meta_data\\\" JSON,\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"product_type\\\" TEXT,\\n \\\"name\\\" TEXT,\\n \\\"description\\\" TEXT,\\n \\\"category\\\" TEXT,\\n \\\"manufacturer\\\" TEXT,\\n \\\"model\\\" TEXT,\\n \\\"price\\\" INTEGER DEFAULT 0,\\n \\\"in_stock\\\" BOOLEAN DEFAULT TRUE,\\n \\\"specifications\\\" JSON DEFAULT '{}',\\n \\\"tags\\\" JSON DEFAULT '[]',\\n \\\"estimated_labour_minutes\\\" INTEGER DEFAULT 0,\\n \\\"default_operation_id\\\" UUID,\\n \\\"part_reference\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"_meta_type\":{\"type\":\"TEXT\",\"notNull\":true},\"_meta_data\":{\"type\":\"JSON\",\"notNull\":false},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false},\"product_type\":{\"type\":\"TEXT\",\"notNull\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false},\"description\":{\"type\":\"TEXT\",\"notNull\":false},\"category\":{\"type\":\"TEXT\",\"notNull\":false},\"manufacturer\":{\"type\":\"TEXT\",\"notNull\":false},\"model\":{\"type\":\"TEXT\",\"notNull\":false},\"price\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":0},\"in_stock\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"default\":true},\"specifications\":{\"type\":\"JSON\",\"notNull\":false,\"default\":{}},\"tags\":{\"type\":\"JSON\",\"notNull\":false,\"default\":[]},\"estimated_labour_minutes\":{\"type\":\"INTEGER\",\"notNull\":false,\"default\":0},\"default_operation_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":false,\"foreignKey\":{\"table\":\"manufacturing_operations\",\"column\":\"id\",\"onDelete\":\"RESTRICT\",\"onUpdate\":\"CASCADE\"}},\"part_reference\":{\"type\":\"TEXT\",\"notNull\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"products_slug_context_meta_type_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\",\"_meta_type\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"products_meta_type_idx\",\"columns\":[\"_meta_type\"]},{\"name\":\"products_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"products_default_operation_id_idx\",\"columns\":[\"default_operation_id\"]}],\"version\":\"f2f2bf95\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:BillOfMaterials\":{\"name\":\"billofmaterials\",\"className\":\"BillOfMaterials\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:BillOfMaterials\",\"collection\":\"billofmaterialses\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/models/BillOfMaterials.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"productId\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"version\":{\"type\":\"integer\",\"required\":true,\"default\":1,\"_meta\":{\"required\":true}},\"effectiveDate\":{\"type\":\"datetime\",\"required\":false},\"status\":{\"type\":\"text\",\"required\":true,\"default\":\"draft\",\"_meta\":{\"required\":true}},\"notes\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"currency\":{\"type\":\"text\",\"required\":false,\"default\":\"USD\"}},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"manufacturing_boms\",\"conflictColumns\":[\"product_id\",\"version\",\"tenant_id\"],\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":true,\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"BillOfMaterials\",\"collectionExportName\":\"BillOfMaterialsCollection\",\"validationRules\":[{\"field\":\"productId\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"version\",\"rule\":\"required\",\"fieldType\":\"integer\"},{\"field\":\"status\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"manufacturing_boms\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_boms\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"product_id\\\" TEXT NOT NULL DEFAULT '',\\n \\\"version\\\" INTEGER NOT NULL DEFAULT 1,\\n \\\"effective_date\\\" TIMESTAMP,\\n \\\"status\\\" TEXT NOT NULL DEFAULT 'draft',\\n \\\"notes\\\" TEXT DEFAULT '',\\n \\\"currency\\\" TEXT DEFAULT 'USD'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"product_id\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"version\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":1},\"effective_date\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"draft\"},\"notes\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"currency\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"USD\"}},\"indexes\":[{\"name\":\"manufacturing_boms_product_id_version_idx\",\"columns\":[\"product_id\",\"version\",\"tenant_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_boms_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"manufacturing_boms_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"b2691adc\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:BomLine\":{\"name\":\"bomline\",\"className\":\"BomLine\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:BomLine\",\"collection\":\"bomlines\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/models/BomLine.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"bomId\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"componentSkuId\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"qtyPerUnit\":{\"type\":\"decimal\",\"required\":false,\"_meta\":{}},\"uom\":{\"type\":\"text\",\"required\":false,\"default\":\"each\"},\"wastePercent\":{\"type\":\"decimal\",\"required\":false,\"_meta\":{}},\"notes\":{\"type\":\"text\",\"required\":false,\"default\":\"\"}},\"methods\":{\"effectiveQtyPerUnit\":{\"name\":\"effectiveQtyPerUnit\",\"async\":false,\"parameters\":[],\"returnType\":\"number\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_bom_lines\",\"conflictColumns\":[\"bom_id\",\"component_sku_id\",\"tenant_id\"],\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"BomLine\",\"collectionExportName\":\"BomLineCollection\",\"validationRules\":[{\"field\":\"bomId\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"componentSkuId\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"manufacturing_bom_lines\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_bom_lines\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"bom_id\\\" TEXT NOT NULL DEFAULT '',\\n \\\"component_sku_id\\\" TEXT NOT NULL DEFAULT '',\\n \\\"qty_per_unit\\\" REAL,\\n \\\"uom\\\" TEXT DEFAULT 'each',\\n \\\"waste_percent\\\" REAL,\\n \\\"notes\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"bom_id\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"component_sku_id\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"qty_per_unit\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"uom\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"each\"},\"waste_percent\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"notes\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"manufacturing_bom_lines_bom_id_component_sku_id_idx\",\"columns\":[\"bom_id\",\"component_sku_id\",\"tenant_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_bom_lines_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"manufacturing_bom_lines_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]}],\"version\":\"cfbae7e8\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:Operation\":{\"name\":\"operation\",\"className\":\"Operation\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:Operation\",\"collection\":\"operations\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/models/Operation.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"code\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"name\":{\"type\":\"text\",\"required\":true,\"default\":\"\",\"_meta\":{\"required\":true}},\"category\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"isActive\":{\"type\":\"boolean\",\"required\":false,\"default\":true},\"requiredQualificationId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-human-resources:Qualification\",\"_meta\":{\"nullable\":true}}},\"methods\":{\"delete\":{\"name\":\"delete\",\"async\":true,\"parameters\":[],\"returnType\":\"Promise<void>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_operations\",\"conflictColumns\":[\"code\",\"tenant_id\"],\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"Operation\",\"collectionExportName\":\"OperationCollection\",\"validationRules\":[{\"field\":\"code\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"name\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"manufacturing_operations\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_operations\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"code\\\" TEXT NOT NULL DEFAULT '',\\n \\\"name\\\" TEXT NOT NULL DEFAULT '',\\n \\\"category\\\" TEXT DEFAULT '',\\n \\\"is_active\\\" BOOLEAN DEFAULT TRUE,\\n \\\"required_qualification_id\\\" UUID\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"code\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"name\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"\"},\"category\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"is_active\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":true},\"required_qualification_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"manufacturing_operations_code_tenant_id_idx\",\"columns\":[\"code\",\"tenant_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_operations_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"manufacturing_operations_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"manufacturing_operations_required_qualification_id_idx\",\"columns\":[\"required_qualification_id\"]}],\"version\":\"0b3134d6\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:ProductionRun\":{\"name\":\"productionrun\",\"className\":\"ProductionRun\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:ProductionRun\",\"collection\":\"productionruns\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/models/ProductionRun.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"bomId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"BillOfMaterials\",\"_meta\":{\"required\":true,\"onDelete\":\"RESTRICT\"}},\"targetQty\":{\"type\":\"decimal\",\"required\":false,\"_meta\":{}},\"completedQty\":{\"type\":\"decimal\",\"required\":false,\"_meta\":{}},\"status\":{\"type\":\"text\",\"required\":true,\"default\":\"planned\",\"_meta\":{\"required\":true}}},\"methods\":{\"remainingQty\":{\"name\":\"remainingQty\",\"async\":false,\"parameters\":[],\"returnType\":\"number\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"manufacturing_production_runs\",\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"optional\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"ProductionRun\",\"collectionExportName\":\"ProductionRunCollection\",\"validationRules\":[{\"field\":\"bomId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"status\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"manufacturing_production_runs\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_production_runs\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"bom_id\\\" UUID NOT NULL,\\n \\\"target_qty\\\" REAL,\\n \\\"completed_qty\\\" REAL,\\n \\\"status\\\" TEXT NOT NULL DEFAULT 'planned'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"bom_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"manufacturing_boms\",\"column\":\"id\",\"onDelete\":\"RESTRICT\",\"onUpdate\":\"CASCADE\"}},\"target_qty\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"completed_qty\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false,\"default\":\"planned\"}},\"indexes\":[{\"name\":\"manufacturing_production_runs_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_production_runs_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"manufacturing_production_runs_bom_id_idx\",\"columns\":[\"bom_id\"]}],\"version\":\"2ca8147d\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:ProductionRunCompletion\":{\"name\":\"productionruncompletion\",\"className\":\"ProductionRunCompletion\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:ProductionRunCompletion\",\"collection\":\"productionruncompletions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/models/ProductionRunCompletion.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"runId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"ProductionRun\",\"_meta\":{\"required\":true,\"onDelete\":\"CASCADE\"}},\"qty\":{\"type\":\"decimal\",\"required\":false,\"_meta\":{}},\"completedAt\":{\"type\":\"datetime\",\"required\":false}},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"manufacturing_production_run_completions\",\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"optional\"},\"conflictColumns\":[\"tenant_id\",\"slug\",\"context\"]},\"extends\":\"SmrtObject\",\"exportName\":\"ProductionRunCompletion\",\"collectionExportName\":\"ProductionRunCompletionCollection\",\"validationRules\":[{\"field\":\"runId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"manufacturing_production_run_completions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_production_run_completions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"run_id\\\" UUID NOT NULL,\\n \\\"qty\\\" REAL,\\n \\\"completed_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"run_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"manufacturing_production_runs\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"qty\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"completed_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"manufacturing_production_run_completions_slug_context_idx\",\"columns\":[\"tenant_id\",\"slug\",\"context\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_production_run_completions_tenant_ea7a0d0125_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"manufacturing_production_run_completions_run_id_idx\",\"columns\":[\"run_id\"]}],\"version\":\"c940de6c\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"},\"@happyvertical/smrt-manufacturing:RoutingStep\":{\"name\":\"routingstep\",\"className\":\"RoutingStep\",\"qualifiedName\":\"@happyvertical/smrt-manufacturing:RoutingStep\",\"collection\":\"routingsteps\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/manufacturing/src/models/RoutingStep.ts\",\"packageName\":\"@happyvertical/smrt-manufacturing\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"bomId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"BillOfMaterials\",\"_meta\":{\"required\":true,\"onDelete\":\"CASCADE\"}},\"operationId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"Operation\",\"_meta\":{\"required\":true,\"onDelete\":\"RESTRICT\"}},\"sequence\":{\"type\":\"integer\",\"required\":true,\"default\":1,\"_meta\":{\"required\":true}},\"estimatedMinutes\":{\"type\":\"decimal\",\"required\":false,\"_meta\":{}},\"notes\":{\"type\":\"text\",\"required\":false,\"default\":\"\"}},\"methods\":{},\"decoratorConfig\":{\"tableName\":\"manufacturing_routing_steps\",\"conflictColumns\":[\"bom_id\",\"sequence\",\"tenant_id\"],\"api\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"skipApiCheck\":true},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"RoutingStep\",\"collectionExportName\":\"RoutingStepCollection\",\"validationRules\":[{\"field\":\"bomId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"operationId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"sequence\",\"rule\":\"required\",\"fieldType\":\"integer\"}],\"schema\":{\"tableName\":\"manufacturing_routing_steps\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"manufacturing_routing_steps\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"bom_id\\\" UUID NOT NULL,\\n \\\"operation_id\\\" UUID NOT NULL,\\n \\\"sequence\\\" INTEGER NOT NULL DEFAULT 1,\\n \\\"estimated_minutes\\\" REAL,\\n \\\"notes\\\" TEXT DEFAULT ''\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"bom_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"manufacturing_boms\",\"column\":\"id\",\"onDelete\":\"CASCADE\",\"onUpdate\":\"CASCADE\"}},\"operation_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false,\"foreignKey\":{\"table\":\"manufacturing_operations\",\"column\":\"id\",\"onDelete\":\"RESTRICT\",\"onUpdate\":\"CASCADE\"}},\"sequence\":{\"type\":\"INTEGER\",\"notNull\":true,\"unique\":false,\"default\":1},\"estimated_minutes\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"notes\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"}},\"indexes\":[{\"name\":\"manufacturing_routing_steps_bom_id_sequence_idx\",\"columns\":[\"bom_id\",\"sequence\",\"tenant_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"manufacturing_routing_steps_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"manufacturing_routing_steps_tenant_id_created_at_idx\",\"columns\":[\"tenant_id\",\"created_at\"]},{\"name\":\"manufacturing_routing_steps_operation_id_idx\",\"columns\":[\"operation_id\"]}],\"version\":\"41ac3c66\"},\"importPath\":\"@happyvertical/smrt-manufacturing\"}},\"moduleType\":\"smrt\",\"smrtDependencies\":[\"@happyvertical/smrt-core\",\"@happyvertical/smrt-inventory\",\"@happyvertical/smrt-products\",\"@happyvertical/smrt-tenancy\"]}"));
|
|
22
22
|
//#endregion
|
|
23
23
|
//#region src/models/Operation.ts
|
|
24
24
|
var __defProp$6 = Object.defineProperty;
|
package/dist/manifest.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"version": "1.0.0",
|
|
3
3
|
"timestamp": 0,
|
|
4
4
|
"packageName": "@happyvertical/smrt-manufacturing",
|
|
5
|
-
"packageVersion": "0.
|
|
5
|
+
"packageVersion": "0.54.1",
|
|
6
6
|
"objects": {
|
|
7
7
|
"@happyvertical/smrt-manufacturing:BillOfMaterialsCollection": {
|
|
8
8
|
"name": "billofmaterialscollection",
|
|
@@ -2489,7 +2489,6 @@
|
|
|
2489
2489
|
"moduleType": "smrt",
|
|
2490
2490
|
"smrtDependencies": [
|
|
2491
2491
|
"@happyvertical/smrt-core",
|
|
2492
|
-
"@happyvertical/smrt-fields",
|
|
2493
2492
|
"@happyvertical/smrt-inventory",
|
|
2494
2493
|
"@happyvertical/smrt-products",
|
|
2495
2494
|
"@happyvertical/smrt-tenancy"
|
package/dist/smrt-knowledge.json
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
"sensitiveFieldsExcluded": true,
|
|
4
4
|
"generatedAt": "1970-01-01T00:00:00.000Z",
|
|
5
5
|
"packageName": "@happyvertical/smrt-manufacturing",
|
|
6
|
-
"packageVersion": "0.
|
|
6
|
+
"packageVersion": "0.54.1",
|
|
7
7
|
"sourceManifestPath": "dist/manifest.json",
|
|
8
8
|
"agentDocPath": "AGENTS.md",
|
|
9
9
|
"sourceHashes": {
|
|
10
|
-
"manifest": "
|
|
11
|
-
"packageJson": "
|
|
12
|
-
"agents": "
|
|
10
|
+
"manifest": "b71187fcccffe9b128ee614c4b8a800b57f3317cfad5820257528d921ca36fb0",
|
|
11
|
+
"packageJson": "866587169468db1fa32573c363ad722a06fc64a47ad5d0f5dfa2d305ec263ea7",
|
|
12
|
+
"agents": "307b97107895d8aca50971c53b5af96099fe5ccc2c2e4715f56450d64ddbee0c",
|
|
13
13
|
"moduleDoc:agents/multilevel-and-runs.md": "544d519356801f3cb3beb9e6d49a3e0eec93fdddf3f56150cf3141f766f98c9d"
|
|
14
14
|
},
|
|
15
15
|
"exports": [
|
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@happyvertical/logger": "catalog:",
|
|
24
24
|
"@happyvertical/smrt-core": "workspace:*",
|
|
25
|
-
"@happyvertical/smrt-fields": "workspace:*",
|
|
26
25
|
"@happyvertical/smrt-inventory": "workspace:*",
|
|
27
26
|
"@happyvertical/smrt-products": "workspace:*",
|
|
28
27
|
"@happyvertical/smrt-tenancy": "workspace:*",
|
|
@@ -41,7 +40,6 @@
|
|
|
41
40
|
},
|
|
42
41
|
"smrtDependencies": [
|
|
43
42
|
"@happyvertical/smrt-core",
|
|
44
|
-
"@happyvertical/smrt-fields",
|
|
45
43
|
"@happyvertical/smrt-inventory",
|
|
46
44
|
"@happyvertical/smrt-products",
|
|
47
45
|
"@happyvertical/smrt-tenancy",
|
|
@@ -2383,7 +2381,7 @@
|
|
|
2383
2381
|
"polymorphicAssociations": 0,
|
|
2384
2382
|
"uuidColumns": 37
|
|
2385
2383
|
},
|
|
2386
|
-
"agentDoc": "# @happyvertical/smrt-manufacturing\n\nBills of materials (multi-level through sub-assemblies), operations and routing, cost and labour rollup, production runs, and production-order stock movement. Strictly industry-neutral — the same primitives serve apparel, furniture, automotive, CPG, electronics, food production, custom hardware, and any vertical that builds finished goods from a recipe.\n\nSits on top of `@happyvertical/smrt-inventory` (stock) and `@happyvertical/smrt-products` (catalog: `Product`, `Material`, `Sku`), and works alongside the `ProductionOrder` Contract STI subtype already shipped in `@happyvertical/smrt-commerce`.\n\n## Models\n\n| Model | Purpose |\n|---|---|\n| `Assembly` | The product that is **made**, counterpart to `Material`. Cross-package STI subtype of `smrt-products` `Product` (`productType: 'assembly'`, `_meta_type: '@happyvertical/smrt-manufacturing:Assembly'`) in the shared `products` table. Own columns: `estimatedLabourMinutes` (integer, per unit; a save refuses anything but a whole number of minutes of zero or more), `defaultOperationId` (`@foreignKey(Operation)`, nullable, RESTRICT like `RoutingStep.operationId`: the operation work on it is booked to by default), `partReference` (the organization's drawing/part number). Name, price, tags come from `Product`; part number and stock from its `Sku` and inventory; structure from its bill; documents from `ProductAsset`. Exposure matches `Product` (REST list/get/create/update, MCP list/get), as the issue asks: unlike `Operation`, the assembly row has no service-owned invariant that generated writes could bypass. |\n| `BillOfMaterials` | Recipe for a finished product. `productId` (plain string) references the upstream `Product` or any STI subtype. Multiple revisions per product via `version` + `status` (`draft` / `active` / `superseded`). `conflictColumns: ['product_id', 'version', 'tenant_id']`. |\n| `BomLine` | One component on a BOM. `bomId` (FK), `componentSkuId` (plain string ref — the `Sku` model lives in `@happyvertical/smrt-products`; inventory tracks stock motion against the id), `qtyPerUnit`, `uom` (open-ended — `yards`, `each`, `grams`, `kg`, ...), `wastePercent`, `notes`. `conflictColumns: ['bom_id', 'component_sku_id', 'tenant_id']`. |\n| `Operation` | A kind of work (cut, weld, inspect), a managed list per tenant. `code` (unique per tenant; `conflictColumns: ['code', 'tenant_id']`, fixed once defined), `name`, `category`, `isActive` (retire/reinstate; never deleted, `delete()` throws), `requiredQualificationId` (nullable `@crossPackageRef('@happyvertical/smrt-human-resources:Qualification')`: metadata only, no dependency, unvalidated; an application reads it to gate who may start the operation). |\n| `ProductionRun` | A build against one bill, reported as it happens (\"25 to build, 12 done\"). `bomId` (`@foreignKey(BillOfMaterials)`, RESTRICT: pinned when created), `targetQty` and `completedQty` (decimal; completed is the sum of completions), `status` (`planned` / `in_progress` / `done` / `cancelled`). Generated list/get only; `ProductionRunService` owns writes. |\n| `ProductionRunCompletion` | One dated report on a run: `runId` (`@foreignKey(ProductionRun)`, CASCADE), `qty` (decimal, > 0), `completedAt`. Generated list/get only. |\n| `RoutingStep` | One operation in a BOM's optional routing. `bomId` (`@foreignKey(BillOfMaterials)`, CASCADE: a routing belongs to its bill), `operationId` (`@foreignKey(Operation)`, RESTRICT: operations are retired, never deleted), `sequence` (1..n, unique per bom), `estimatedMinutes` (decimal, per produced unit), `notes`. `conflictColumns: ['bom_id', 'sequence', 'tenant_id']`. |\n\nAll models are `@TenantScoped({ mode: 'optional' })` with a nullable `tenantId` so they can be used either tenant-scoped or globally.\n\n## Operations, routing and labour estimate\n\n- `OperationService` maintains the list (`define` rejects a duplicate code, including a retired one's; `rename`, `update`, `retire`, `reinstate`). `RoutingService.replaceRouting(bomId, steps)` swaps a bill's whole routing in one transaction and numbers it 1..n; a retired operation may stay on a routing that has it but cannot be newly added.\n- `BomService.computeLabourEstimate(bomId)` returns minutes and, only when the caller supplies `rateResolver` (hourly rate per `Operation`, mirroring `costResolver`), cost. No resolver means minutes only with `rateUnavailable` on each step. A bill with no routing returns an empty estimate; `computeMaterialCost` is unchanged.\n- `Operation` and `RoutingStep` expose generated list/get only; writes go through the services (generated create/update would upsert on a duplicate code or rename the code). `replaceRouting` saves the bill row inside its transaction (row lock) and retries on a revision conflict, so concurrent replacements serialize.\n- Deliberately absent: a default labour rate class (nothing here would use it; the resolver receives the whole `Operation` and can key on `code`/`category`), setup time, scheduling and work-centre capacity, and time recorded against an operation (that stays in `smrt-timesheets` or the application).\n- `./svelte` exports `OperationList` and `OperationForm` (props-driven; hosts persist through `OperationService`). Messages live in `src/svelte/i18n.ts`; component tests use the shared jsdom harness with axe assertions.\n- Tests: `operations-suite.ts` runs on SQLite (`operations.test.ts`) and PostgreSQL (`operations.optional.test.ts`, `pnpm test:postgres`; each test runs in its own tenant because PostgreSQL test data persists).\n\n## Assemblies — nesting lives in the bill\n\nA sub-assembly is a `BomLine` whose component SKU belongs to an `Assembly`; there is no children list on the model. `AssemblyService` is the one link from a line to what it names:\n\n| Method | Behavior |\n|---|---|\n| `resolveComponent(skuId, { tenantId? })` | `{ kind, sku, product, assembly, activeBom, buildable }`. `kind` is `assembly`, `material` (`Material`), `bought` (any other `Product`), or `missing` (unknown SKU, SKU with no product, or a non-UUID id; never throws). `activeBom` is the assembly's highest active bill, `null` when it has none; `buildable` is `assembly && activeBom`. Multi-level explosion (#3444) recurses on `activeBom` and stops at every other kind. |\n| `isAssembly(skuId)` | `resolveComponent(skuId).kind === 'assembly'`. |\n| `findActiveBom(productId, { tenantId? })` | Highest active bill. With `tenantId` (including `null`), that tenant's own bill, else a global one, and `resolveComponent` reads the SKU and product as that tenant's or global (through `tenant-scope.ts`, so a shared global component stays visible under a tenant context) and reports another tenant's as `missing`, whatever the tenant context; the cycle walk and `getBillStructure` pass the bill's own tenant, so a shared assembly resolves to the right tenant's bill on writes made without `withTenant()`. |\n| `getBillStructure(bomId)` | One level: the bill plus each line with its resolved component. Throws `BomNotFoundError`. |\n| `findCycle(productId, componentSkuIds)` | The path by which those components would make `productId` contain itself, following sub-assemblies' **active** bills only; `null` when none. |\n| `assertLineAcyclic(line)` / `assertBillAcyclic(bom)` | Throw `BomCycleError` (a `ValidationError`, code `MANUFACTURING_BOM_CYCLE`, `path` from the product back to itself). |\n\n**Cycle refusal runs in the models.** `BomLine.validateBeforeSave` checks every line save (draft bills too, so a loop is refused when written); `BillOfMaterials.validateBeforeSave` checks every save of an `active` bill (activation), including the lines of a stored bill with the same `(productId, version, tenantId)` that the save would upsert onto. The generated REST routes go through `save()`, so they refuse cycles as well. Not covered: re-pointing a `Sku.productId` (owned by `smrt-products`) and two concurrent saves that each close half of a loop.\n\n## Multi-level walks and production runs\n\nDetail: [agents/multilevel-and-runs.md](agents/multilevel-and-runs.md).\n\n- Every `BomService` method takes `{ levels }` (default `1`, unchanged; up to `MAX_EXPLOSION_DEPTH` = 32, or `'all'`). One walk (`services/structure-walk.ts`) serves `explode` (gross lines and totals), `planRequirements` (net of stock: available, short, what building a shortfall takes; facts, no make-or-buy policy), `canProduce`, cost and labour. A loop already in stored data fails with `BomStructureCycleError`; size limits with `BomExplosionLimitError`.\n- `ProductionRunService` writes `ProductionRun` / `ProductionRunCompletion` in one transaction per call, locking the run row through its revision-guarded save and retrying on a revision conflict; no adapter without `transaction()`. Stock moves only when the caller passes `consume` / `produce`.\n- A run is not commerce's `ProductionOrder` (a `Contract` with terms and money, in a package this one does not depend on); an application that has both links them.\n\n## Svelte components (`./svelte`)\n\nProps-driven; the host loads and persists. `AssemblyList` (field policy drops hidden columns via `policyToVisibleColumnIds`), `AssemblyForm` (smrt-fields `ObjectForm` for `@happyvertical/smrt-manufacturing:Assembly`, so price and every other field follow the consumer's field policy), `BomEditor` (add/edit/remove lines through host handlers; a sub-assembly shows whether it has its own bill and expands read-only through `loadBill`), `BomStructureTree` (the read-only nested view). `ProductionRunList` (progress, status, and with `oncomplete` a quantity field per open run; rows from `toProductionRunView`), `RequirementsTree` (read-only `explode` / `planRequirements` result by level with totals; `toRequirementTree`, `toRequirementTotals`; internal `RequirementsTreeLevel`). Adapters: `toAssemblyView`, `toBomEditorLines`. Strings are under `manufacturing.` in `src/svelte/i18n.ts`; the package is strict for raw primitives, hardcoded strings and JSDoc.\n\n\n## BomService — planning helpers\n\n```typescript\nimport { BomService } from '@happyvertical/smrt-manufacturing';\n\nconst bom = await BomService.create({\n db,\n // Optional. Resolve unit cost for a component SKU.\n // Without this, every line rolls up to $0 and `costUnavailable` is set.\n costResolver: async (componentSkuId) => fetchLatestCost(componentSkuId),\n});\n\nconst rollup = await bom.computeMaterialCost(bomId);\n// { totalCost, currency, lineBreakdown, hasMissingCosts }\n\nconst requirements = await bom.explodeRequirements(bomId, 100);\n// [{ componentSkuId, totalQty, uom }, ...]\n\nconst check = await bom.canProduce(bomId, 100);\n// { ok: true } | { ok: false, shortages: [...] }\n```\n\n| Method | Behavior |\n|---|---|\n| `computeMaterialCost(bomId)` | Walks every BomLine, applies waste (`qtyPerUnit * (1 + wastePercent / 100)`), resolves unit costs via the optional `costResolver`, returns per-line breakdown plus rolled-up total. Lines with no cost set `costUnavailable: true` and contribute `0`. |\n| `explodeRequirements(bomId, qty)` | Returns a \"shopping list\" of materials needed for `qty` units. Duplicates across lines are summed. Does NOT mutate stock. |\n| `canProduce(bomId, qty)` | Calls `explodeRequirements`, then sums `available` stock across every location per component, returns `{ ok: true }` if everything's covered, else `{ ok: false, shortages: [...] }`. |\n| `explode` / `planRequirements` | Multi-level walks; see \"Multi-level walks\" above. Each method above also takes `{ levels }`. |\n\n## ProductionService — consume / produce\n\n```typescript\nimport { ProductionService } from '@happyvertical/smrt-manufacturing';\n\nconst production = await ProductionService.create({ db });\n\n// Drain materials at the factory.\nconst consumed = await production.consumeMaterials(\n { id: order.id, productId: order.productId, bomId: order.bomId },\n { locationId: factory.id, qty: runQty },\n);\n\n// Receive finished goods.\nconst produced = await production.produceFinishedGoods(\n { id: order.id, productId: order.productId },\n { locationId: factory.id, qty: runQty, finishedSkuId: variant.id },\n);\n\n// Or run both in one transaction — see \"Joint atomicity\" below.\nconst { consumed, produced } = await production.runProduction(\n { id: order.id, productId: order.productId, bomId: order.bomId },\n {\n consume: { locationId: factory.id, qty: runQty },\n produce: { locationId: factory.id, qty: runQty, finishedSkuId: variant.id },\n },\n);\n```\n\nAll three methods write through `StockService` and stamp every emitted `StockMovement` with `sourceType: 'ProductionOrder'` (override with the `sourceType` option, as `ProductionRunService` does) + the production order id so audit queries can roll them up later.\n\n### Joint atomicity — `runProduction` vs the two-call form\n\n`consumeMaterials` and `produceFinishedGoods` are each individually atomic, but calling them as two separate awaits is NOT jointly atomic — each opens its own `stockService.withTransaction(...)` scope. If something goes wrong between the two calls (process crash, transient adapter failure on the produce leg), you can land in a state where materials are deducted but no finished SKU receipt balances them. The audit ledger stays consistent within each call; what's missing is the cross-call invariant.\n\nWhen you need that invariant — typically make-to-stock flows where the factory step is invisible to the ledger — use `runProduction(order, { consume, produce })`. Both legs run inside one transaction; any failure (BOM shortage, adapter error, interceptor reject) rolls back both legs together.\n\nWhen NOT to use it: workflows where consume and produce represent a real wall-clock gap that downstream observers need to see (WIP dashboards, partial-run reporting, separate \"materials posted\" and \"production completed\" events on the dispatch bus). There, the two-call form is the right shape — each call is its own ledger event.\n\n### Location convention — explicit-arg design\n\nThe location where materials are consumed and finished goods are received is passed explicitly to `consumeMaterials` / `produceFinishedGoods`, not carried on the production order itself. Rationale:\n\n- The commerce `ProductionOrder` is a `Contract` STI subtype owned by `@happyvertical/smrt-commerce`. Adding an `originLocationId` field there would either need a schema change in commerce (cross-cutting) or a meta field that only manufacturing knows about (leaky).\n- Real shops often pick a location at run time (factory A is congested, route the run through factory B), so even if the order carried a default, the explicit-arg signature is the more flexible canonical form.\n- Callers that want a default can stash a `locationId` on their own production-order helper and pass it through.\n\n### Finished-SKU convention\n\nA `ProductionOrder` references a `productId`, but a `Product` typically has multiple SKUs (one per variant). The caller of `produceFinishedGoods` picks the concrete `finishedSkuId` because the multi-SKU mapping is application-specific (size run, finish mix, kit variant).\n\n## Opt-in DispatchBus hooks\n\nOff by default. Wire them up explicitly in the application's `smrt.ts`:\n\n```typescript\nimport { installManufacturingDispatchHandlers } from '@happyvertical/smrt-manufacturing';\n\nconst handlers = await installManufacturingDispatchHandlers({\n dispatchBus: bus,\n db,\n // Default: subscribe to production_order:posted, call consumeMaterials.\n installProductionPosted: true,\n // Default: don't auto-produce. Set to true if your shop emits a\n // separate production_order:completed event.\n installProductionCompleted: false,\n // Default: don't combine consume + produce on `posted`. Set to true\n // for make-to-stock-instantly workflows where the factory step is\n // invisible. Ignored when installProductionCompleted is true.\n producedOnPosted: false,\n});\n```\n\nThis subscribes to:\n\n- `production_order:posted` → `production.consumeMaterials(...)`; when `producedOnPosted: true` the handler instead calls `production.runProduction(...)` so consume + produce share one transaction. Process crashes or adapter errors between the two legs can never leave materials deducted with no finished-goods receipt.\n- `production_order:completed` → `production.produceFinishedGoods(...)` (opt-in)\n\nThe companion handlers for `contract:created` (reserve) and `fulfillment:shipped` (fulfil) live in `@happyvertical/smrt-inventory` — wire both packages' installers from `smrt.ts` to get the full lifecycle.\n\n## Tests\n\n`multilevel-suite.ts` (rolled back on PostgreSQL) and `production-run-suite.ts` (base handle, per-test tenant, for real concurrent transactions) follow the same SQLite / `*.optional.test.ts` pattern. `src/__tests__/assembly-suite.ts` runs on SQLite (`assembly.test.ts`) and on PostgreSQL (`assembly.optional.test.ts`, skipped without `DATABASE_URL`; `pnpm test:postgres` and the PostgreSQL CI lane run it on a transaction-scoped handle). Component tests under `src/svelte/__tests__` use jsdom and assert axe.\n\n## Gotchas\n\n- **`computeMaterialCost` without a resolver returns `$0`.** That is deliberate — manufacturing does not assume any particular cost source. A real wiring will plug in `@happyvertical/smrt-products` `Material.costPerUnit`, or a rolling average from purchase-order history, or a vendor price book. The `costUnavailable` flag tells UIs to surface \"unknown cost\" rather than silently rolling up zeros.\n- **`explodeRequirements` does not call any stock APIs.** It is a planning helper. To check whether the materials are actually on hand, use `canProduce`. To actually deduct them, use `ProductionService.consumeMaterials`.\n- **`canProduce` sums available stock across every location.** The planning question is \"do we have it at all?\". The operational question of \"which warehouse do we pull from?\" is left to the caller of `consumeMaterials`, which targets a single `locationId` per call.\n- **`consumeMaterials` propagates `InsufficientStockError`.** If a line would drive `available` below zero, the underlying `StockService.adjust` throws. Pre-flight with `canProduce` before posting if you want to avoid partial-failure mid-run.\n- **`consumeMaterials` is atomic across BOM lines.** All per-line deductions and their audit rows run inside a single `stockService.withTransaction(...)` scope (powered by `@happyvertical/sql >= 0.74.0`'s native `db.transaction()`). An `InsufficientStockError` on line N+1 rolls back lines 1..N so production-order posting never leaves materials half-consumed. The recommended pre-flight (`BomService.canProduce(orderId, qty)`) is still useful when you'd rather know upfront than discover the shortfall mid-run, but a missed pre-flight no longer corrupts state.\n- **`consumeMaterials` + `produceFinishedGoods` are NOT jointly atomic.** Each opens its own transaction. A failure on the produce leg leaves materials deducted with no finished SKU receipt to balance it. Use `runProduction(order, { consume, produce })` when you need both legs to commit or roll back together.\n- **Cross-package references are plain strings.** `BillOfMaterials.productId`, `BomLine.componentSkuId` and `BomLine.bomId` are plain string ids (changing them to UUID references needs a migration window); the newer models (`RoutingStep`, `ProductionRun`, `ProductionRunCompletion`) reference this package's own models with `@foreignKey`. The package does depend on `smrt-products` (for `Assembly` and the resolve helper), but the bill schema does not couple to the catalog's table layout.\n- **`Assembly` fields are columns, not `Meta<T>`.** Unlike `Material`, its own fields are ordinary columns this package adds to `products` (filterable over REST). The PostgreSQL suite asserts they land there.\n- **`AssemblyCollection` lists exact `Assembly` rows.** An application subtype (e.g. one adding a customer) has its own `_meta_type`; read it through its own collection or `ProductCollection` (`resolveComponent` uses `instanceof Assembly`, so subtypes resolve as assemblies).\n- **`conflictColumns` include `tenant_id`** on both models. NULL-matching semantics are handled by `@happyvertical/sql >= 0.74.0`; two saves with the same `(product_id, version, NULL)` tuple merge in place.\n- **Lazy table creation.** Like everything else in SMRT, the `manufacturing_boms` and `manufacturing_bom_lines` tables are created on first DB op via `syncSchema`. Safe for SSR. A `BomLine` save now reads `product_skus` and `products` for the cycle check.\n- **Cross-industry constraint.** This package's vocabulary stays generic. Apparel-specific concepts (`Style`, `Makeup`, `Colorway`, `tech-pack`, fashion `Season`) and their analogues in furniture / automotive / CPG live in the relevant template package, never here. PRs that introduce industry vocabulary should be rejected.\n\n## Source attribution\n\nEvery emitted `StockMovement` carries `sourceType: 'ProductionOrder'` plus `sourceId: order.id` so downstream queries can reconstruct \"what caused this movement\". Reason codes used:\n\n| reasonCode | Emitter | Note |\n|---|---|---|\n| `production_consume` | `ProductionService.consumeMaterials` | One per BOM line per consume call |\n| `production_produce` | `ProductionService.produceFinishedGoods` | One per produce call |\n| either, with `sourceType: 'ProductionRunCompletion'` | `ProductionRunService.recordCompletion` | Only when the caller passes `consume` / `produce` |\n\nThese join cleanly with the standard inventory reason codes (`receipt`, `reservation`, `release`, `fulfillment`, `transfer_out`, `transfer_in`, `adjustment`) defined in `@happyvertical/smrt-inventory`.\n\n## Dependencies\n\n| Package | Purpose |\n|---|---|\n| `@happyvertical/smrt-core` | SmrtObject / SmrtCollection / DispatchBus |\n| `@happyvertical/smrt-inventory` | StockService, stock levels, movements (the `Sku` model itself lives in `@happyvertical/smrt-products`; inventory tracks stock motion against the id) |\n| `@happyvertical/smrt-products` | `Product` (the `Assembly` STI base), `Material`, `Sku` for the resolve helper and cycle check |\n| `@happyvertical/smrt-fields` | `ObjectForm` and field-policy column visibility for the Svelte components |\n| `@happyvertical/smrt-ui` / `smrt-types` | Svelte controls, i18n, module UI slots |\n| `@happyvertical/smrt-tenancy` | Optional tenant scoping |\n| `@happyvertical/sql` | Database adapter |\n",
|
|
2384
|
+
"agentDoc": "# @happyvertical/smrt-manufacturing\n\nBills of materials (multi-level through sub-assemblies), operations and routing, cost and labour rollup, production runs, and production-order stock movement. Strictly industry-neutral — the same primitives serve apparel, furniture, automotive, CPG, electronics, food production, custom hardware, and any vertical that builds finished goods from a recipe.\n\nSits on top of `@happyvertical/smrt-inventory` (stock) and `@happyvertical/smrt-products` (catalog: `Product`, `Material`, `Sku`), and works alongside the `ProductionOrder` Contract STI subtype already shipped in `@happyvertical/smrt-commerce`.\n\n## Models\n\n| Model | Purpose |\n|---|---|\n| `Assembly` | The product that is **made**, counterpart to `Material`. Cross-package STI subtype of `smrt-products` `Product` (`productType: 'assembly'`, `_meta_type: '@happyvertical/smrt-manufacturing:Assembly'`) in the shared `products` table. Own columns: `estimatedLabourMinutes` (integer, per unit; a save refuses anything but a whole number of minutes of zero or more), `defaultOperationId` (`@foreignKey(Operation)`, nullable, RESTRICT like `RoutingStep.operationId`: the operation work on it is booked to by default), `partReference` (the organization's drawing/part number). Name, price, tags come from `Product`; part number and stock from its `Sku` and inventory; structure from its bill; documents from `ProductAsset`. Exposure matches `Product` (REST list/get/create/update, MCP list/get), as the issue asks: unlike `Operation`, the assembly row has no service-owned invariant that generated writes could bypass. |\n| `BillOfMaterials` | Recipe for a finished product. `productId` (plain string) references the upstream `Product` or any STI subtype. Multiple revisions per product via `version` + `status` (`draft` / `active` / `superseded`). `conflictColumns: ['product_id', 'version', 'tenant_id']`. |\n| `BomLine` | One component on a BOM. `bomId` (FK), `componentSkuId` (plain string ref — the `Sku` model lives in `@happyvertical/smrt-products`; inventory tracks stock motion against the id), `qtyPerUnit`, `uom` (open-ended — `yards`, `each`, `grams`, `kg`, ...), `wastePercent`, `notes`. `conflictColumns: ['bom_id', 'component_sku_id', 'tenant_id']`. |\n| `Operation` | A kind of work (cut, weld, inspect), a managed list per tenant. `code` (unique per tenant; `conflictColumns: ['code', 'tenant_id']`, fixed once defined), `name`, `category`, `isActive` (retire/reinstate; never deleted, `delete()` throws), `requiredQualificationId` (nullable `@crossPackageRef('@happyvertical/smrt-human-resources:Qualification')`: metadata only, no dependency, unvalidated; an application reads it to gate who may start the operation). |\n| `ProductionRun` | A build against one bill, reported as it happens (\"25 to build, 12 done\"). `bomId` (`@foreignKey(BillOfMaterials)`, RESTRICT: pinned when created), `targetQty` and `completedQty` (decimal; completed is the sum of completions), `status` (`planned` / `in_progress` / `done` / `cancelled`). Generated list/get only; `ProductionRunService` owns writes. |\n| `ProductionRunCompletion` | One dated report on a run: `runId` (`@foreignKey(ProductionRun)`, CASCADE), `qty` (decimal, > 0), `completedAt`. Generated list/get only. |\n| `RoutingStep` | One operation in a BOM's optional routing. `bomId` (`@foreignKey(BillOfMaterials)`, CASCADE: a routing belongs to its bill), `operationId` (`@foreignKey(Operation)`, RESTRICT: operations are retired, never deleted), `sequence` (1..n, unique per bom), `estimatedMinutes` (decimal, per produced unit), `notes`. `conflictColumns: ['bom_id', 'sequence', 'tenant_id']`. |\n\nAll models are `@TenantScoped({ mode: 'optional' })` with a nullable `tenantId` so they can be used either tenant-scoped or globally.\n\n## Operations, routing and labour estimate\n\n- `OperationService` maintains the list (`define` rejects a duplicate code, including a retired one's; `rename`, `update`, `retire`, `reinstate`). `RoutingService.replaceRouting(bomId, steps)` swaps a bill's whole routing in one transaction and numbers it 1..n; a retired operation may stay on a routing that has it but cannot be newly added.\n- `BomService.computeLabourEstimate(bomId)` returns minutes and, only when the caller supplies `rateResolver` (hourly rate per `Operation`, mirroring `costResolver`), cost. No resolver means minutes only with `rateUnavailable` on each step. A bill with no routing returns an empty estimate; `computeMaterialCost` is unchanged.\n- `Operation` and `RoutingStep` expose generated list/get only; writes go through the services (generated create/update would upsert on a duplicate code or rename the code). `replaceRouting` saves the bill row inside its transaction (row lock) and retries on a revision conflict, so concurrent replacements serialize.\n- Deliberately absent: a default labour rate class (nothing here would use it; the resolver receives the whole `Operation` and can key on `code`/`category`), setup time, scheduling and work-centre capacity, and time recorded against an operation (that stays in `smrt-timesheets` or the application).\n- `./svelte` exports `OperationList` and `OperationForm` (props-driven; hosts persist through `OperationService`). Messages live in `src/svelte/i18n.ts`; component tests use the shared jsdom harness with axe assertions.\n- Tests: `operations-suite.ts` runs on SQLite (`operations.test.ts`) and PostgreSQL (`operations.optional.test.ts`, `pnpm test:postgres`; each test runs in its own tenant because PostgreSQL test data persists).\n\n## Assemblies — nesting lives in the bill\n\nA sub-assembly is a `BomLine` whose component SKU belongs to an `Assembly`; there is no children list on the model. `AssemblyService` is the one link from a line to what it names:\n\n| Method | Behavior |\n|---|---|\n| `resolveComponent(skuId, { tenantId? })` | `{ kind, sku, product, assembly, activeBom, buildable }`. `kind` is `assembly`, `material` (`Material`), `bought` (any other `Product`), or `missing` (unknown SKU, SKU with no product, or a non-UUID id; never throws). `activeBom` is the assembly's highest active bill, `null` when it has none; `buildable` is `assembly && activeBom`. Multi-level explosion (#3444) recurses on `activeBom` and stops at every other kind. |\n| `isAssembly(skuId)` | `resolveComponent(skuId).kind === 'assembly'`. |\n| `findActiveBom(productId, { tenantId? })` | Highest active bill. With `tenantId` (including `null`), that tenant's own bill, else a global one, and `resolveComponent` reads the SKU and product as that tenant's or global (through `tenant-scope.ts`, so a shared global component stays visible under a tenant context) and reports another tenant's as `missing`, whatever the tenant context; the cycle walk and `getBillStructure` pass the bill's own tenant, so a shared assembly resolves to the right tenant's bill on writes made without `withTenant()`. |\n| `getBillStructure(bomId)` | One level: the bill plus each line with its resolved component. Throws `BomNotFoundError`. |\n| `findCycle(productId, componentSkuIds)` | The path by which those components would make `productId` contain itself, following sub-assemblies' **active** bills only; `null` when none. |\n| `assertLineAcyclic(line)` / `assertBillAcyclic(bom)` | Throw `BomCycleError` (a `ValidationError`, code `MANUFACTURING_BOM_CYCLE`, `path` from the product back to itself). |\n\n**Cycle refusal runs in the models.** `BomLine.validateBeforeSave` checks every line save (draft bills too, so a loop is refused when written); `BillOfMaterials.validateBeforeSave` checks every save of an `active` bill (activation), including the lines of a stored bill with the same `(productId, version, tenantId)` that the save would upsert onto. The generated REST routes go through `save()`, so they refuse cycles as well. Not covered: re-pointing a `Sku.productId` (owned by `smrt-products`) and two concurrent saves that each close half of a loop.\n\n## Multi-level walks and production runs\n\nDetail: [agents/multilevel-and-runs.md](agents/multilevel-and-runs.md).\n\n- Every `BomService` method takes `{ levels }` (default `1`, unchanged; up to `MAX_EXPLOSION_DEPTH` = 32, or `'all'`). One walk (`services/structure-walk.ts`) serves `explode` (gross lines and totals), `planRequirements` (net of stock: available, short, what building a shortfall takes; facts, no make-or-buy policy), `canProduce`, cost and labour. A loop already in stored data fails with `BomStructureCycleError`; size limits with `BomExplosionLimitError`.\n- `ProductionRunService` writes `ProductionRun` / `ProductionRunCompletion` in one transaction per call, locking the run row through its revision-guarded save and retrying on a revision conflict; no adapter without `transaction()`. Stock moves only when the caller passes `consume` / `produce`.\n- A run is not commerce's `ProductionOrder` (a `Contract` with terms and money, in a package this one does not depend on); an application that has both links them.\n\n## Svelte components (`./svelte`)\n\nProps-driven; the host loads and persists. `AssemblyList` (a structural `policy` drops hidden columns), `AssemblyForm` (smrt-ui controls like `OperationForm`: `assembly`, `onsubmit`, `operations` for the default-operation picker, a retired or unlisted current operation stays selected and marked, `hiddenFields`/`readonlyFields` for the reader's field policy; price is major units in the form and integer minor units in `onsubmit`; `validateAssemblyForm` mirrors the model's whole-minutes rule). `smrt-fields` is not a dependency: never add `ObjectForm`, `BomEditor` (add/edit/remove lines through host handlers; a sub-assembly shows whether it has its own bill and expands read-only through `loadBill`), `BomStructureTree` (the read-only nested view). `ProductionRunList` (progress, status, and with `oncomplete` a quantity field per open run; rows from `toProductionRunView`), `RequirementsTree` (read-only `explode` / `planRequirements` result by level with totals; `toRequirementTree`, `toRequirementTotals`; internal `RequirementsTreeLevel`). Adapters: `toAssemblyView`, `toBomEditorLines`. Strings are under `manufacturing.` in `src/svelte/i18n.ts`; the package is strict for raw primitives, hardcoded strings and JSDoc.\n\n\n## BomService — planning helpers\n\n```typescript\nimport { BomService } from '@happyvertical/smrt-manufacturing';\n\nconst bom = await BomService.create({\n db,\n // Optional. Resolve unit cost for a component SKU.\n // Without this, every line rolls up to $0 and `costUnavailable` is set.\n costResolver: async (componentSkuId) => fetchLatestCost(componentSkuId),\n});\n\nconst rollup = await bom.computeMaterialCost(bomId);\n// { totalCost, currency, lineBreakdown, hasMissingCosts }\n\nconst requirements = await bom.explodeRequirements(bomId, 100);\n// [{ componentSkuId, totalQty, uom }, ...]\n\nconst check = await bom.canProduce(bomId, 100);\n// { ok: true } | { ok: false, shortages: [...] }\n```\n\n| Method | Behavior |\n|---|---|\n| `computeMaterialCost(bomId)` | Walks every BomLine, applies waste (`qtyPerUnit * (1 + wastePercent / 100)`), resolves unit costs via the optional `costResolver`, returns per-line breakdown plus rolled-up total. Lines with no cost set `costUnavailable: true` and contribute `0`. |\n| `explodeRequirements(bomId, qty)` | Returns a \"shopping list\" of materials needed for `qty` units. Duplicates across lines are summed. Does NOT mutate stock. |\n| `canProduce(bomId, qty)` | Calls `explodeRequirements`, then sums `available` stock across every location per component, returns `{ ok: true }` if everything's covered, else `{ ok: false, shortages: [...] }`. |\n| `explode` / `planRequirements` | Multi-level walks; see \"Multi-level walks\" above. Each method above also takes `{ levels }`. |\n\n## ProductionService — consume / produce\n\n```typescript\nimport { ProductionService } from '@happyvertical/smrt-manufacturing';\n\nconst production = await ProductionService.create({ db });\n\n// Drain materials at the factory.\nconst consumed = await production.consumeMaterials(\n { id: order.id, productId: order.productId, bomId: order.bomId },\n { locationId: factory.id, qty: runQty },\n);\n\n// Receive finished goods.\nconst produced = await production.produceFinishedGoods(\n { id: order.id, productId: order.productId },\n { locationId: factory.id, qty: runQty, finishedSkuId: variant.id },\n);\n\n// Or run both in one transaction — see \"Joint atomicity\" below.\nconst { consumed, produced } = await production.runProduction(\n { id: order.id, productId: order.productId, bomId: order.bomId },\n {\n consume: { locationId: factory.id, qty: runQty },\n produce: { locationId: factory.id, qty: runQty, finishedSkuId: variant.id },\n },\n);\n```\n\nAll three methods write through `StockService` and stamp every emitted `StockMovement` with `sourceType: 'ProductionOrder'` (override with the `sourceType` option, as `ProductionRunService` does) + the production order id so audit queries can roll them up later.\n\n### Joint atomicity — `runProduction` vs the two-call form\n\n`consumeMaterials` and `produceFinishedGoods` are each individually atomic, but calling them as two separate awaits is NOT jointly atomic — each opens its own `stockService.withTransaction(...)` scope. If something goes wrong between the two calls (process crash, transient adapter failure on the produce leg), you can land in a state where materials are deducted but no finished SKU receipt balances them. The audit ledger stays consistent within each call; what's missing is the cross-call invariant.\n\nWhen you need that invariant — typically make-to-stock flows where the factory step is invisible to the ledger — use `runProduction(order, { consume, produce })`. Both legs run inside one transaction; any failure (BOM shortage, adapter error, interceptor reject) rolls back both legs together.\n\nWhen NOT to use it: workflows where consume and produce represent a real wall-clock gap that downstream observers need to see (WIP dashboards, partial-run reporting, separate \"materials posted\" and \"production completed\" events on the dispatch bus). There, the two-call form is the right shape — each call is its own ledger event.\n\n### Location convention — explicit-arg design\n\nThe location where materials are consumed and finished goods are received is passed explicitly to `consumeMaterials` / `produceFinishedGoods`, not carried on the production order itself. Rationale:\n\n- The commerce `ProductionOrder` is a `Contract` STI subtype owned by `@happyvertical/smrt-commerce`. Adding an `originLocationId` field there would either need a schema change in commerce (cross-cutting) or a meta field that only manufacturing knows about (leaky).\n- Real shops often pick a location at run time (factory A is congested, route the run through factory B), so even if the order carried a default, the explicit-arg signature is the more flexible canonical form.\n- Callers that want a default can stash a `locationId` on their own production-order helper and pass it through.\n\n### Finished-SKU convention\n\nA `ProductionOrder` references a `productId`, but a `Product` typically has multiple SKUs (one per variant). The caller of `produceFinishedGoods` picks the concrete `finishedSkuId` because the multi-SKU mapping is application-specific (size run, finish mix, kit variant).\n\n## Opt-in DispatchBus hooks\n\nOff by default. Wire them up explicitly in the application's `smrt.ts`:\n\n```typescript\nimport { installManufacturingDispatchHandlers } from '@happyvertical/smrt-manufacturing';\n\nconst handlers = await installManufacturingDispatchHandlers({\n dispatchBus: bus,\n db,\n // Default: subscribe to production_order:posted, call consumeMaterials.\n installProductionPosted: true,\n // Default: don't auto-produce. Set to true if your shop emits a\n // separate production_order:completed event.\n installProductionCompleted: false,\n // Default: don't combine consume + produce on `posted`. Set to true\n // for make-to-stock-instantly workflows where the factory step is\n // invisible. Ignored when installProductionCompleted is true.\n producedOnPosted: false,\n});\n```\n\nThis subscribes to:\n\n- `production_order:posted` → `production.consumeMaterials(...)`; when `producedOnPosted: true` the handler instead calls `production.runProduction(...)` so consume + produce share one transaction. Process crashes or adapter errors between the two legs can never leave materials deducted with no finished-goods receipt.\n- `production_order:completed` → `production.produceFinishedGoods(...)` (opt-in)\n\nThe companion handlers for `contract:created` (reserve) and `fulfillment:shipped` (fulfil) live in `@happyvertical/smrt-inventory` — wire both packages' installers from `smrt.ts` to get the full lifecycle.\n\n## Tests\n\n`multilevel-suite.ts` (rolled back on PostgreSQL) and `production-run-suite.ts` (base handle, per-test tenant, for real concurrent transactions) follow the same SQLite / `*.optional.test.ts` pattern. `src/__tests__/assembly-suite.ts` runs on SQLite (`assembly.test.ts`) and on PostgreSQL (`assembly.optional.test.ts`, skipped without `DATABASE_URL`; `pnpm test:postgres` and the PostgreSQL CI lane run it on a transaction-scoped handle). Component tests under `src/svelte/__tests__` use jsdom and assert axe.\n\n## Gotchas\n\n- **`computeMaterialCost` without a resolver returns `$0`.** That is deliberate — manufacturing does not assume any particular cost source. A real wiring will plug in `@happyvertical/smrt-products` `Material.costPerUnit`, or a rolling average from purchase-order history, or a vendor price book. The `costUnavailable` flag tells UIs to surface \"unknown cost\" rather than silently rolling up zeros.\n- **`explodeRequirements` does not call any stock APIs.** It is a planning helper. To check whether the materials are actually on hand, use `canProduce`. To actually deduct them, use `ProductionService.consumeMaterials`.\n- **`canProduce` sums available stock across every location.** The planning question is \"do we have it at all?\". The operational question of \"which warehouse do we pull from?\" is left to the caller of `consumeMaterials`, which targets a single `locationId` per call.\n- **`consumeMaterials` propagates `InsufficientStockError`.** If a line would drive `available` below zero, the underlying `StockService.adjust` throws. Pre-flight with `canProduce` before posting if you want to avoid partial-failure mid-run.\n- **`consumeMaterials` is atomic across BOM lines.** All per-line deductions and their audit rows run inside a single `stockService.withTransaction(...)` scope (powered by `@happyvertical/sql >= 0.74.0`'s native `db.transaction()`). An `InsufficientStockError` on line N+1 rolls back lines 1..N so production-order posting never leaves materials half-consumed. The recommended pre-flight (`BomService.canProduce(orderId, qty)`) is still useful when you'd rather know upfront than discover the shortfall mid-run, but a missed pre-flight no longer corrupts state.\n- **`consumeMaterials` + `produceFinishedGoods` are NOT jointly atomic.** Each opens its own transaction. A failure on the produce leg leaves materials deducted with no finished SKU receipt to balance it. Use `runProduction(order, { consume, produce })` when you need both legs to commit or roll back together.\n- **Cross-package references are plain strings.** `BillOfMaterials.productId`, `BomLine.componentSkuId` and `BomLine.bomId` are plain string ids (changing them to UUID references needs a migration window); the newer models (`RoutingStep`, `ProductionRun`, `ProductionRunCompletion`) reference this package's own models with `@foreignKey`. The package does depend on `smrt-products` (for `Assembly` and the resolve helper), but the bill schema does not couple to the catalog's table layout.\n- **`Assembly` fields are columns, not `Meta<T>`.** Unlike `Material`, its own fields are ordinary columns this package adds to `products` (filterable over REST). The PostgreSQL suite asserts they land there.\n- **`AssemblyCollection` lists exact `Assembly` rows.** An application subtype (e.g. one adding a customer) has its own `_meta_type`; read it through its own collection or `ProductCollection` (`resolveComponent` uses `instanceof Assembly`, so subtypes resolve as assemblies).\n- **`conflictColumns` include `tenant_id`** on both models. NULL-matching semantics are handled by `@happyvertical/sql >= 0.74.0`; two saves with the same `(product_id, version, NULL)` tuple merge in place.\n- **Lazy table creation.** Like everything else in SMRT, the `manufacturing_boms` and `manufacturing_bom_lines` tables are created on first DB op via `syncSchema`. Safe for SSR. A `BomLine` save now reads `product_skus` and `products` for the cycle check.\n- **Cross-industry constraint.** This package's vocabulary stays generic. Apparel-specific concepts (`Style`, `Makeup`, `Colorway`, `tech-pack`, fashion `Season`) and their analogues in furniture / automotive / CPG live in the relevant template package, never here. PRs that introduce industry vocabulary should be rejected.\n\n## Source attribution\n\nEvery emitted `StockMovement` carries `sourceType: 'ProductionOrder'` plus `sourceId: order.id` so downstream queries can reconstruct \"what caused this movement\". Reason codes used:\n\n| reasonCode | Emitter | Note |\n|---|---|---|\n| `production_consume` | `ProductionService.consumeMaterials` | One per BOM line per consume call |\n| `production_produce` | `ProductionService.produceFinishedGoods` | One per produce call |\n| either, with `sourceType: 'ProductionRunCompletion'` | `ProductionRunService.recordCompletion` | Only when the caller passes `consume` / `produce` |\n\nThese join cleanly with the standard inventory reason codes (`receipt`, `reservation`, `release`, `fulfillment`, `transfer_out`, `transfer_in`, `adjustment`) defined in `@happyvertical/smrt-inventory`.\n\n## Dependencies\n\n| Package | Purpose |\n|---|---|\n| `@happyvertical/smrt-core` | SmrtObject / SmrtCollection / DispatchBus |\n| `@happyvertical/smrt-inventory` | StockService, stock levels, movements (the `Sku` model itself lives in `@happyvertical/smrt-products`; inventory tracks stock motion against the id) |\n| `@happyvertical/smrt-products` | `Product` (the `Assembly` STI base), `Material`, `Sku` for the resolve helper and cycle check |\n| `@happyvertical/smrt-ui` / `smrt-types` | Svelte controls, i18n, module UI slots |\n| `@happyvertical/smrt-tenancy` | Optional tenant scoping |\n| `@happyvertical/sql` | Database adapter |\n",
|
|
2387
2385
|
"moduleDocs": [
|
|
2388
2386
|
{
|
|
2389
2387
|
"path": "agents/multilevel-and-runs.md",
|