@kernhq/module-inventory 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/README.md +106 -25
  2. package/dist/contract/capabilities.d.ts +4 -4
  3. package/dist/contract/capabilities.d.ts.map +1 -1
  4. package/dist/contract/capabilities.js +51 -9
  5. package/dist/contract/capabilities.js.map +1 -1
  6. package/dist/contract/events.d.ts +43 -0
  7. package/dist/contract/events.d.ts.map +1 -1
  8. package/dist/contract/events.js +40 -0
  9. package/dist/contract/events.js.map +1 -1
  10. package/dist/contract/index.d.ts +1 -0
  11. package/dist/contract/index.d.ts.map +1 -1
  12. package/dist/contract/index.js +1 -0
  13. package/dist/contract/index.js.map +1 -1
  14. package/dist/contract/models.d.ts +345 -0
  15. package/dist/contract/models.d.ts.map +1 -1
  16. package/dist/contract/models.js +245 -0
  17. package/dist/contract/models.js.map +1 -1
  18. package/dist/contract/notifications.d.ts +24 -0
  19. package/dist/contract/notifications.d.ts.map +1 -0
  20. package/dist/contract/notifications.js +72 -0
  21. package/dist/contract/notifications.js.map +1 -0
  22. package/dist/contract/permissions.d.ts +52 -2
  23. package/dist/contract/permissions.d.ts.map +1 -1
  24. package/dist/contract/permissions.js +55 -2
  25. package/dist/contract/permissions.js.map +1 -1
  26. package/dist/contract/router.d.ts +1108 -0
  27. package/dist/contract/router.d.ts.map +1 -1
  28. package/dist/contract/router.js +253 -1
  29. package/dist/contract/router.js.map +1 -1
  30. package/dist/contract/settings.d.ts +2 -0
  31. package/dist/contract/settings.d.ts.map +1 -1
  32. package/dist/contract/settings.js +24 -4
  33. package/dist/contract/settings.js.map +1 -1
  34. package/dist/server/index.d.ts +8 -4
  35. package/dist/server/index.d.ts.map +1 -1
  36. package/dist/server/index.js +289 -5
  37. package/dist/server/index.js.map +1 -1
  38. package/dist/server/jobs.d.ts +48 -0
  39. package/dist/server/jobs.d.ts.map +1 -0
  40. package/dist/server/jobs.js +358 -0
  41. package/dist/server/jobs.js.map +1 -0
  42. package/dist/server/router.d.ts +1392 -0
  43. package/dist/server/router.d.ts.map +1 -1
  44. package/dist/server/router.js +385 -7
  45. package/dist/server/router.js.map +1 -1
  46. package/dist/server/schema.d.ts +134 -1
  47. package/dist/server/schema.d.ts.map +1 -1
  48. package/dist/server/schema.js +169 -4
  49. package/dist/server/schema.js.map +1 -1
  50. package/dist/server/services/assets.d.ts +69 -3
  51. package/dist/server/services/assets.d.ts.map +1 -1
  52. package/dist/server/services/assets.js +199 -31
  53. package/dist/server/services/assets.js.map +1 -1
  54. package/dist/server/services/attachments.d.ts +80 -0
  55. package/dist/server/services/attachments.d.ts.map +1 -0
  56. package/dist/server/services/attachments.js +182 -0
  57. package/dist/server/services/attachments.js.map +1 -0
  58. package/dist/server/services/audience.d.ts +15 -0
  59. package/dist/server/services/audience.d.ts.map +1 -0
  60. package/dist/server/services/audience.js +64 -0
  61. package/dist/server/services/audience.js.map +1 -0
  62. package/dist/server/services/categories.d.ts +157 -0
  63. package/dist/server/services/categories.d.ts.map +1 -0
  64. package/dist/server/services/categories.js +309 -0
  65. package/dist/server/services/categories.js.map +1 -0
  66. package/dist/server/services/cursor.d.ts +68 -0
  67. package/dist/server/services/cursor.d.ts.map +1 -0
  68. package/dist/server/services/cursor.js +39 -0
  69. package/dist/server/services/cursor.js.map +1 -0
  70. package/dist/server/services/custody.d.ts +175 -0
  71. package/dist/server/services/custody.d.ts.map +1 -0
  72. package/dist/server/services/custody.js +367 -0
  73. package/dist/server/services/custody.js.map +1 -0
  74. package/dist/server/services/db-errors.d.ts +7 -0
  75. package/dist/server/services/db-errors.d.ts.map +1 -0
  76. package/dist/server/services/db-errors.js +32 -0
  77. package/dist/server/services/db-errors.js.map +1 -0
  78. package/dist/server/services/index.d.ts +16 -0
  79. package/dist/server/services/index.d.ts.map +1 -1
  80. package/dist/server/services/index.js +25 -1
  81. package/dist/server/services/index.js.map +1 -1
  82. package/dist/server/services/members.d.ts +27 -0
  83. package/dist/server/services/members.d.ts.map +1 -0
  84. package/dist/server/services/members.js +39 -0
  85. package/dist/server/services/members.js.map +1 -0
  86. package/dist/server/services/notify.d.ts +43 -1
  87. package/dist/server/services/notify.d.ts.map +1 -1
  88. package/dist/server/services/notify.js +47 -5
  89. package/dist/server/services/notify.js.map +1 -1
  90. package/dist/server/services/offboarding.d.ts +70 -0
  91. package/dist/server/services/offboarding.d.ts.map +1 -0
  92. package/dist/server/services/offboarding.js +116 -0
  93. package/dist/server/services/offboarding.js.map +1 -0
  94. package/dist/server/services/repairs.d.ts +204 -0
  95. package/dist/server/services/repairs.d.ts.map +1 -0
  96. package/dist/server/services/repairs.js +476 -0
  97. package/dist/server/services/repairs.js.map +1 -0
  98. package/dist/server/services/search.d.ts +85 -0
  99. package/dist/server/services/search.d.ts.map +1 -0
  100. package/dist/server/services/search.js +142 -0
  101. package/dist/server/services/search.js.map +1 -0
  102. package/dist/server/services/stats.d.ts +42 -0
  103. package/dist/server/services/stats.d.ts.map +1 -0
  104. package/dist/server/services/stats.js +80 -0
  105. package/dist/server/services/stats.js.map +1 -0
  106. package/dist/server/services/status.d.ts +102 -0
  107. package/dist/server/services/status.d.ts.map +1 -0
  108. package/dist/server/services/status.js +71 -0
  109. package/dist/server/services/status.js.map +1 -0
  110. package/migrations/0002_custody_and_categories.sql +23 -0
  111. package/migrations/0003_repairs.sql +23 -0
  112. package/migrations/0004_platform_surfaces.sql +51 -0
  113. package/migrations/0005_repair_dates.sql +35 -0
  114. package/migrations/0006_workspace_registry_read.sql +50 -0
  115. package/migrations/0007_history_sequence.sql +83 -0
  116. package/migrations/0008_category_order_unique.sql +71 -0
  117. package/migrations/meta/0002_snapshot.json +1054 -0
  118. package/migrations/meta/0003_snapshot.json +1070 -0
  119. package/migrations/meta/0004_snapshot.json +1130 -0
  120. package/migrations/meta/0005_snapshot.json +1135 -0
  121. package/migrations/meta/_journal.json +49 -0
  122. package/package.json +2 -1
  123. package/src/client/api-instance.ts +27 -2
  124. package/src/client/bidi.test.ts +148 -0
  125. package/src/client/bidi.ts +85 -0
  126. package/src/client/components/AssetDetailPanel.svelte +614 -0
  127. package/src/client/components/AssetFormDialog.svelte +71 -22
  128. package/src/client/components/AssetPhoto.svelte +178 -0
  129. package/src/client/components/AttachmentsSection.svelte +327 -0
  130. package/src/client/components/CustodyDialog.svelte +201 -0
  131. package/src/client/components/RepairDialog.svelte +271 -0
  132. package/src/client/components/RepairsSection.svelte +318 -0
  133. package/src/client/components/Timeline.svelte +347 -0
  134. package/src/client/components/TimelineText.svelte +124 -0
  135. package/src/client/core-api.ts +71 -0
  136. package/src/client/custody.test.ts +31 -0
  137. package/src/client/custody.ts +34 -0
  138. package/src/client/errors.test.ts +395 -0
  139. package/src/client/errors.ts +229 -0
  140. package/src/client/links.test.ts +74 -0
  141. package/src/client/links.ts +44 -0
  142. package/src/client/members.test.ts +132 -0
  143. package/src/client/members.ts +116 -0
  144. package/src/client/messages.test.ts +127 -0
  145. package/src/client/messages.ts +1106 -18
  146. package/src/client/mock.test.ts +465 -1
  147. package/src/client/mock.ts +1105 -79
  148. package/src/client/module.ts +73 -1
  149. package/src/client/pages/AssetsPage.svelte +317 -45
  150. package/src/client/permissions.ts +7 -0
  151. package/src/client/price.test.ts +151 -3
  152. package/src/client/price.ts +155 -11
  153. package/src/client/query.ts +36 -0
  154. package/src/client/reorder.test.ts +100 -0
  155. package/src/client/reorder.ts +79 -0
  156. package/src/client/repairs.test.ts +38 -0
  157. package/src/client/repairs.ts +38 -0
  158. package/src/client/sequence.test.ts +248 -0
  159. package/src/client/sequence.ts +185 -0
  160. package/src/client/settings/CategoriesSettings.svelte +746 -0
  161. package/src/client/settings/GeneralSettings.svelte +0 -0
  162. package/src/client/status.ts +29 -0
  163. package/src/client/timeline.test.ts +175 -0
  164. package/src/client/timeline.ts +206 -0
  165. package/src/client/widgets/OverviewWidget.svelte +127 -26
  166. package/src/client/widgets/RepairsWidget.svelte +124 -0
  167. package/src/contract/capabilities.ts +53 -9
  168. package/src/contract/events.ts +49 -0
  169. package/src/contract/index.ts +1 -0
  170. package/src/contract/models.ts +270 -0
  171. package/src/contract/notifications.ts +73 -0
  172. package/src/contract/permissions.ts +55 -2
  173. package/src/contract/router.ts +284 -1
  174. package/src/contract/settings.ts +24 -4
  175. package/src/module.test.ts +217 -4
  176. package/src/server/index.ts +311 -4
  177. package/src/server/inventory.int.test.ts +4109 -19
  178. package/src/server/jobs.ts +444 -0
  179. package/src/server/migrations.test.ts +253 -2
  180. package/src/server/router.ts +486 -6
  181. package/src/server/schema.ts +171 -3
  182. package/src/server/services/assets.ts +214 -54
  183. package/src/server/services/attachments.ts +215 -0
  184. package/src/server/services/audience.ts +77 -0
  185. package/src/server/services/categories.ts +337 -0
  186. package/src/server/services/cursor.ts +104 -0
  187. package/src/server/services/custody.ts +471 -0
  188. package/src/server/services/db-errors.ts +42 -0
  189. package/src/server/services/index.ts +34 -1
  190. package/src/server/services/members.ts +54 -0
  191. package/src/server/services/notify.ts +52 -7
  192. package/src/server/services/offboarding.ts +150 -0
  193. package/src/server/services/repairs.ts +567 -0
  194. package/src/server/services/search.ts +166 -0
  195. package/src/server/services/stats.ts +88 -0
  196. package/src/server/services/status.test.ts +34 -0
  197. package/src/server/services/status.ts +143 -0
  198. package/src/client/settings/core-api.ts +0 -32
@@ -14,6 +14,12 @@ export declare const MODULE_ID = "inventory";
14
14
  *
15
15
  * Stored rather than derived, because every list filter asks for it — and kept in step inside the
16
16
  * same transaction that writes the row it derives from, never by a job afterwards.
17
+ *
18
+ * **`under_repair` belongs to the `repairs` capability**, so a workspace with that switch off never
19
+ * has an asset in it: the procedure that ends a repair answers 404 there, and a status nothing can
20
+ * move an item out of is a register the workspace cannot correct. The one thing a job does here is
21
+ * bring the rows *nobody touches* back into step after that switch moves, in both directions —
22
+ * `deriveStatus` in `src/server/services/status.ts` argues it, and nothing is destroyed either way.
17
23
  */
18
24
  export declare const AssetStatus: z.ZodEnum<{
19
25
  in_stock: "in_stock";
@@ -33,6 +39,99 @@ export type AssetStatus = z.infer<typeof AssetStatus>;
33
39
  */
34
40
  export declare const CustomValues: z.ZodRecord<z.ZodString, z.ZodUnknown>;
35
41
  export type CustomValues = z.infer<typeof CustomValues>;
42
+ /**
43
+ * A workspace's own grouping of what it owns — Laptops, Furniture, Cameras.
44
+ *
45
+ * Archived rather than deleted, and `archivedAt` is the whole reason: `assets.category_id` is a
46
+ * plain uuid with no foreign key, so a deleted category leaves every asset filed under it pointing
47
+ * at a row that is not there. The list column goes blank and the timeline entry that recorded the
48
+ * move loses the name it recorded. Archiving takes it out of every picker and every filter and
49
+ * leaves each asset able to say what it is.
50
+ */
51
+ export declare const Category: z.ZodObject<{
52
+ id: z.ZodUUID;
53
+ workspaceId: z.core.$ZodBranded<z.ZodUUID, "WorkspaceId", "out">;
54
+ name: z.ZodString;
55
+ order: z.ZodNumber;
56
+ createdAt: z.ZodString;
57
+ updatedAt: z.ZodString;
58
+ archivedAt: z.ZodNullable<z.ZodString>;
59
+ }, z.core.$strip>;
60
+ export type Category = z.infer<typeof Category>;
61
+ /**
62
+ * What a person types when they add or rename a category: a name, and nothing else.
63
+ *
64
+ * `order` used to be here, optional, and it was the only way to move a category — a number field on
65
+ * a settings form, with a hint explaining that lower comes first and that ties fall back to names.
66
+ * The sequence is written by `categories.reorder` now, so an `order` on create or update would be a
67
+ * second way to set the same thing, disagreeing with the first the moment anybody used it.
68
+ */
69
+ export declare const CategoryInput: z.ZodObject<{
70
+ name: z.ZodString;
71
+ }, z.core.$strip>;
72
+ export type CategoryInput = z.infer<typeof CategoryInput>;
73
+ /**
74
+ * How many categories one workspace may have live at once — and the reason it is a *stated* limit.
75
+ *
76
+ * `categories.reorder` has to name every live category exactly once, so its input array needs a
77
+ * bound; every zod array that a client fills does, or a single request can ask the server to hold an
78
+ * arbitrary list in memory. A bound on that array alone is a **silent ceiling**: a workspace with
79
+ * more live categories than the number could still create, rename and archive them, and only
80
+ * reordering would fail — the one procedure with no other way to do the job.
81
+ *
82
+ * So the same number is enforced where somebody meets it. `categories.create` and a restore both
83
+ * refuse with `inventory.category.limit_reached` once a workspace holds this many live categories,
84
+ * which is a sentence naming the number at the moment it matters. Archiving one frees a place, which
85
+ * is why the limit counts the **live** rows rather than every row ever made: the advice the refusal
86
+ * gives has to be true.
87
+ */
88
+ export declare const MAX_LIVE_CATEGORIES = 500;
89
+ /**
90
+ * One stretch of time during which one person held one asset.
91
+ *
92
+ * Effective-dated, exactly as HR keeps employments: nothing is ever updated in place, a change
93
+ * closes the open row and inserts a new one. `effectiveTo === null` means "still holding it", and
94
+ * `inventory_custody_no_overlap` — a GiST exclusion constraint on
95
+ * `(asset_id =, tstzrange(effective_from, effective_to, '[)') &&)` — makes two of those for one
96
+ * asset impossible in the database rather than merely unlikely in the service.
97
+ */
98
+ export declare const CustodyPeriod: z.ZodObject<{
99
+ id: z.ZodUUID;
100
+ workspaceId: z.core.$ZodBranded<z.ZodUUID, "WorkspaceId", "out">;
101
+ assetId: z.ZodUUID;
102
+ userId: z.ZodUUID;
103
+ note: z.ZodNullable<z.ZodString>;
104
+ effectiveFrom: z.ZodString;
105
+ effectiveTo: z.ZodNullable<z.ZodString>;
106
+ createdBy: z.ZodNullable<z.ZodUUID>;
107
+ createdAt: z.ZodString;
108
+ }, z.core.$strip>;
109
+ export type CustodyPeriod = z.infer<typeof CustodyPeriod>;
110
+ /**
111
+ * One entry in an asset's timeline.
112
+ *
113
+ * `action` is a **plain string, deliberately not an enum**. The rows are append-only and outlive
114
+ * the image that wrote them: an instance rolled back to a previous release would fail to parse its
115
+ * own history the moment a newer image had written an action the older enum does not list — a
116
+ * timeline that 500s rather than one that says a little less. The client renders a sentence per
117
+ * action it knows and a neutral one for anything else. What is written today is `created`,
118
+ * `updated`, `assigned`, `transferred`, `returned`, `retired`, `restored`, `repair_logged`,
119
+ * `repair_completed`, `attachment_added` and `attachment_removed`.
120
+ */
121
+ export declare const AssetHistoryEntry: z.ZodObject<{
122
+ id: z.ZodUUID;
123
+ assetId: z.ZodUUID;
124
+ actorId: z.ZodNullable<z.ZodUUID>;
125
+ action: z.ZodString;
126
+ changes: z.ZodArray<z.ZodObject<{
127
+ field: z.ZodString;
128
+ from: z.ZodUnknown;
129
+ to: z.ZodUnknown;
130
+ }, z.core.$strip>>;
131
+ data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
132
+ occurredAt: z.ZodString;
133
+ }, z.core.$strip>;
134
+ export type AssetHistoryEntry = z.infer<typeof AssetHistoryEntry>;
36
135
  export declare const Asset: z.ZodObject<{
37
136
  id: z.ZodUUID;
38
137
  workspaceId: z.core.$ZodBranded<z.ZodUUID, "WorkspaceId", "out">;
@@ -64,6 +163,252 @@ export declare const Asset: z.ZodObject<{
64
163
  archivedAt: z.ZodNullable<z.ZodString>;
65
164
  }, z.core.$strip>;
66
165
  export type Asset = z.infer<typeof Asset>;
166
+ /**
167
+ * What a custody procedure answers with: the asset as it now stands, and the period this call
168
+ * opened.
169
+ *
170
+ * Both, because a screen needs both and fetching the asset again afterwards is a second round trip
171
+ * that can read a row somebody else has changed in between — the panel would then show a handover
172
+ * that has already been undone. `period` is null on a return: something closed, nothing opened.
173
+ */
174
+ export declare const CustodyResult: z.ZodObject<{
175
+ asset: z.ZodObject<{
176
+ id: z.ZodUUID;
177
+ workspaceId: z.core.$ZodBranded<z.ZodUUID, "WorkspaceId", "out">;
178
+ code: z.ZodString;
179
+ name: z.ZodString;
180
+ description: z.ZodString;
181
+ categoryId: z.ZodNullable<z.ZodUUID>;
182
+ status: z.ZodEnum<{
183
+ in_stock: "in_stock";
184
+ assigned: "assigned";
185
+ reserved: "reserved";
186
+ under_repair: "under_repair";
187
+ lost: "lost";
188
+ retired: "retired";
189
+ }>;
190
+ custodianUserId: z.ZodNullable<z.ZodUUID>;
191
+ custodySince: z.ZodNullable<z.ZodString>;
192
+ serialNumber: z.ZodNullable<z.ZodString>;
193
+ location: z.ZodNullable<z.ZodString>;
194
+ purchasedOn: z.ZodNullable<z.ZodString>;
195
+ purchasedFrom: z.ZodNullable<z.ZodString>;
196
+ priceMinor: z.ZodNullable<z.ZodNumber>;
197
+ currency: z.ZodNullable<z.ZodString>;
198
+ warrantyUntil: z.ZodNullable<z.ZodString>;
199
+ photoFileId: z.ZodNullable<z.ZodUUID>;
200
+ custom: z.ZodRecord<z.ZodString, z.ZodUnknown>;
201
+ createdAt: z.ZodString;
202
+ updatedAt: z.ZodString;
203
+ archivedAt: z.ZodNullable<z.ZodString>;
204
+ }, z.core.$strip>;
205
+ period: z.ZodNullable<z.ZodObject<{
206
+ id: z.ZodUUID;
207
+ workspaceId: z.core.$ZodBranded<z.ZodUUID, "WorkspaceId", "out">;
208
+ assetId: z.ZodUUID;
209
+ userId: z.ZodUUID;
210
+ note: z.ZodNullable<z.ZodString>;
211
+ effectiveFrom: z.ZodString;
212
+ effectiveTo: z.ZodNullable<z.ZodString>;
213
+ createdBy: z.ZodNullable<z.ZodUUID>;
214
+ createdAt: z.ZodString;
215
+ }, z.core.$strip>>;
216
+ }, z.core.$strip>;
217
+ export type CustodyResult = z.infer<typeof CustodyResult>;
218
+ /**
219
+ * One trip an item made to a repairer.
220
+ *
221
+ * `returnedOn === null` means it is still away, and that single fact is what puts the asset in
222
+ * `under_repair` — see `deriveStatus` in `src/server/services/status.ts`, which is the only place
223
+ * the three columns that drive a status are read together.
224
+ *
225
+ * **A repair is not custody, and neither one cancels the other.** A laptop assigned to Dan that goes
226
+ * to the repairer is still Dan's responsibility: the custody period stays open, `custodianUserId`
227
+ * stays set, and only `status` moves. That is why a repair does not touch custody and custody does
228
+ * not refuse a repaired item — the two answer different questions ("who is answerable for it" and
229
+ * "where is it"), and collapsing them would mean an item could not come back to the person who sent
230
+ * it.
231
+ */
232
+ export declare const Repair: z.ZodObject<{
233
+ id: z.ZodUUID;
234
+ workspaceId: z.core.$ZodBranded<z.ZodUUID, "WorkspaceId", "out">;
235
+ assetId: z.ZodUUID;
236
+ summary: z.ZodString;
237
+ detail: z.ZodNullable<z.ZodString>;
238
+ vendor: z.ZodNullable<z.ZodString>;
239
+ costMinor: z.ZodNullable<z.ZodNumber>;
240
+ currency: z.ZodNullable<z.ZodString>;
241
+ sentOn: z.ZodString;
242
+ returnedOn: z.ZodNullable<z.ZodString>;
243
+ createdBy: z.ZodNullable<z.ZodUUID>;
244
+ createdAt: z.ZodString;
245
+ updatedAt: z.ZodString;
246
+ }, z.core.$strip>;
247
+ export type Repair = z.infer<typeof Repair>;
248
+ /**
249
+ * A repair in a list, with the two things a reader needs to know *which item* it is about.
250
+ *
251
+ * **Joined at read time, never stored here.** `mod_inventory.repairs` holds no asset name, so
252
+ * renaming an asset renames it everywhere at once — a copied label is a label that goes stale, and
253
+ * this module already refuses to copy a person's name for the same reason. The join is inside one
254
+ * schema, which is the kind a module is allowed to make; the kind it is not is a join across the
255
+ * boundary into another module's tables.
256
+ *
257
+ * It extends `Repair` rather than replacing it, so a component that renders a repair renders one of
258
+ * these without knowing the difference. `create`, `update` and `complete` answer with a plain
259
+ * `Repair`: the caller of those already knows which asset it asked about.
260
+ */
261
+ export declare const RepairListItem: z.ZodObject<{
262
+ id: z.ZodUUID;
263
+ workspaceId: z.core.$ZodBranded<z.ZodUUID, "WorkspaceId", "out">;
264
+ assetId: z.ZodUUID;
265
+ summary: z.ZodString;
266
+ detail: z.ZodNullable<z.ZodString>;
267
+ vendor: z.ZodNullable<z.ZodString>;
268
+ costMinor: z.ZodNullable<z.ZodNumber>;
269
+ currency: z.ZodNullable<z.ZodString>;
270
+ sentOn: z.ZodString;
271
+ returnedOn: z.ZodNullable<z.ZodString>;
272
+ createdBy: z.ZodNullable<z.ZodUUID>;
273
+ createdAt: z.ZodString;
274
+ updatedAt: z.ZodString;
275
+ assetCode: z.ZodString;
276
+ assetName: z.ZodString;
277
+ }, z.core.$strip>;
278
+ export type RepairListItem = z.infer<typeof RepairListItem>;
279
+ /**
280
+ * Everything a person can say about a repair.
281
+ *
282
+ * **No field here carries `.default()`, for the reason `AssetInput` spells out**: `update` is built
283
+ * from `.partial()`, and `.partial()` does not strip a default — zod still substitutes it for a key
284
+ * the request never sent, so a patch that renames a repair would silently re-date it. `sentOn` is
285
+ * optional rather than defaulted for the same reason; `repairs.create` fills today's date on the
286
+ * server, which is the only clock this module trusts.
287
+ */
288
+ export declare const RepairInput: z.ZodObject<{
289
+ summary: z.ZodString;
290
+ detail: z.ZodOptional<z.ZodNullable<z.ZodString>>;
291
+ vendor: z.ZodOptional<z.ZodNullable<z.ZodString>>;
292
+ costMinor: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
293
+ currency: z.ZodOptional<z.ZodNullable<z.ZodString>>;
294
+ sentOn: z.ZodOptional<z.ZodISODate>;
295
+ }, z.core.$strip>;
296
+ export type RepairInput = z.infer<typeof RepairInput>;
297
+ export declare const RepairPatchInput: z.ZodObject<{
298
+ summary: z.ZodOptional<z.ZodString>;
299
+ detail: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
300
+ vendor: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
301
+ costMinor: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodNumber>>>;
302
+ currency: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
303
+ sentOn: z.ZodOptional<z.ZodOptional<z.ZodISODate>>;
304
+ }, z.core.$strip>;
305
+ export type RepairPatchInput = z.infer<typeof RepairPatchInput>;
306
+ /**
307
+ * What a repair mutation answers with: the repair, and the asset as it now stands.
308
+ *
309
+ * Both, for the reason `CustodyResult` carries both — sending an item away moves `assets.status`,
310
+ * and a screen that had to fetch the asset again afterwards would be reading a row somebody else
311
+ * may have changed in between.
312
+ */
313
+ export declare const RepairResult: z.ZodObject<{
314
+ repair: z.ZodObject<{
315
+ id: z.ZodUUID;
316
+ workspaceId: z.core.$ZodBranded<z.ZodUUID, "WorkspaceId", "out">;
317
+ assetId: z.ZodUUID;
318
+ summary: z.ZodString;
319
+ detail: z.ZodNullable<z.ZodString>;
320
+ vendor: z.ZodNullable<z.ZodString>;
321
+ costMinor: z.ZodNullable<z.ZodNumber>;
322
+ currency: z.ZodNullable<z.ZodString>;
323
+ sentOn: z.ZodString;
324
+ returnedOn: z.ZodNullable<z.ZodString>;
325
+ createdBy: z.ZodNullable<z.ZodUUID>;
326
+ createdAt: z.ZodString;
327
+ updatedAt: z.ZodString;
328
+ }, z.core.$strip>;
329
+ asset: z.ZodObject<{
330
+ id: z.ZodUUID;
331
+ workspaceId: z.core.$ZodBranded<z.ZodUUID, "WorkspaceId", "out">;
332
+ code: z.ZodString;
333
+ name: z.ZodString;
334
+ description: z.ZodString;
335
+ categoryId: z.ZodNullable<z.ZodUUID>;
336
+ status: z.ZodEnum<{
337
+ in_stock: "in_stock";
338
+ assigned: "assigned";
339
+ reserved: "reserved";
340
+ under_repair: "under_repair";
341
+ lost: "lost";
342
+ retired: "retired";
343
+ }>;
344
+ custodianUserId: z.ZodNullable<z.ZodUUID>;
345
+ custodySince: z.ZodNullable<z.ZodString>;
346
+ serialNumber: z.ZodNullable<z.ZodString>;
347
+ location: z.ZodNullable<z.ZodString>;
348
+ purchasedOn: z.ZodNullable<z.ZodString>;
349
+ purchasedFrom: z.ZodNullable<z.ZodString>;
350
+ priceMinor: z.ZodNullable<z.ZodNumber>;
351
+ currency: z.ZodNullable<z.ZodString>;
352
+ warrantyUntil: z.ZodNullable<z.ZodString>;
353
+ photoFileId: z.ZodNullable<z.ZodUUID>;
354
+ custom: z.ZodRecord<z.ZodString, z.ZodUnknown>;
355
+ createdAt: z.ZodString;
356
+ updatedAt: z.ZodString;
357
+ archivedAt: z.ZodNullable<z.ZodString>;
358
+ }, z.core.$strip>;
359
+ }, z.core.$strip>;
360
+ export type RepairResult = z.infer<typeof RepairResult>;
361
+ /**
362
+ * A file recorded against an asset — a receipt, a warranty card, a manual.
363
+ *
364
+ * **The bytes are core's, not this module's.** A module does not upload: the browser uploads through
365
+ * core's file service and hands this module the id it was given, and reading one back is a download
366
+ * URL core signs. All that lives here is the fact that this asset has that file, plus the name and
367
+ * size copied at attach time so a list can be drawn without asking core once per row.
368
+ *
369
+ * `repairId` is what separates "the invoice for the screen replacement" from "the purchase receipt":
370
+ * null means it belongs to the asset itself.
371
+ */
372
+ export declare const Attachment: z.ZodObject<{
373
+ id: z.ZodUUID;
374
+ workspaceId: z.core.$ZodBranded<z.ZodUUID, "WorkspaceId", "out">;
375
+ assetId: z.ZodUUID;
376
+ repairId: z.ZodNullable<z.ZodUUID>;
377
+ fileId: z.ZodUUID;
378
+ name: z.ZodString;
379
+ mimeType: z.ZodNullable<z.ZodString>;
380
+ size: z.ZodNullable<z.ZodNumber>;
381
+ uploadedBy: z.ZodNullable<z.ZodUUID>;
382
+ createdAt: z.ZodString;
383
+ }, z.core.$strip>;
384
+ export type Attachment = z.infer<typeof Attachment>;
385
+ /**
386
+ * The register in numbers: what a page's count line and a dashboard card need in one request.
387
+ *
388
+ * `total` counts what the list shows by default — live rows — and `archived` is beside it rather
389
+ * than inside it, because a count line that silently included archived rows would disagree with the
390
+ * list under it.
391
+ *
392
+ * **`outForRepair` is null when the workspace does not track repairs.** Zero would be a claim
393
+ * ("nothing is away"), and a workspace with the `repairs` capability off has not made that claim —
394
+ * it has no opinion at all. The screens show the tile only when a number arrives, which is the same
395
+ * rule as hiding the Repairs tab, expressed in the data instead of in a second capability lookup.
396
+ */
397
+ export declare const InventoryStats: z.ZodObject<{
398
+ total: z.ZodNumber;
399
+ archived: z.ZodNumber;
400
+ byStatus: z.ZodRecord<z.ZodEnum<{
401
+ in_stock: "in_stock";
402
+ assigned: "assigned";
403
+ reserved: "reserved";
404
+ under_repair: "under_repair";
405
+ lost: "lost";
406
+ retired: "retired";
407
+ }>, z.ZodNumber>;
408
+ outForRepair: z.ZodNullable<z.ZodNumber>;
409
+ unassigned: z.ZodNumber;
410
+ }, z.core.$strip>;
411
+ export type InventoryStats = z.infer<typeof InventoryStats>;
67
412
  /**
68
413
  * How a list is ordered, and therefore what a page cursor is a bookmark *into*.
69
414
  *
@@ -1 +1 @@
1
- {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/contract/models.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;GAKG;AAEH,wGAAwG;AACxG,eAAO,MAAM,SAAS,cAAc,CAAA;AAEpC;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW;;;;;;;EAAkF,CAAA;AAC1G,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAA;AAErD;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,wCAAoC,CAAA;AAC7D,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAEvD,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4BhB,CAAA;AACF,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,CAAA;AAEzC;;;;;;GAMG;AACH,eAAO,MAAM,SAAS;;;;EAAqC,CAAA;AAC3D,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAA;AAEjD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;iBAerB,CAAA;AACF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAA;AAEnD;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;iBAE3B,CAAA;AACF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAE/D,6FAA6F;AAC7F,eAAO,MAAM,eAAe;;;;;;;;;;;;iBAAuB,CAAA;AACnD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAA;AAE7D,wEAAwE;AACxE,eAAO,MAAM,EAAE;;iBAAyC,CAAA"}
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/contract/models.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,12 @@ export const MODULE_ID = 'inventory';
15
15
  *
16
16
  * Stored rather than derived, because every list filter asks for it — and kept in step inside the
17
17
  * same transaction that writes the row it derives from, never by a job afterwards.
18
+ *
19
+ * **`under_repair` belongs to the `repairs` capability**, so a workspace with that switch off never
20
+ * has an asset in it: the procedure that ends a repair answers 404 there, and a status nothing can
21
+ * move an item out of is a register the workspace cannot correct. The one thing a job does here is
22
+ * bring the rows *nobody touches* back into step after that switch moves, in both directions —
23
+ * `deriveStatus` in `src/server/services/status.ts` argues it, and nothing is destroyed either way.
18
24
  */
19
25
  export const AssetStatus = z.enum(['in_stock', 'assigned', 'reserved', 'under_repair', 'lost', 'retired']);
20
26
  /**
@@ -25,6 +31,110 @@ export const AssetStatus = z.enum(['in_stock', 'assigned', 'reserved', 'under_re
25
31
  * it against `field_defs` before writing.
26
32
  */
27
33
  export const CustomValues = z.record(z.string(), z.unknown());
34
+ /**
35
+ * A workspace's own grouping of what it owns — Laptops, Furniture, Cameras.
36
+ *
37
+ * Archived rather than deleted, and `archivedAt` is the whole reason: `assets.category_id` is a
38
+ * plain uuid with no foreign key, so a deleted category leaves every asset filed under it pointing
39
+ * at a row that is not there. The list column goes blank and the timeline entry that recorded the
40
+ * move loses the name it recorded. Archiving takes it out of every picker and every filter and
41
+ * leaves each asset able to say what it is.
42
+ */
43
+ export const Category = z.object({
44
+ id: z.uuid(),
45
+ workspaceId: WorkspaceId,
46
+ name: z.string().min(1).max(120),
47
+ /**
48
+ * Where it sits in the sequence. **Storage, not a setting.**
49
+ *
50
+ * Nobody thinks about their categories as integers, so no screen shows this number and no input
51
+ * accepts one: `categories.reorder` takes the ids in the order somebody dragged them into and
52
+ * renumbers the live ones `0…n-1` in one transaction. `create` and a restore append, so two live
53
+ * categories never share a value — which is the state a "position" field invited on every save.
54
+ *
55
+ * The name is still the tiebreak in `list`, because a workspace seeded before this existed, or a
56
+ * row written by hand, can still hold a duplicate; it just stops being the ordinary case.
57
+ */
58
+ order: z.number().int(),
59
+ createdAt: z.string(),
60
+ updatedAt: z.string(),
61
+ archivedAt: z.string().nullable(),
62
+ });
63
+ /**
64
+ * What a person types when they add or rename a category: a name, and nothing else.
65
+ *
66
+ * `order` used to be here, optional, and it was the only way to move a category — a number field on
67
+ * a settings form, with a hint explaining that lower comes first and that ties fall back to names.
68
+ * The sequence is written by `categories.reorder` now, so an `order` on create or update would be a
69
+ * second way to set the same thing, disagreeing with the first the moment anybody used it.
70
+ */
71
+ export const CategoryInput = z.object({
72
+ name: z.string().trim().min(1).max(120),
73
+ });
74
+ /**
75
+ * How many categories one workspace may have live at once — and the reason it is a *stated* limit.
76
+ *
77
+ * `categories.reorder` has to name every live category exactly once, so its input array needs a
78
+ * bound; every zod array that a client fills does, or a single request can ask the server to hold an
79
+ * arbitrary list in memory. A bound on that array alone is a **silent ceiling**: a workspace with
80
+ * more live categories than the number could still create, rename and archive them, and only
81
+ * reordering would fail — the one procedure with no other way to do the job.
82
+ *
83
+ * So the same number is enforced where somebody meets it. `categories.create` and a restore both
84
+ * refuse with `inventory.category.limit_reached` once a workspace holds this many live categories,
85
+ * which is a sentence naming the number at the moment it matters. Archiving one frees a place, which
86
+ * is why the limit counts the **live** rows rather than every row ever made: the advice the refusal
87
+ * gives has to be true.
88
+ */
89
+ export const MAX_LIVE_CATEGORIES = 500;
90
+ /**
91
+ * One stretch of time during which one person held one asset.
92
+ *
93
+ * Effective-dated, exactly as HR keeps employments: nothing is ever updated in place, a change
94
+ * closes the open row and inserts a new one. `effectiveTo === null` means "still holding it", and
95
+ * `inventory_custody_no_overlap` — a GiST exclusion constraint on
96
+ * `(asset_id =, tstzrange(effective_from, effective_to, '[)') &&)` — makes two of those for one
97
+ * asset impossible in the database rather than merely unlikely in the service.
98
+ */
99
+ export const CustodyPeriod = z.object({
100
+ id: z.uuid(),
101
+ workspaceId: WorkspaceId,
102
+ assetId: z.uuid(),
103
+ /**
104
+ * The member who held it. A plain uuid — a cross-schema foreign key is what the module boundary
105
+ * exists to prevent — resolved against core membership at read time, which is also why a person
106
+ * who has since left the workspace still has readable history.
107
+ */
108
+ userId: z.uuid(),
109
+ note: z.string().max(500).nullable(),
110
+ effectiveFrom: z.string(),
111
+ effectiveTo: z.string().nullable(),
112
+ /** Who did the handing over, which is not always who received it. */
113
+ createdBy: z.uuid().nullable(),
114
+ createdAt: z.string(),
115
+ });
116
+ /**
117
+ * One entry in an asset's timeline.
118
+ *
119
+ * `action` is a **plain string, deliberately not an enum**. The rows are append-only and outlive
120
+ * the image that wrote them: an instance rolled back to a previous release would fail to parse its
121
+ * own history the moment a newer image had written an action the older enum does not list — a
122
+ * timeline that 500s rather than one that says a little less. The client renders a sentence per
123
+ * action it knows and a neutral one for anything else. What is written today is `created`,
124
+ * `updated`, `assigned`, `transferred`, `returned`, `retired`, `restored`, `repair_logged`,
125
+ * `repair_completed`, `attachment_added` and `attachment_removed`.
126
+ */
127
+ export const AssetHistoryEntry = z.object({
128
+ id: z.uuid(),
129
+ assetId: z.uuid(),
130
+ /** Null for anything the platform did rather than a person. */
131
+ actorId: z.uuid().nullable(),
132
+ action: z.string().max(40),
133
+ changes: z.array(z.object({ field: z.string(), from: z.unknown(), to: z.unknown() })),
134
+ /** Action-specific ids — who received an item, who handed it over. Never a row. */
135
+ data: z.record(z.string(), z.unknown()),
136
+ occurredAt: z.string(),
137
+ });
28
138
  export const Asset = z.object({
29
139
  id: z.uuid(),
30
140
  workspaceId: WorkspaceId,
@@ -54,6 +164,141 @@ export const Asset = z.object({
54
164
  updatedAt: z.string(),
55
165
  archivedAt: z.string().nullable(),
56
166
  });
167
+ /**
168
+ * What a custody procedure answers with: the asset as it now stands, and the period this call
169
+ * opened.
170
+ *
171
+ * Both, because a screen needs both and fetching the asset again afterwards is a second round trip
172
+ * that can read a row somebody else has changed in between — the panel would then show a handover
173
+ * that has already been undone. `period` is null on a return: something closed, nothing opened.
174
+ */
175
+ export const CustodyResult = z.object({
176
+ asset: Asset,
177
+ period: CustodyPeriod.nullable(),
178
+ });
179
+ /**
180
+ * One trip an item made to a repairer.
181
+ *
182
+ * `returnedOn === null` means it is still away, and that single fact is what puts the asset in
183
+ * `under_repair` — see `deriveStatus` in `src/server/services/status.ts`, which is the only place
184
+ * the three columns that drive a status are read together.
185
+ *
186
+ * **A repair is not custody, and neither one cancels the other.** A laptop assigned to Dan that goes
187
+ * to the repairer is still Dan's responsibility: the custody period stays open, `custodianUserId`
188
+ * stays set, and only `status` moves. That is why a repair does not touch custody and custody does
189
+ * not refuse a repaired item — the two answer different questions ("who is answerable for it" and
190
+ * "where is it"), and collapsing them would mean an item could not come back to the person who sent
191
+ * it.
192
+ */
193
+ export const Repair = z.object({
194
+ id: z.uuid(),
195
+ workspaceId: WorkspaceId,
196
+ assetId: z.uuid(),
197
+ summary: z.string().min(1).max(200),
198
+ detail: z.string().max(4000).nullable(),
199
+ vendor: z.string().max(200).nullable(),
200
+ /** Minor units, like `Asset.priceMinor` — one convention for money across the module. */
201
+ costMinor: z.number().int().nullable(),
202
+ currency: z.string().length(3).nullable(),
203
+ sentOn: z.string(),
204
+ /** Null while it is still away. Set by `repairs.complete` and by nothing else. */
205
+ returnedOn: z.string().nullable(),
206
+ createdBy: z.uuid().nullable(),
207
+ createdAt: z.string(),
208
+ updatedAt: z.string(),
209
+ });
210
+ /**
211
+ * A repair in a list, with the two things a reader needs to know *which item* it is about.
212
+ *
213
+ * **Joined at read time, never stored here.** `mod_inventory.repairs` holds no asset name, so
214
+ * renaming an asset renames it everywhere at once — a copied label is a label that goes stale, and
215
+ * this module already refuses to copy a person's name for the same reason. The join is inside one
216
+ * schema, which is the kind a module is allowed to make; the kind it is not is a join across the
217
+ * boundary into another module's tables.
218
+ *
219
+ * It extends `Repair` rather than replacing it, so a component that renders a repair renders one of
220
+ * these without knowing the difference. `create`, `update` and `complete` answer with a plain
221
+ * `Repair`: the caller of those already knows which asset it asked about.
222
+ */
223
+ export const RepairListItem = Repair.extend({
224
+ assetCode: z.string().min(1).max(40),
225
+ assetName: z.string().min(1).max(200),
226
+ });
227
+ /**
228
+ * Everything a person can say about a repair.
229
+ *
230
+ * **No field here carries `.default()`, for the reason `AssetInput` spells out**: `update` is built
231
+ * from `.partial()`, and `.partial()` does not strip a default — zod still substitutes it for a key
232
+ * the request never sent, so a patch that renames a repair would silently re-date it. `sentOn` is
233
+ * optional rather than defaulted for the same reason; `repairs.create` fills today's date on the
234
+ * server, which is the only clock this module trusts.
235
+ */
236
+ export const RepairInput = z.object({
237
+ summary: z.string().trim().min(1).max(200),
238
+ detail: z.string().max(4000).nullish(),
239
+ vendor: z.string().max(200).nullish(),
240
+ costMinor: z.number().int().min(0).nullish(),
241
+ currency: z.string().length(3).nullish(),
242
+ /** `sent_on` is `not null` in the database, so this is optional but never nullable. */
243
+ sentOn: z.iso.date().optional(),
244
+ });
245
+ export const RepairPatchInput = RepairInput.partial();
246
+ /**
247
+ * What a repair mutation answers with: the repair, and the asset as it now stands.
248
+ *
249
+ * Both, for the reason `CustodyResult` carries both — sending an item away moves `assets.status`,
250
+ * and a screen that had to fetch the asset again afterwards would be reading a row somebody else
251
+ * may have changed in between.
252
+ */
253
+ export const RepairResult = z.object({
254
+ repair: Repair,
255
+ asset: Asset,
256
+ });
257
+ /**
258
+ * A file recorded against an asset — a receipt, a warranty card, a manual.
259
+ *
260
+ * **The bytes are core's, not this module's.** A module does not upload: the browser uploads through
261
+ * core's file service and hands this module the id it was given, and reading one back is a download
262
+ * URL core signs. All that lives here is the fact that this asset has that file, plus the name and
263
+ * size copied at attach time so a list can be drawn without asking core once per row.
264
+ *
265
+ * `repairId` is what separates "the invoice for the screen replacement" from "the purchase receipt":
266
+ * null means it belongs to the asset itself.
267
+ */
268
+ export const Attachment = z.object({
269
+ id: z.uuid(),
270
+ workspaceId: WorkspaceId,
271
+ assetId: z.uuid(),
272
+ repairId: z.uuid().nullable(),
273
+ fileId: z.uuid(),
274
+ name: z.string().max(300),
275
+ mimeType: z.string().max(200).nullable(),
276
+ /** Bytes, as core reported them when the file was attached. */
277
+ size: z.number().int().nullable(),
278
+ uploadedBy: z.uuid().nullable(),
279
+ createdAt: z.string(),
280
+ });
281
+ /**
282
+ * The register in numbers: what a page's count line and a dashboard card need in one request.
283
+ *
284
+ * `total` counts what the list shows by default — live rows — and `archived` is beside it rather
285
+ * than inside it, because a count line that silently included archived rows would disagree with the
286
+ * list under it.
287
+ *
288
+ * **`outForRepair` is null when the workspace does not track repairs.** Zero would be a claim
289
+ * ("nothing is away"), and a workspace with the `repairs` capability off has not made that claim —
290
+ * it has no opinion at all. The screens show the tile only when a number arrives, which is the same
291
+ * rule as hiding the Repairs tab, expressed in the data instead of in a second capability lookup.
292
+ */
293
+ export const InventoryStats = z.object({
294
+ total: z.number().int().nonnegative(),
295
+ archived: z.number().int().nonnegative(),
296
+ /** Every status, zero-filled, so a screen can render the set without knowing which exist. */
297
+ byStatus: z.record(AssetStatus, z.number().int().nonnegative()),
298
+ outForRepair: z.number().int().nonnegative().nullable(),
299
+ /** Live assets nobody is holding — what is actually available to hand out. */
300
+ unassigned: z.number().int().nonnegative(),
301
+ });
57
302
  /**
58
303
  * How a list is ordered, and therefore what a page cursor is a bookmark *into*.
59
304
  *
@@ -1 +1 @@
1
- {"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/contract/models.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/contract/models.ts"],"names":[],"mappings":"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"}