@happyvertical/smrt-timesheets 0.55.24 → 0.56.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.
Files changed (69) hide show
  1. package/AGENTS.md +60 -0
  2. package/README.md +190 -12
  3. package/agents/period-rollup.md +20 -0
  4. package/dist/attendance/context.d.ts +80 -0
  5. package/dist/attendance/context.d.ts.map +1 -0
  6. package/dist/attendance/correction-models.d.ts +39 -0
  7. package/dist/attendance/correction-models.d.ts.map +1 -0
  8. package/dist/attendance/correction-service.d.ts +118 -0
  9. package/dist/attendance/correction-service.d.ts.map +1 -0
  10. package/dist/attendance/models.d.ts +57 -0
  11. package/dist/attendance/models.d.ts.map +1 -1
  12. package/dist/attendance/segments.d.ts +20 -0
  13. package/dist/attendance/segments.d.ts.map +1 -0
  14. package/dist/attendance/service.d.ts +106 -22
  15. package/dist/attendance/service.d.ts.map +1 -1
  16. package/dist/attendance/write.d.ts +12 -0
  17. package/dist/attendance/write.d.ts.map +1 -0
  18. package/dist/attendance.d.ts +2 -0
  19. package/dist/attendance.d.ts.map +1 -1
  20. package/dist/attendance.js +3 -323
  21. package/dist/chunks/{attendance-Cpo4mIID.js → attendance-Cw75uJnT.js} +3 -3
  22. package/dist/chunks/{attendance-Cpo4mIID.js.map → attendance-Cw75uJnT.js.map} +1 -1
  23. package/dist/chunks/attendance-DJNytMTN.js +1246 -0
  24. package/dist/chunks/attendance-DJNytMTN.js.map +1 -0
  25. package/dist/chunks/models-tUePZ5x7.js +372 -0
  26. package/dist/chunks/models-tUePZ5x7.js.map +1 -0
  27. package/dist/chunks/{rollup-Du6uaqyM.js → rollup-CzCb-DxI.js} +211 -6
  28. package/dist/chunks/rollup-CzCb-DxI.js.map +1 -0
  29. package/dist/chunks/service-time-entry-BJVSGx33.js +286 -0
  30. package/dist/chunks/service-time-entry-BJVSGx33.js.map +1 -0
  31. package/dist/chunks/time-entry-actions-ChT1lcOp.js +576 -0
  32. package/dist/chunks/time-entry-actions-ChT1lcOp.js.map +1 -0
  33. package/dist/index.d.ts +1 -0
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +113 -334
  36. package/dist/index.js.map +1 -1
  37. package/dist/manifest.json +2020 -168
  38. package/dist/models/service-snapshots.d.ts.map +1 -1
  39. package/dist/models/service-time-entry.d.ts +36 -1
  40. package/dist/models/service-time-entry.d.ts.map +1 -1
  41. package/dist/recipes.d.ts +124 -0
  42. package/dist/recipes.d.ts.map +1 -0
  43. package/dist/rollup/correction-guard.d.ts +12 -0
  44. package/dist/rollup/correction-guard.d.ts.map +1 -0
  45. package/dist/rollup/models.d.ts +31 -1
  46. package/dist/rollup/models.d.ts.map +1 -1
  47. package/dist/rollup/service.d.ts +25 -7
  48. package/dist/rollup/service.d.ts.map +1 -1
  49. package/dist/rollup/types.d.ts +18 -0
  50. package/dist/rollup/types.d.ts.map +1 -1
  51. package/dist/rollup/write.d.ts +2 -0
  52. package/dist/rollup/write.d.ts.map +1 -1
  53. package/dist/rollup.d.ts +3 -2
  54. package/dist/rollup.d.ts.map +1 -1
  55. package/dist/rollup.js +2 -2
  56. package/dist/services/action-principal.d.ts +54 -0
  57. package/dist/services/action-principal.d.ts.map +1 -0
  58. package/dist/services/index.d.ts +2 -0
  59. package/dist/services/index.d.ts.map +1 -1
  60. package/dist/services/time-entry-actions.d.ts +83 -0
  61. package/dist/services/time-entry-actions.d.ts.map +1 -0
  62. package/dist/smrt-knowledge.json +902 -40
  63. package/package.json +8 -7
  64. package/dist/attendance.js.map +0 -1
  65. package/dist/chunks/models-_ZbpXWnb.js +0 -176
  66. package/dist/chunks/models-_ZbpXWnb.js.map +0 -1
  67. package/dist/chunks/rollup-Du6uaqyM.js.map +0 -1
  68. package/dist/chunks/service-time-entry-BGj39_EC.js +0 -227
  69. package/dist/chunks/service-time-entry-BGj39_EC.js.map +0 -1
@@ -2,8 +2,513 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-timesheets",
5
- "packageVersion": "0.55.24",
5
+ "packageVersion": "0.56.1",
6
6
  "objects": {
7
+ "@happyvertical/smrt-timesheets:AttendanceCorrection": {
8
+ "name": "attendancecorrection",
9
+ "className": "AttendanceCorrection",
10
+ "qualifiedName": "@happyvertical/smrt-timesheets:AttendanceCorrection",
11
+ "collection": "attendancecorrections",
12
+ "description": "One append-only change to closed attendance: who changed whose time, why, and the before/after values as JSON (null for an addition's before or a removal's after).",
13
+ "filePath": "/home/runner/work/smrt/smrt/packages/timesheets/src/attendance/correction-models.ts",
14
+ "packageName": "@happyvertical/smrt-timesheets",
15
+ "fields": {
16
+ "tenantId": {
17
+ "type": "text",
18
+ "required": true,
19
+ "_meta": {
20
+ "sqlType": "UUID",
21
+ "__tenancy": {
22
+ "isTenantIdField": true,
23
+ "autoFilter": true,
24
+ "required": true,
25
+ "autoPopulate": true,
26
+ "nullable": false,
27
+ "mode": "required",
28
+ "field": "tenantId",
29
+ "allowSuperAdminBypass": false
30
+ }
31
+ }
32
+ },
33
+ "subjectProfileId": {
34
+ "type": "crossPackageRef",
35
+ "required": false,
36
+ "related": "@happyvertical/smrt-profiles:Profile"
37
+ },
38
+ "actorProfileId": {
39
+ "type": "crossPackageRef",
40
+ "required": false,
41
+ "related": "@happyvertical/smrt-profiles:Profile"
42
+ },
43
+ "kind": {
44
+ "type": "text",
45
+ "required": false,
46
+ "_meta": {}
47
+ },
48
+ "punchId": {
49
+ "type": "foreignKey",
50
+ "required": false,
51
+ "related": "AttendancePunch"
52
+ },
53
+ "targetId": {
54
+ "type": "text",
55
+ "required": false
56
+ },
57
+ "beforeState": {
58
+ "type": "text",
59
+ "required": false,
60
+ "_meta": {}
61
+ },
62
+ "afterState": {
63
+ "type": "text",
64
+ "required": false,
65
+ "_meta": {}
66
+ },
67
+ "reason": {
68
+ "type": "text",
69
+ "required": false,
70
+ "_meta": {}
71
+ },
72
+ "acknowledgementRequired": {
73
+ "type": "boolean",
74
+ "required": true,
75
+ "default": false
76
+ },
77
+ "acknowledgedAt": {
78
+ "type": "datetime",
79
+ "required": false
80
+ },
81
+ "acknowledgedByProfileId": {
82
+ "type": "crossPackageRef",
83
+ "required": false,
84
+ "related": "@happyvertical/smrt-profiles:Profile",
85
+ "_meta": {
86
+ "nullable": true
87
+ }
88
+ }
89
+ },
90
+ "methods": {
91
+ "getBefore": {
92
+ "name": "getBefore",
93
+ "async": false,
94
+ "parameters": [],
95
+ "returnType": "T | null",
96
+ "isStatic": false,
97
+ "isPublic": true
98
+ },
99
+ "getAfter": {
100
+ "name": "getAfter",
101
+ "async": false,
102
+ "parameters": [],
103
+ "returnType": "T | null",
104
+ "isStatic": false,
105
+ "isPublic": true
106
+ },
107
+ "save": {
108
+ "name": "save",
109
+ "async": true,
110
+ "parameters": [],
111
+ "returnType": "Promise<this>",
112
+ "isStatic": false,
113
+ "isPublic": true
114
+ },
115
+ "delete": {
116
+ "name": "delete",
117
+ "async": true,
118
+ "parameters": [],
119
+ "returnType": "Promise<void>",
120
+ "isStatic": false,
121
+ "isPublic": true
122
+ }
123
+ },
124
+ "decoratorConfig": {
125
+ "tableName": "attendance_corrections",
126
+ "sensitive": true,
127
+ "indexes": [
128
+ {
129
+ "name": "attendance_corrections_punch_idx",
130
+ "columns": [
131
+ "tenantId",
132
+ "punchId"
133
+ ]
134
+ },
135
+ {
136
+ "name": "attendance_corrections_subject_idx",
137
+ "columns": [
138
+ "tenantId",
139
+ "subjectProfileId"
140
+ ]
141
+ }
142
+ ],
143
+ "api": {
144
+ "include": []
145
+ },
146
+ "cli": {
147
+ "include": []
148
+ },
149
+ "mcp": {
150
+ "include": []
151
+ },
152
+ "tenantScoped": {
153
+ "mode": "required"
154
+ },
155
+ "conflictColumns": [
156
+ "tenant_id",
157
+ "slug",
158
+ "context"
159
+ ]
160
+ },
161
+ "extends": "SmrtObject",
162
+ "exportName": "AttendanceCorrection",
163
+ "collectionExportName": "AttendanceCorrectionCollection",
164
+ "validationRules": [
165
+ {
166
+ "field": "acknowledgementRequired",
167
+ "rule": "required",
168
+ "fieldType": "boolean"
169
+ }
170
+ ],
171
+ "schema": {
172
+ "tableName": "attendance_corrections",
173
+ "ddl": "CREATE TABLE IF NOT EXISTS \"attendance_corrections\" (\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 NOT NULL,\n \"subject_profile_id\" UUID,\n \"actor_profile_id\" UUID,\n \"kind\" TEXT,\n \"punch_id\" UUID,\n \"target_id\" TEXT,\n \"before_state\" TEXT,\n \"after_state\" TEXT,\n \"reason\" TEXT,\n \"acknowledgement_required\" BOOLEAN NOT NULL DEFAULT FALSE,\n \"acknowledged_at\" TIMESTAMP,\n \"acknowledged_by_profile_id\" UUID\n);",
174
+ "columns": {
175
+ "id": {
176
+ "type": "UUID",
177
+ "primaryKey": true,
178
+ "referenceKind": "id",
179
+ "notNull": true
180
+ },
181
+ "slug": {
182
+ "type": "TEXT",
183
+ "notNull": true
184
+ },
185
+ "context": {
186
+ "type": "TEXT",
187
+ "notNull": true,
188
+ "default": ""
189
+ },
190
+ "created_at": {
191
+ "type": "TIMESTAMP",
192
+ "notNull": true,
193
+ "default": "current_timestamp"
194
+ },
195
+ "updated_at": {
196
+ "type": "TIMESTAMP",
197
+ "notNull": true,
198
+ "default": "current_timestamp"
199
+ },
200
+ "tenant_id": {
201
+ "type": "UUID",
202
+ "referenceKind": "tenantId",
203
+ "notNull": true,
204
+ "unique": false
205
+ },
206
+ "subject_profile_id": {
207
+ "type": "UUID",
208
+ "referenceKind": "crossPackageRef",
209
+ "notNull": false,
210
+ "unique": false
211
+ },
212
+ "actor_profile_id": {
213
+ "type": "UUID",
214
+ "referenceKind": "crossPackageRef",
215
+ "notNull": false,
216
+ "unique": false
217
+ },
218
+ "kind": {
219
+ "type": "TEXT",
220
+ "notNull": false,
221
+ "unique": false
222
+ },
223
+ "punch_id": {
224
+ "type": "UUID",
225
+ "referenceKind": "foreignKey",
226
+ "notNull": false,
227
+ "unique": false,
228
+ "foreignKey": {
229
+ "table": "attendance_punches",
230
+ "column": "id",
231
+ "onDelete": "NO ACTION",
232
+ "onUpdate": "CASCADE"
233
+ }
234
+ },
235
+ "target_id": {
236
+ "type": "TEXT",
237
+ "notNull": false,
238
+ "unique": false
239
+ },
240
+ "before_state": {
241
+ "type": "TEXT",
242
+ "notNull": false,
243
+ "unique": false
244
+ },
245
+ "after_state": {
246
+ "type": "TEXT",
247
+ "notNull": false,
248
+ "unique": false
249
+ },
250
+ "reason": {
251
+ "type": "TEXT",
252
+ "notNull": false,
253
+ "unique": false
254
+ },
255
+ "acknowledgement_required": {
256
+ "type": "BOOLEAN",
257
+ "notNull": true,
258
+ "unique": false,
259
+ "default": false
260
+ },
261
+ "acknowledged_at": {
262
+ "type": "TIMESTAMP",
263
+ "notNull": false,
264
+ "unique": false
265
+ },
266
+ "acknowledged_by_profile_id": {
267
+ "type": "UUID",
268
+ "referenceKind": "crossPackageRef",
269
+ "notNull": false,
270
+ "unique": false
271
+ }
272
+ },
273
+ "indexes": [
274
+ {
275
+ "name": "attendance_corrections_slug_context_idx",
276
+ "columns": [
277
+ "tenant_id",
278
+ "slug",
279
+ "context"
280
+ ],
281
+ "unique": true
282
+ },
283
+ {
284
+ "name": "attendance_corrections_punch_idx",
285
+ "columns": [
286
+ "tenant_id",
287
+ "punch_id"
288
+ ]
289
+ },
290
+ {
291
+ "name": "attendance_corrections_subject_idx",
292
+ "columns": [
293
+ "tenant_id",
294
+ "subject_profile_id"
295
+ ]
296
+ },
297
+ {
298
+ "name": "attendance_corrections_tenant_id_created_at_idx",
299
+ "columns": [
300
+ "tenant_id",
301
+ "created_at"
302
+ ]
303
+ },
304
+ {
305
+ "name": "attendance_corrections_subject_profile_id_idx",
306
+ "columns": [
307
+ "subject_profile_id"
308
+ ]
309
+ },
310
+ {
311
+ "name": "attendance_corrections_actor_profile_id_idx",
312
+ "columns": [
313
+ "actor_profile_id"
314
+ ]
315
+ },
316
+ {
317
+ "name": "attendance_corrections_punch_id_idx",
318
+ "columns": [
319
+ "punch_id"
320
+ ]
321
+ },
322
+ {
323
+ "name": "attendance_corrections_acknowledged_by_profile_id_idx",
324
+ "columns": [
325
+ "acknowledged_by_profile_id"
326
+ ]
327
+ }
328
+ ],
329
+ "version": "19e8de69"
330
+ },
331
+ "importPath": "@happyvertical/smrt-timesheets/attendance"
332
+ },
333
+ "@happyvertical/smrt-timesheets:AttendanceCorrectionCollection": {
334
+ "name": "attendancecorrectioncollection",
335
+ "className": "AttendanceCorrectionCollection",
336
+ "qualifiedName": "@happyvertical/smrt-timesheets:AttendanceCorrectionCollection",
337
+ "collection": "attendancecorrections",
338
+ "description": "The correction ledger.",
339
+ "filePath": "/home/runner/work/smrt/smrt/packages/timesheets/src/attendance/correction-models.ts",
340
+ "packageName": "@happyvertical/smrt-timesheets",
341
+ "fields": {},
342
+ "methods": {},
343
+ "decoratorConfig": {
344
+ "tableName": "attendance_corrections"
345
+ },
346
+ "extends": "SmrtCollection",
347
+ "extendsTypeArg": "AttendanceCorrection",
348
+ "exportName": "AttendanceCorrectionCollection",
349
+ "collectionExportName": "AttendanceCorrectionCollectionCollection",
350
+ "schema": {
351
+ "tableName": "attendance_corrections",
352
+ "ddl": "CREATE TABLE IF NOT EXISTS \"attendance_corrections\" (\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 NOT NULL,\n \"subject_profile_id\" UUID,\n \"actor_profile_id\" UUID,\n \"kind\" TEXT,\n \"punch_id\" UUID,\n \"target_id\" TEXT,\n \"before_state\" TEXT,\n \"after_state\" TEXT,\n \"reason\" TEXT,\n \"acknowledgement_required\" BOOLEAN NOT NULL DEFAULT FALSE,\n \"acknowledged_at\" TIMESTAMP,\n \"acknowledged_by_profile_id\" UUID\n);",
353
+ "columns": {
354
+ "id": {
355
+ "type": "UUID",
356
+ "primaryKey": true,
357
+ "referenceKind": "id",
358
+ "notNull": true
359
+ },
360
+ "slug": {
361
+ "type": "TEXT",
362
+ "notNull": true
363
+ },
364
+ "context": {
365
+ "type": "TEXT",
366
+ "notNull": true,
367
+ "default": ""
368
+ },
369
+ "created_at": {
370
+ "type": "TIMESTAMP",
371
+ "notNull": true,
372
+ "default": "current_timestamp"
373
+ },
374
+ "updated_at": {
375
+ "type": "TIMESTAMP",
376
+ "notNull": true,
377
+ "default": "current_timestamp"
378
+ },
379
+ "tenant_id": {
380
+ "type": "UUID",
381
+ "referenceKind": "tenantId",
382
+ "notNull": true,
383
+ "unique": false
384
+ },
385
+ "subject_profile_id": {
386
+ "type": "UUID",
387
+ "referenceKind": "crossPackageRef",
388
+ "notNull": false,
389
+ "unique": false
390
+ },
391
+ "actor_profile_id": {
392
+ "type": "UUID",
393
+ "referenceKind": "crossPackageRef",
394
+ "notNull": false,
395
+ "unique": false
396
+ },
397
+ "kind": {
398
+ "type": "TEXT",
399
+ "notNull": false,
400
+ "unique": false
401
+ },
402
+ "punch_id": {
403
+ "type": "UUID",
404
+ "referenceKind": "foreignKey",
405
+ "notNull": false,
406
+ "unique": false,
407
+ "foreignKey": {
408
+ "table": "attendance_punches",
409
+ "column": "id",
410
+ "onDelete": "NO ACTION",
411
+ "onUpdate": "CASCADE"
412
+ }
413
+ },
414
+ "target_id": {
415
+ "type": "TEXT",
416
+ "notNull": false,
417
+ "unique": false
418
+ },
419
+ "before_state": {
420
+ "type": "TEXT",
421
+ "notNull": false,
422
+ "unique": false
423
+ },
424
+ "after_state": {
425
+ "type": "TEXT",
426
+ "notNull": false,
427
+ "unique": false
428
+ },
429
+ "reason": {
430
+ "type": "TEXT",
431
+ "notNull": false,
432
+ "unique": false
433
+ },
434
+ "acknowledgement_required": {
435
+ "type": "BOOLEAN",
436
+ "notNull": true,
437
+ "unique": false,
438
+ "default": false
439
+ },
440
+ "acknowledged_at": {
441
+ "type": "TIMESTAMP",
442
+ "notNull": false,
443
+ "unique": false
444
+ },
445
+ "acknowledged_by_profile_id": {
446
+ "type": "UUID",
447
+ "referenceKind": "crossPackageRef",
448
+ "notNull": false,
449
+ "unique": false
450
+ }
451
+ },
452
+ "indexes": [
453
+ {
454
+ "name": "attendance_corrections_slug_context_idx",
455
+ "columns": [
456
+ "tenant_id",
457
+ "slug",
458
+ "context"
459
+ ],
460
+ "unique": true
461
+ },
462
+ {
463
+ "name": "attendance_corrections_punch_idx",
464
+ "columns": [
465
+ "tenant_id",
466
+ "punch_id"
467
+ ]
468
+ },
469
+ {
470
+ "name": "attendance_corrections_subject_idx",
471
+ "columns": [
472
+ "tenant_id",
473
+ "subject_profile_id"
474
+ ]
475
+ },
476
+ {
477
+ "name": "attendance_corrections_tenant_id_created_at_idx",
478
+ "columns": [
479
+ "tenant_id",
480
+ "created_at"
481
+ ]
482
+ },
483
+ {
484
+ "name": "attendance_corrections_subject_profile_id_idx",
485
+ "columns": [
486
+ "subject_profile_id"
487
+ ]
488
+ },
489
+ {
490
+ "name": "attendance_corrections_actor_profile_id_idx",
491
+ "columns": [
492
+ "actor_profile_id"
493
+ ]
494
+ },
495
+ {
496
+ "name": "attendance_corrections_punch_id_idx",
497
+ "columns": [
498
+ "punch_id"
499
+ ]
500
+ },
501
+ {
502
+ "name": "attendance_corrections_acknowledged_by_profile_id_idx",
503
+ "columns": [
504
+ "acknowledged_by_profile_id"
505
+ ]
506
+ }
507
+ ],
508
+ "version": "19e8de69"
509
+ },
510
+ "importPath": "@happyvertical/smrt-timesheets/attendance"
511
+ },
7
512
  "@happyvertical/smrt-timesheets:AttendancePunch": {
8
513
  "name": "attendancepunch",
9
514
  "className": "AttendancePunch",
@@ -30,10 +535,367 @@
30
535
  }
31
536
  }
32
537
  },
33
- "profileId": {
34
- "type": "crossPackageRef",
538
+ "profileId": {
539
+ "type": "crossPackageRef",
540
+ "required": false,
541
+ "related": "@happyvertical/smrt-profiles:Profile"
542
+ },
543
+ "startedAt": {
544
+ "type": "datetime",
545
+ "required": false
546
+ },
547
+ "endedAt": {
548
+ "type": "datetime",
549
+ "required": false
550
+ },
551
+ "durationSeconds": {
552
+ "type": "integer",
553
+ "required": true,
554
+ "default": 0
555
+ },
556
+ "unpaidBreakSeconds": {
557
+ "type": "integer",
558
+ "required": true,
559
+ "default": 0
560
+ },
561
+ "reviewRequired": {
562
+ "type": "boolean",
563
+ "required": true,
564
+ "default": false
565
+ },
566
+ "autoCloseReason": {
567
+ "type": "text",
568
+ "required": false
569
+ },
570
+ "recordedOffline": {
571
+ "type": "boolean",
572
+ "required": true,
573
+ "default": false
574
+ },
575
+ "source": {
576
+ "type": "text",
577
+ "required": false
578
+ },
579
+ "deviceRefType": {
580
+ "type": "text",
581
+ "required": false
582
+ },
583
+ "deviceRefId": {
584
+ "type": "text",
585
+ "required": false
586
+ },
587
+ "serviceTimeEntryId": {
588
+ "type": "foreignKey",
589
+ "required": false,
590
+ "related": "ServiceTimeEntry",
591
+ "_meta": {
592
+ "nullable": true
593
+ }
594
+ },
595
+ "openSlot": {
596
+ "type": "text",
597
+ "required": true,
598
+ "_meta": {
599
+ "required": true
600
+ }
601
+ }
602
+ },
603
+ "methods": {
604
+ "save": {
605
+ "name": "save",
606
+ "async": true,
607
+ "parameters": [],
608
+ "returnType": "Promise<this>",
609
+ "isStatic": false,
610
+ "isPublic": true
611
+ }
612
+ },
613
+ "decoratorConfig": {
614
+ "tableName": "attendance_punches",
615
+ "indexes": [
616
+ {
617
+ "name": "attendance_punches_open_owner_key",
618
+ "columns": [
619
+ "tenantId",
620
+ "profileId",
621
+ "openSlot"
622
+ ],
623
+ "unique": true
624
+ },
625
+ {
626
+ "name": "attendance_punches_source_idx",
627
+ "columns": [
628
+ "tenantId",
629
+ "source"
630
+ ]
631
+ },
632
+ {
633
+ "name": "attendance_punches_device_idx",
634
+ "columns": [
635
+ "tenantId",
636
+ "deviceRefType",
637
+ "deviceRefId"
638
+ ]
639
+ }
640
+ ],
641
+ "api": {
642
+ "include": [
643
+ "list",
644
+ "get"
645
+ ]
646
+ },
647
+ "cli": {
648
+ "include": [
649
+ "list",
650
+ "get"
651
+ ]
652
+ },
653
+ "mcp": {
654
+ "include": [
655
+ "list",
656
+ "get"
657
+ ]
658
+ },
659
+ "tenantScoped": {
660
+ "mode": "required"
661
+ },
662
+ "conflictColumns": [
663
+ "tenant_id",
664
+ "slug",
665
+ "context"
666
+ ]
667
+ },
668
+ "extends": "SmrtObject",
669
+ "exportName": "AttendancePunch",
670
+ "collectionExportName": "AttendancePunchCollection",
671
+ "validationRules": [
672
+ {
673
+ "field": "durationSeconds",
674
+ "rule": "required",
675
+ "fieldType": "integer"
676
+ },
677
+ {
678
+ "field": "unpaidBreakSeconds",
679
+ "rule": "required",
680
+ "fieldType": "integer"
681
+ },
682
+ {
683
+ "field": "reviewRequired",
684
+ "rule": "required",
685
+ "fieldType": "boolean"
686
+ },
687
+ {
688
+ "field": "recordedOffline",
689
+ "rule": "required",
690
+ "fieldType": "boolean"
691
+ },
692
+ {
693
+ "field": "openSlot",
694
+ "rule": "required",
695
+ "fieldType": "text"
696
+ }
697
+ ],
698
+ "schema": {
699
+ "tableName": "attendance_punches",
700
+ "ddl": "CREATE TABLE IF NOT EXISTS \"attendance_punches\" (\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 NOT NULL,\n \"profile_id\" UUID,\n \"started_at\" TIMESTAMP,\n \"ended_at\" TIMESTAMP,\n \"duration_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"unpaid_break_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"review_required\" BOOLEAN NOT NULL DEFAULT FALSE,\n \"auto_close_reason\" TEXT,\n \"recorded_offline\" BOOLEAN NOT NULL DEFAULT FALSE,\n \"source\" TEXT,\n \"device_ref_type\" TEXT,\n \"device_ref_id\" TEXT,\n \"service_time_entry_id\" UUID,\n \"open_slot\" TEXT NOT NULL\n);",
701
+ "columns": {
702
+ "id": {
703
+ "type": "UUID",
704
+ "primaryKey": true,
705
+ "referenceKind": "id",
706
+ "notNull": true
707
+ },
708
+ "slug": {
709
+ "type": "TEXT",
710
+ "notNull": true
711
+ },
712
+ "context": {
713
+ "type": "TEXT",
714
+ "notNull": true,
715
+ "default": ""
716
+ },
717
+ "created_at": {
718
+ "type": "TIMESTAMP",
719
+ "notNull": true,
720
+ "default": "current_timestamp"
721
+ },
722
+ "updated_at": {
723
+ "type": "TIMESTAMP",
724
+ "notNull": true,
725
+ "default": "current_timestamp"
726
+ },
727
+ "tenant_id": {
728
+ "type": "UUID",
729
+ "referenceKind": "tenantId",
730
+ "notNull": true,
731
+ "unique": false
732
+ },
733
+ "profile_id": {
734
+ "type": "UUID",
735
+ "referenceKind": "crossPackageRef",
736
+ "notNull": false,
737
+ "unique": false
738
+ },
739
+ "started_at": {
740
+ "type": "TIMESTAMP",
741
+ "notNull": false,
742
+ "unique": false
743
+ },
744
+ "ended_at": {
745
+ "type": "TIMESTAMP",
746
+ "notNull": false,
747
+ "unique": false
748
+ },
749
+ "duration_seconds": {
750
+ "type": "INTEGER",
751
+ "notNull": true,
752
+ "unique": false,
753
+ "default": 0
754
+ },
755
+ "unpaid_break_seconds": {
756
+ "type": "INTEGER",
757
+ "notNull": true,
758
+ "unique": false,
759
+ "default": 0
760
+ },
761
+ "review_required": {
762
+ "type": "BOOLEAN",
763
+ "notNull": true,
764
+ "unique": false,
765
+ "default": false
766
+ },
767
+ "auto_close_reason": {
768
+ "type": "TEXT",
769
+ "notNull": false,
770
+ "unique": false
771
+ },
772
+ "recorded_offline": {
773
+ "type": "BOOLEAN",
774
+ "notNull": true,
775
+ "unique": false,
776
+ "default": false
777
+ },
778
+ "source": {
779
+ "type": "TEXT",
780
+ "notNull": false,
781
+ "unique": false
782
+ },
783
+ "device_ref_type": {
784
+ "type": "TEXT",
785
+ "notNull": false,
786
+ "unique": false
787
+ },
788
+ "device_ref_id": {
789
+ "type": "TEXT",
790
+ "notNull": false,
791
+ "unique": false
792
+ },
793
+ "service_time_entry_id": {
794
+ "type": "UUID",
795
+ "referenceKind": "foreignKey",
796
+ "notNull": false,
797
+ "unique": false,
798
+ "foreignKey": {
799
+ "table": "service_time_entries",
800
+ "column": "id",
801
+ "onDelete": "NO ACTION",
802
+ "onUpdate": "CASCADE"
803
+ }
804
+ },
805
+ "open_slot": {
806
+ "type": "TEXT",
807
+ "notNull": true,
808
+ "unique": false
809
+ }
810
+ },
811
+ "indexes": [
812
+ {
813
+ "name": "attendance_punches_slug_context_idx",
814
+ "columns": [
815
+ "tenant_id",
816
+ "slug",
817
+ "context"
818
+ ],
819
+ "unique": true
820
+ },
821
+ {
822
+ "name": "attendance_punches_open_owner_key",
823
+ "columns": [
824
+ "tenant_id",
825
+ "profile_id",
826
+ "open_slot"
827
+ ],
828
+ "unique": true
829
+ },
830
+ {
831
+ "name": "attendance_punches_source_idx",
832
+ "columns": [
833
+ "tenant_id",
834
+ "source"
835
+ ]
836
+ },
837
+ {
838
+ "name": "attendance_punches_device_idx",
839
+ "columns": [
840
+ "tenant_id",
841
+ "device_ref_type",
842
+ "device_ref_id"
843
+ ]
844
+ },
845
+ {
846
+ "name": "attendance_punches_tenant_id_created_at_idx",
847
+ "columns": [
848
+ "tenant_id",
849
+ "created_at"
850
+ ]
851
+ },
852
+ {
853
+ "name": "attendance_punches_profile_id_idx",
854
+ "columns": [
855
+ "profile_id"
856
+ ]
857
+ },
858
+ {
859
+ "name": "attendance_punches_service_time_entry_id_idx",
860
+ "columns": [
861
+ "service_time_entry_id"
862
+ ]
863
+ }
864
+ ],
865
+ "version": "6fa5db50"
866
+ },
867
+ "importPath": "@happyvertical/smrt-timesheets/attendance"
868
+ },
869
+ "@happyvertical/smrt-timesheets:AttendanceBreak": {
870
+ "name": "attendancebreak",
871
+ "className": "AttendanceBreak",
872
+ "qualifiedName": "@happyvertical/smrt-timesheets:AttendanceBreak",
873
+ "collection": "attendancebreaks",
874
+ "description": "A paid or unpaid break inside one attendance punch.",
875
+ "filePath": "/home/runner/work/smrt/smrt/packages/timesheets/src/attendance/models.ts",
876
+ "packageName": "@happyvertical/smrt-timesheets",
877
+ "fields": {
878
+ "tenantId": {
879
+ "type": "text",
880
+ "required": true,
881
+ "_meta": {
882
+ "sqlType": "UUID",
883
+ "__tenancy": {
884
+ "isTenantIdField": true,
885
+ "autoFilter": true,
886
+ "required": true,
887
+ "autoPopulate": true,
888
+ "nullable": false,
889
+ "mode": "required",
890
+ "field": "tenantId",
891
+ "allowSuperAdminBypass": false
892
+ }
893
+ }
894
+ },
895
+ "punchId": {
896
+ "type": "foreignKey",
35
897
  "required": false,
36
- "related": "@happyvertical/smrt-profiles:Profile"
898
+ "related": "AttendancePunch"
37
899
  },
38
900
  "startedAt": {
39
901
  "type": "datetime",
@@ -43,33 +905,14 @@
43
905
  "type": "datetime",
44
906
  "required": false
45
907
  },
46
- "durationSeconds": {
47
- "type": "integer",
48
- "required": true,
49
- "default": 0
50
- },
51
- "unpaidBreakSeconds": {
52
- "type": "integer",
53
- "required": true,
54
- "default": 0
55
- },
56
- "reviewRequired": {
57
- "type": "boolean",
58
- "required": true,
59
- "default": false
60
- },
61
- "recordedOffline": {
908
+ "paid": {
62
909
  "type": "boolean",
63
910
  "required": true,
64
911
  "default": false
65
912
  },
66
- "serviceTimeEntryId": {
67
- "type": "foreignKey",
68
- "required": false,
69
- "related": "ServiceTimeEntry",
70
- "_meta": {
71
- "nullable": true
72
- }
913
+ "kind": {
914
+ "type": "text",
915
+ "required": false
73
916
  },
74
917
  "openSlot": {
75
918
  "type": "text",
@@ -87,16 +930,24 @@
87
930
  "returnType": "Promise<this>",
88
931
  "isStatic": false,
89
932
  "isPublic": true
933
+ },
934
+ "delete": {
935
+ "name": "delete",
936
+ "async": true,
937
+ "parameters": [],
938
+ "returnType": "Promise<void>",
939
+ "isStatic": false,
940
+ "isPublic": true
90
941
  }
91
942
  },
92
943
  "decoratorConfig": {
93
- "tableName": "attendance_punches",
944
+ "tableName": "attendance_breaks",
94
945
  "indexes": [
95
946
  {
96
- "name": "attendance_punches_open_owner_key",
947
+ "name": "attendance_breaks_open_punch_key",
97
948
  "columns": [
98
949
  "tenantId",
99
- "profileId",
950
+ "punchId",
100
951
  "openSlot"
101
952
  ],
102
953
  "unique": true
@@ -130,26 +981,11 @@
130
981
  ]
131
982
  },
132
983
  "extends": "SmrtObject",
133
- "exportName": "AttendancePunch",
134
- "collectionExportName": "AttendancePunchCollection",
984
+ "exportName": "AttendanceBreak",
985
+ "collectionExportName": "AttendanceBreakCollection",
135
986
  "validationRules": [
136
987
  {
137
- "field": "durationSeconds",
138
- "rule": "required",
139
- "fieldType": "integer"
140
- },
141
- {
142
- "field": "unpaidBreakSeconds",
143
- "rule": "required",
144
- "fieldType": "integer"
145
- },
146
- {
147
- "field": "reviewRequired",
148
- "rule": "required",
149
- "fieldType": "boolean"
150
- },
151
- {
152
- "field": "recordedOffline",
988
+ "field": "paid",
153
989
  "rule": "required",
154
990
  "fieldType": "boolean"
155
991
  },
@@ -160,8 +996,8 @@
160
996
  }
161
997
  ],
162
998
  "schema": {
163
- "tableName": "attendance_punches",
164
- "ddl": "CREATE TABLE IF NOT EXISTS \"attendance_punches\" (\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 NOT NULL,\n \"profile_id\" UUID,\n \"started_at\" TIMESTAMP,\n \"ended_at\" TIMESTAMP,\n \"duration_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"unpaid_break_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"review_required\" BOOLEAN NOT NULL DEFAULT FALSE,\n \"recorded_offline\" BOOLEAN NOT NULL DEFAULT FALSE,\n \"service_time_entry_id\" UUID,\n \"open_slot\" TEXT NOT NULL\n);",
999
+ "tableName": "attendance_breaks",
1000
+ "ddl": "CREATE TABLE IF NOT EXISTS \"attendance_breaks\" (\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 NOT NULL,\n \"punch_id\" UUID,\n \"started_at\" TIMESTAMP,\n \"ended_at\" TIMESTAMP,\n \"paid\" BOOLEAN NOT NULL DEFAULT FALSE,\n \"kind\" TEXT,\n \"open_slot\" TEXT NOT NULL\n);",
165
1001
  "columns": {
166
1002
  "id": {
167
1003
  "type": "UUID",
@@ -194,11 +1030,17 @@
194
1030
  "notNull": true,
195
1031
  "unique": false
196
1032
  },
197
- "profile_id": {
1033
+ "punch_id": {
198
1034
  "type": "UUID",
199
- "referenceKind": "crossPackageRef",
1035
+ "referenceKind": "foreignKey",
200
1036
  "notNull": false,
201
- "unique": false
1037
+ "unique": false,
1038
+ "foreignKey": {
1039
+ "table": "attendance_punches",
1040
+ "column": "id",
1041
+ "onDelete": "NO ACTION",
1042
+ "onUpdate": "CASCADE"
1043
+ }
202
1044
  },
203
1045
  "started_at": {
204
1046
  "type": "TIMESTAMP",
@@ -210,41 +1052,16 @@
210
1052
  "notNull": false,
211
1053
  "unique": false
212
1054
  },
213
- "duration_seconds": {
214
- "type": "INTEGER",
215
- "notNull": true,
216
- "unique": false,
217
- "default": 0
218
- },
219
- "unpaid_break_seconds": {
220
- "type": "INTEGER",
221
- "notNull": true,
222
- "unique": false,
223
- "default": 0
224
- },
225
- "review_required": {
226
- "type": "BOOLEAN",
227
- "notNull": true,
228
- "unique": false,
229
- "default": false
230
- },
231
- "recorded_offline": {
1055
+ "paid": {
232
1056
  "type": "BOOLEAN",
233
1057
  "notNull": true,
234
1058
  "unique": false,
235
1059
  "default": false
236
1060
  },
237
- "service_time_entry_id": {
238
- "type": "UUID",
239
- "referenceKind": "foreignKey",
1061
+ "kind": {
1062
+ "type": "TEXT",
240
1063
  "notNull": false,
241
- "unique": false,
242
- "foreignKey": {
243
- "table": "service_time_entries",
244
- "column": "id",
245
- "onDelete": "NO ACTION",
246
- "onUpdate": "CASCADE"
247
- }
1064
+ "unique": false
248
1065
  },
249
1066
  "open_slot": {
250
1067
  "type": "TEXT",
@@ -254,7 +1071,7 @@
254
1071
  },
255
1072
  "indexes": [
256
1073
  {
257
- "name": "attendance_punches_slug_context_idx",
1074
+ "name": "attendance_breaks_slug_context_idx",
258
1075
  "columns": [
259
1076
  "tenant_id",
260
1077
  "slug",
@@ -263,44 +1080,38 @@
263
1080
  "unique": true
264
1081
  },
265
1082
  {
266
- "name": "attendance_punches_open_owner_key",
1083
+ "name": "attendance_breaks_open_punch_key",
267
1084
  "columns": [
268
1085
  "tenant_id",
269
- "profile_id",
1086
+ "punch_id",
270
1087
  "open_slot"
271
1088
  ],
272
1089
  "unique": true
273
1090
  },
274
1091
  {
275
- "name": "attendance_punches_tenant_id_created_at_idx",
1092
+ "name": "attendance_breaks_tenant_id_created_at_idx",
276
1093
  "columns": [
277
1094
  "tenant_id",
278
1095
  "created_at"
279
1096
  ]
280
1097
  },
281
1098
  {
282
- "name": "attendance_punches_profile_id_idx",
283
- "columns": [
284
- "profile_id"
285
- ]
286
- },
287
- {
288
- "name": "attendance_punches_service_time_entry_id_idx",
1099
+ "name": "attendance_breaks_punch_id_idx",
289
1100
  "columns": [
290
- "service_time_entry_id"
1101
+ "punch_id"
291
1102
  ]
292
1103
  }
293
1104
  ],
294
- "version": "eeca63b1"
1105
+ "version": "1f6b2ddc"
295
1106
  },
296
1107
  "importPath": "@happyvertical/smrt-timesheets/attendance"
297
1108
  },
298
- "@happyvertical/smrt-timesheets:AttendanceBreak": {
299
- "name": "attendancebreak",
300
- "className": "AttendanceBreak",
301
- "qualifiedName": "@happyvertical/smrt-timesheets:AttendanceBreak",
302
- "collection": "attendancebreaks",
303
- "description": "A paid or unpaid break inside one attendance punch.",
1109
+ "@happyvertical/smrt-timesheets:AttendanceSegment": {
1110
+ "name": "attendancesegment",
1111
+ "className": "AttendanceSegment",
1112
+ "qualifiedName": "@happyvertical/smrt-timesheets:AttendanceSegment",
1113
+ "collection": "attendancesegments",
1114
+ "description": "A running unit of work inside one attendance punch: a work reference plus an optional second (task) reference as queryable columns, so job costing can index and join them.",
304
1115
  "filePath": "/home/runner/work/smrt/smrt/packages/timesheets/src/attendance/models.ts",
305
1116
  "packageName": "@happyvertical/smrt-timesheets",
306
1117
  "fields": {
@@ -326,6 +1137,30 @@
326
1137
  "required": false,
327
1138
  "related": "AttendancePunch"
328
1139
  },
1140
+ "workRefType": {
1141
+ "type": "text",
1142
+ "required": false
1143
+ },
1144
+ "workRefId": {
1145
+ "type": "text",
1146
+ "required": false
1147
+ },
1148
+ "taskRefType": {
1149
+ "type": "text",
1150
+ "required": false
1151
+ },
1152
+ "taskRefId": {
1153
+ "type": "text",
1154
+ "required": false
1155
+ },
1156
+ "kind": {
1157
+ "type": "text",
1158
+ "required": false
1159
+ },
1160
+ "description": {
1161
+ "type": "text",
1162
+ "required": false
1163
+ },
329
1164
  "startedAt": {
330
1165
  "type": "datetime",
331
1166
  "required": false
@@ -334,7 +1169,17 @@
334
1169
  "type": "datetime",
335
1170
  "required": false
336
1171
  },
337
- "paid": {
1172
+ "durationSeconds": {
1173
+ "type": "integer",
1174
+ "required": true,
1175
+ "default": 0
1176
+ },
1177
+ "closedReason": {
1178
+ "type": "text",
1179
+ "required": false,
1180
+ "default": ""
1181
+ },
1182
+ "reviewRequired": {
338
1183
  "type": "boolean",
339
1184
  "required": true,
340
1185
  "default": false
@@ -355,19 +1200,43 @@
355
1200
  "returnType": "Promise<this>",
356
1201
  "isStatic": false,
357
1202
  "isPublic": true
1203
+ },
1204
+ "delete": {
1205
+ "name": "delete",
1206
+ "async": true,
1207
+ "parameters": [],
1208
+ "returnType": "Promise<void>",
1209
+ "isStatic": false,
1210
+ "isPublic": true
358
1211
  }
359
1212
  },
360
1213
  "decoratorConfig": {
361
- "tableName": "attendance_breaks",
1214
+ "tableName": "attendance_segments",
362
1215
  "indexes": [
363
1216
  {
364
- "name": "attendance_breaks_open_punch_key",
1217
+ "name": "attendance_segments_open_punch_key",
365
1218
  "columns": [
366
1219
  "tenantId",
367
1220
  "punchId",
368
1221
  "openSlot"
369
1222
  ],
370
1223
  "unique": true
1224
+ },
1225
+ {
1226
+ "name": "attendance_segments_work_idx",
1227
+ "columns": [
1228
+ "tenantId",
1229
+ "workRefType",
1230
+ "workRefId"
1231
+ ]
1232
+ },
1233
+ {
1234
+ "name": "attendance_segments_task_idx",
1235
+ "columns": [
1236
+ "tenantId",
1237
+ "taskRefType",
1238
+ "taskRefId"
1239
+ ]
371
1240
  }
372
1241
  ],
373
1242
  "api": {
@@ -398,11 +1267,16 @@
398
1267
  ]
399
1268
  },
400
1269
  "extends": "SmrtObject",
401
- "exportName": "AttendanceBreak",
402
- "collectionExportName": "AttendanceBreakCollection",
1270
+ "exportName": "AttendanceSegment",
1271
+ "collectionExportName": "AttendanceSegmentCollection",
403
1272
  "validationRules": [
404
1273
  {
405
- "field": "paid",
1274
+ "field": "durationSeconds",
1275
+ "rule": "required",
1276
+ "fieldType": "integer"
1277
+ },
1278
+ {
1279
+ "field": "reviewRequired",
406
1280
  "rule": "required",
407
1281
  "fieldType": "boolean"
408
1282
  },
@@ -413,8 +1287,8 @@
413
1287
  }
414
1288
  ],
415
1289
  "schema": {
416
- "tableName": "attendance_breaks",
417
- "ddl": "CREATE TABLE IF NOT EXISTS \"attendance_breaks\" (\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 NOT NULL,\n \"punch_id\" UUID,\n \"started_at\" TIMESTAMP,\n \"ended_at\" TIMESTAMP,\n \"paid\" BOOLEAN NOT NULL DEFAULT FALSE,\n \"open_slot\" TEXT NOT NULL\n);",
1290
+ "tableName": "attendance_segments",
1291
+ "ddl": "CREATE TABLE IF NOT EXISTS \"attendance_segments\" (\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 NOT NULL,\n \"punch_id\" UUID,\n \"work_ref_type\" TEXT,\n \"work_ref_id\" TEXT,\n \"task_ref_type\" TEXT,\n \"task_ref_id\" TEXT,\n \"kind\" TEXT,\n \"description\" TEXT,\n \"started_at\" TIMESTAMP,\n \"ended_at\" TIMESTAMP,\n \"duration_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"closed_reason\" TEXT DEFAULT '',\n \"review_required\" BOOLEAN NOT NULL DEFAULT FALSE,\n \"open_slot\" TEXT NOT NULL\n);",
418
1292
  "columns": {
419
1293
  "id": {
420
1294
  "type": "UUID",
@@ -459,6 +1333,36 @@
459
1333
  "onUpdate": "CASCADE"
460
1334
  }
461
1335
  },
1336
+ "work_ref_type": {
1337
+ "type": "TEXT",
1338
+ "notNull": false,
1339
+ "unique": false
1340
+ },
1341
+ "work_ref_id": {
1342
+ "type": "TEXT",
1343
+ "notNull": false,
1344
+ "unique": false
1345
+ },
1346
+ "task_ref_type": {
1347
+ "type": "TEXT",
1348
+ "notNull": false,
1349
+ "unique": false
1350
+ },
1351
+ "task_ref_id": {
1352
+ "type": "TEXT",
1353
+ "notNull": false,
1354
+ "unique": false
1355
+ },
1356
+ "kind": {
1357
+ "type": "TEXT",
1358
+ "notNull": false,
1359
+ "unique": false
1360
+ },
1361
+ "description": {
1362
+ "type": "TEXT",
1363
+ "notNull": false,
1364
+ "unique": false
1365
+ },
462
1366
  "started_at": {
463
1367
  "type": "TIMESTAMP",
464
1368
  "notNull": false,
@@ -469,7 +1373,19 @@
469
1373
  "notNull": false,
470
1374
  "unique": false
471
1375
  },
472
- "paid": {
1376
+ "duration_seconds": {
1377
+ "type": "INTEGER",
1378
+ "notNull": true,
1379
+ "unique": false,
1380
+ "default": 0
1381
+ },
1382
+ "closed_reason": {
1383
+ "type": "TEXT",
1384
+ "notNull": false,
1385
+ "unique": false,
1386
+ "default": ""
1387
+ },
1388
+ "review_required": {
473
1389
  "type": "BOOLEAN",
474
1390
  "notNull": true,
475
1391
  "unique": false,
@@ -483,7 +1399,7 @@
483
1399
  },
484
1400
  "indexes": [
485
1401
  {
486
- "name": "attendance_breaks_slug_context_idx",
1402
+ "name": "attendance_segments_slug_context_idx",
487
1403
  "columns": [
488
1404
  "tenant_id",
489
1405
  "slug",
@@ -492,7 +1408,7 @@
492
1408
  "unique": true
493
1409
  },
494
1410
  {
495
- "name": "attendance_breaks_open_punch_key",
1411
+ "name": "attendance_segments_open_punch_key",
496
1412
  "columns": [
497
1413
  "tenant_id",
498
1414
  "punch_id",
@@ -501,20 +1417,36 @@
501
1417
  "unique": true
502
1418
  },
503
1419
  {
504
- "name": "attendance_breaks_tenant_id_created_at_idx",
1420
+ "name": "attendance_segments_work_idx",
1421
+ "columns": [
1422
+ "tenant_id",
1423
+ "work_ref_type",
1424
+ "work_ref_id"
1425
+ ]
1426
+ },
1427
+ {
1428
+ "name": "attendance_segments_task_idx",
1429
+ "columns": [
1430
+ "tenant_id",
1431
+ "task_ref_type",
1432
+ "task_ref_id"
1433
+ ]
1434
+ },
1435
+ {
1436
+ "name": "attendance_segments_tenant_id_created_at_idx",
505
1437
  "columns": [
506
1438
  "tenant_id",
507
1439
  "created_at"
508
1440
  ]
509
1441
  },
510
1442
  {
511
- "name": "attendance_breaks_punch_id_idx",
1443
+ "name": "attendance_segments_punch_id_idx",
512
1444
  "columns": [
513
1445
  "punch_id"
514
1446
  ]
515
1447
  }
516
1448
  ],
517
- "version": "00cb739e"
1449
+ "version": "6e1c6c80"
518
1450
  },
519
1451
  "importPath": "@happyvertical/smrt-timesheets/attendance"
520
1452
  },
@@ -718,7 +1650,7 @@
718
1650
  "collectionExportName": "AttendancePunchCollectionCollection",
719
1651
  "schema": {
720
1652
  "tableName": "attendance_punches",
721
- "ddl": "CREATE TABLE IF NOT EXISTS \"attendance_punches\" (\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 NOT NULL,\n \"profile_id\" UUID,\n \"started_at\" TIMESTAMP,\n \"ended_at\" TIMESTAMP,\n \"duration_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"unpaid_break_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"review_required\" BOOLEAN NOT NULL DEFAULT FALSE,\n \"recorded_offline\" BOOLEAN NOT NULL DEFAULT FALSE,\n \"service_time_entry_id\" UUID,\n \"open_slot\" TEXT NOT NULL\n);",
1653
+ "ddl": "CREATE TABLE IF NOT EXISTS \"attendance_punches\" (\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 NOT NULL,\n \"profile_id\" UUID,\n \"started_at\" TIMESTAMP,\n \"ended_at\" TIMESTAMP,\n \"duration_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"unpaid_break_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"review_required\" BOOLEAN NOT NULL DEFAULT FALSE,\n \"auto_close_reason\" TEXT,\n \"recorded_offline\" BOOLEAN NOT NULL DEFAULT FALSE,\n \"source\" TEXT,\n \"device_ref_type\" TEXT,\n \"device_ref_id\" TEXT,\n \"service_time_entry_id\" UUID,\n \"open_slot\" TEXT NOT NULL\n);",
722
1654
  "columns": {
723
1655
  "id": {
724
1656
  "type": "UUID",
@@ -785,12 +1717,32 @@
785
1717
  "unique": false,
786
1718
  "default": false
787
1719
  },
1720
+ "auto_close_reason": {
1721
+ "type": "TEXT",
1722
+ "notNull": false,
1723
+ "unique": false
1724
+ },
788
1725
  "recorded_offline": {
789
1726
  "type": "BOOLEAN",
790
1727
  "notNull": true,
791
1728
  "unique": false,
792
1729
  "default": false
793
1730
  },
1731
+ "source": {
1732
+ "type": "TEXT",
1733
+ "notNull": false,
1734
+ "unique": false
1735
+ },
1736
+ "device_ref_type": {
1737
+ "type": "TEXT",
1738
+ "notNull": false,
1739
+ "unique": false
1740
+ },
1741
+ "device_ref_id": {
1742
+ "type": "TEXT",
1743
+ "notNull": false,
1744
+ "unique": false
1745
+ },
794
1746
  "service_time_entry_id": {
795
1747
  "type": "UUID",
796
1748
  "referenceKind": "foreignKey",
@@ -828,6 +1780,21 @@
828
1780
  ],
829
1781
  "unique": true
830
1782
  },
1783
+ {
1784
+ "name": "attendance_punches_source_idx",
1785
+ "columns": [
1786
+ "tenant_id",
1787
+ "source"
1788
+ ]
1789
+ },
1790
+ {
1791
+ "name": "attendance_punches_device_idx",
1792
+ "columns": [
1793
+ "tenant_id",
1794
+ "device_ref_type",
1795
+ "device_ref_id"
1796
+ ]
1797
+ },
831
1798
  {
832
1799
  "name": "attendance_punches_tenant_id_created_at_idx",
833
1800
  "columns": [
@@ -848,7 +1815,7 @@
848
1815
  ]
849
1816
  }
850
1817
  ],
851
- "version": "eeca63b1"
1818
+ "version": "6fa5db50"
852
1819
  },
853
1820
  "importPath": "@happyvertical/smrt-timesheets/attendance"
854
1821
  },
@@ -871,7 +1838,7 @@
871
1838
  "collectionExportName": "AttendanceBreakCollectionCollection",
872
1839
  "schema": {
873
1840
  "tableName": "attendance_breaks",
874
- "ddl": "CREATE TABLE IF NOT EXISTS \"attendance_breaks\" (\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 NOT NULL,\n \"punch_id\" UUID,\n \"started_at\" TIMESTAMP,\n \"ended_at\" TIMESTAMP,\n \"paid\" BOOLEAN NOT NULL DEFAULT FALSE,\n \"open_slot\" TEXT NOT NULL\n);",
1841
+ "ddl": "CREATE TABLE IF NOT EXISTS \"attendance_breaks\" (\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 NOT NULL,\n \"punch_id\" UUID,\n \"started_at\" TIMESTAMP,\n \"ended_at\" TIMESTAMP,\n \"paid\" BOOLEAN NOT NULL DEFAULT FALSE,\n \"kind\" TEXT,\n \"open_slot\" TEXT NOT NULL\n);",
875
1842
  "columns": {
876
1843
  "id": {
877
1844
  "type": "UUID",
@@ -932,6 +1899,11 @@
932
1899
  "unique": false,
933
1900
  "default": false
934
1901
  },
1902
+ "kind": {
1903
+ "type": "TEXT",
1904
+ "notNull": false,
1905
+ "unique": false
1906
+ },
935
1907
  "open_slot": {
936
1908
  "type": "TEXT",
937
1909
  "notNull": true,
@@ -971,7 +1943,188 @@
971
1943
  ]
972
1944
  }
973
1945
  ],
974
- "version": "00cb739e"
1946
+ "version": "1f6b2ddc"
1947
+ },
1948
+ "importPath": "@happyvertical/smrt-timesheets/attendance"
1949
+ },
1950
+ "@happyvertical/smrt-timesheets:AttendanceSegmentCollection": {
1951
+ "name": "attendancesegmentcollection",
1952
+ "className": "AttendanceSegmentCollection",
1953
+ "qualifiedName": "@happyvertical/smrt-timesheets:AttendanceSegmentCollection",
1954
+ "collection": "attendancesegments",
1955
+ "description": "Work segments for job costing and attendance review.",
1956
+ "filePath": "/home/runner/work/smrt/smrt/packages/timesheets/src/attendance/models.ts",
1957
+ "packageName": "@happyvertical/smrt-timesheets",
1958
+ "fields": {},
1959
+ "methods": {},
1960
+ "decoratorConfig": {
1961
+ "tableName": "attendance_segments"
1962
+ },
1963
+ "extends": "SmrtCollection",
1964
+ "extendsTypeArg": "AttendanceSegment",
1965
+ "exportName": "AttendanceSegmentCollection",
1966
+ "collectionExportName": "AttendanceSegmentCollectionCollection",
1967
+ "schema": {
1968
+ "tableName": "attendance_segments",
1969
+ "ddl": "CREATE TABLE IF NOT EXISTS \"attendance_segments\" (\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 NOT NULL,\n \"punch_id\" UUID,\n \"work_ref_type\" TEXT,\n \"work_ref_id\" TEXT,\n \"task_ref_type\" TEXT,\n \"task_ref_id\" TEXT,\n \"kind\" TEXT,\n \"description\" TEXT,\n \"started_at\" TIMESTAMP,\n \"ended_at\" TIMESTAMP,\n \"duration_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"closed_reason\" TEXT DEFAULT '',\n \"review_required\" BOOLEAN NOT NULL DEFAULT FALSE,\n \"open_slot\" TEXT NOT NULL\n);",
1970
+ "columns": {
1971
+ "id": {
1972
+ "type": "UUID",
1973
+ "primaryKey": true,
1974
+ "referenceKind": "id",
1975
+ "notNull": true
1976
+ },
1977
+ "slug": {
1978
+ "type": "TEXT",
1979
+ "notNull": true
1980
+ },
1981
+ "context": {
1982
+ "type": "TEXT",
1983
+ "notNull": true,
1984
+ "default": ""
1985
+ },
1986
+ "created_at": {
1987
+ "type": "TIMESTAMP",
1988
+ "notNull": true,
1989
+ "default": "current_timestamp"
1990
+ },
1991
+ "updated_at": {
1992
+ "type": "TIMESTAMP",
1993
+ "notNull": true,
1994
+ "default": "current_timestamp"
1995
+ },
1996
+ "tenant_id": {
1997
+ "type": "UUID",
1998
+ "referenceKind": "tenantId",
1999
+ "notNull": true,
2000
+ "unique": false
2001
+ },
2002
+ "punch_id": {
2003
+ "type": "UUID",
2004
+ "referenceKind": "foreignKey",
2005
+ "notNull": false,
2006
+ "unique": false,
2007
+ "foreignKey": {
2008
+ "table": "attendance_punches",
2009
+ "column": "id",
2010
+ "onDelete": "NO ACTION",
2011
+ "onUpdate": "CASCADE"
2012
+ }
2013
+ },
2014
+ "work_ref_type": {
2015
+ "type": "TEXT",
2016
+ "notNull": false,
2017
+ "unique": false
2018
+ },
2019
+ "work_ref_id": {
2020
+ "type": "TEXT",
2021
+ "notNull": false,
2022
+ "unique": false
2023
+ },
2024
+ "task_ref_type": {
2025
+ "type": "TEXT",
2026
+ "notNull": false,
2027
+ "unique": false
2028
+ },
2029
+ "task_ref_id": {
2030
+ "type": "TEXT",
2031
+ "notNull": false,
2032
+ "unique": false
2033
+ },
2034
+ "kind": {
2035
+ "type": "TEXT",
2036
+ "notNull": false,
2037
+ "unique": false
2038
+ },
2039
+ "description": {
2040
+ "type": "TEXT",
2041
+ "notNull": false,
2042
+ "unique": false
2043
+ },
2044
+ "started_at": {
2045
+ "type": "TIMESTAMP",
2046
+ "notNull": false,
2047
+ "unique": false
2048
+ },
2049
+ "ended_at": {
2050
+ "type": "TIMESTAMP",
2051
+ "notNull": false,
2052
+ "unique": false
2053
+ },
2054
+ "duration_seconds": {
2055
+ "type": "INTEGER",
2056
+ "notNull": true,
2057
+ "unique": false,
2058
+ "default": 0
2059
+ },
2060
+ "closed_reason": {
2061
+ "type": "TEXT",
2062
+ "notNull": false,
2063
+ "unique": false,
2064
+ "default": ""
2065
+ },
2066
+ "review_required": {
2067
+ "type": "BOOLEAN",
2068
+ "notNull": true,
2069
+ "unique": false,
2070
+ "default": false
2071
+ },
2072
+ "open_slot": {
2073
+ "type": "TEXT",
2074
+ "notNull": true,
2075
+ "unique": false
2076
+ }
2077
+ },
2078
+ "indexes": [
2079
+ {
2080
+ "name": "attendance_segments_slug_context_idx",
2081
+ "columns": [
2082
+ "tenant_id",
2083
+ "slug",
2084
+ "context"
2085
+ ],
2086
+ "unique": true
2087
+ },
2088
+ {
2089
+ "name": "attendance_segments_open_punch_key",
2090
+ "columns": [
2091
+ "tenant_id",
2092
+ "punch_id",
2093
+ "open_slot"
2094
+ ],
2095
+ "unique": true
2096
+ },
2097
+ {
2098
+ "name": "attendance_segments_work_idx",
2099
+ "columns": [
2100
+ "tenant_id",
2101
+ "work_ref_type",
2102
+ "work_ref_id"
2103
+ ]
2104
+ },
2105
+ {
2106
+ "name": "attendance_segments_task_idx",
2107
+ "columns": [
2108
+ "tenant_id",
2109
+ "task_ref_type",
2110
+ "task_ref_id"
2111
+ ]
2112
+ },
2113
+ {
2114
+ "name": "attendance_segments_tenant_id_created_at_idx",
2115
+ "columns": [
2116
+ "tenant_id",
2117
+ "created_at"
2118
+ ]
2119
+ },
2120
+ {
2121
+ "name": "attendance_segments_punch_id_idx",
2122
+ "columns": [
2123
+ "punch_id"
2124
+ ]
2125
+ }
2126
+ ],
2127
+ "version": "6e1c6c80"
975
2128
  },
976
2129
  "importPath": "@happyvertical/smrt-timesheets/attendance"
977
2130
  },
@@ -1518,12 +2671,18 @@
1518
2671
  "className": "ServiceChargeSnapshotCollection",
1519
2672
  "qualifiedName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshotCollection",
1520
2673
  "collection": "servicechargesnapshots",
1521
- "description": "Collection over service_charge_snapshots.",
1522
2674
  "filePath": "/home/runner/work/smrt/smrt/packages/timesheets/src/models/service-snapshots.ts",
1523
2675
  "packageName": "@happyvertical/smrt-timesheets",
1524
2676
  "fields": {},
1525
2677
  "methods": {},
1526
2678
  "decoratorConfig": {
2679
+ "mcp": {
2680
+ "include": [
2681
+ "list",
2682
+ "get"
2683
+ ]
2684
+ },
2685
+ "cli": false,
1527
2686
  "tableName": "service_charge_snapshots"
1528
2687
  },
1529
2688
  "extends": "SmrtCollection",
@@ -1641,12 +2800,18 @@
1641
2800
  "className": "ServiceCompensationSnapshotCollection",
1642
2801
  "qualifiedName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshotCollection",
1643
2802
  "collection": "servicecompensationsnapshots",
1644
- "description": "Collection over service_compensation_snapshots.",
1645
2803
  "filePath": "/home/runner/work/smrt/smrt/packages/timesheets/src/models/service-snapshots.ts",
1646
2804
  "packageName": "@happyvertical/smrt-timesheets",
1647
2805
  "fields": {},
1648
2806
  "methods": {},
1649
2807
  "decoratorConfig": {
2808
+ "mcp": {
2809
+ "include": [
2810
+ "list",
2811
+ "get"
2812
+ ]
2813
+ },
2814
+ "cli": false,
1650
2815
  "tableName": "service_compensation_snapshots"
1651
2816
  },
1652
2817
  "extends": "SmrtCollection",
@@ -2011,7 +3176,10 @@
2011
3176
  "api": {
2012
3177
  "include": [
2013
3178
  "list",
2014
- "get"
3179
+ "get",
3180
+ "record",
3181
+ "submit",
3182
+ "approve"
2015
3183
  ]
2016
3184
  },
2017
3185
  "cli": {
@@ -2258,6 +3426,72 @@
2258
3426
  "packageName": "@happyvertical/smrt-timesheets",
2259
3427
  "fields": {},
2260
3428
  "methods": {
3429
+ "record": {
3430
+ "name": "record",
3431
+ "async": true,
3432
+ "parameters": [
3433
+ {
3434
+ "name": "options",
3435
+ "type": "RecordServiceTimeActionInput",
3436
+ "optional": false
3437
+ }
3438
+ ],
3439
+ "returnType": "Promise<ServiceTimeEntry>",
3440
+ "isStatic": false,
3441
+ "isPublic": true,
3442
+ "decoratorConfig": {
3443
+ "httpMethod": "POST",
3444
+ "path": "record",
3445
+ "effect": "write",
3446
+ "idempotent": false,
3447
+ "openWorld": false,
3448
+ "description": "Record a draft time entry for the signed-in person (service-backed)."
3449
+ }
3450
+ },
3451
+ "submit": {
3452
+ "name": "submit",
3453
+ "async": true,
3454
+ "parameters": [
3455
+ {
3456
+ "name": "options",
3457
+ "type": "ServiceTimeEntryActionTarget",
3458
+ "optional": false
3459
+ }
3460
+ ],
3461
+ "returnType": "Promise<ServiceTimeEntry>",
3462
+ "isStatic": false,
3463
+ "isPublic": true,
3464
+ "decoratorConfig": {
3465
+ "httpMethod": "POST",
3466
+ "path": "submit",
3467
+ "effect": "write",
3468
+ "idempotent": false,
3469
+ "openWorld": false,
3470
+ "description": "Submit a time entry for approval (service-backed)."
3471
+ }
3472
+ },
3473
+ "approve": {
3474
+ "name": "approve",
3475
+ "async": true,
3476
+ "parameters": [
3477
+ {
3478
+ "name": "options",
3479
+ "type": "ServiceTimeEntryActionTarget",
3480
+ "optional": false
3481
+ }
3482
+ ],
3483
+ "returnType": "Promise<ServiceTimeEntry>",
3484
+ "isStatic": false,
3485
+ "isPublic": true,
3486
+ "decoratorConfig": {
3487
+ "httpMethod": "POST",
3488
+ "path": "approve",
3489
+ "effect": "write",
3490
+ "idempotent": true,
3491
+ "openWorld": false,
3492
+ "description": "Approve a submitted time entry and snapshot its charge and compensation (service-backed)."
3493
+ }
3494
+ },
2261
3495
  "forWork": {
2262
3496
  "name": "forWork",
2263
3497
  "async": true,
@@ -2287,6 +3521,24 @@
2287
3521
  }
2288
3522
  },
2289
3523
  "decoratorConfig": {
3524
+ "api": {
3525
+ "include": [
3526
+ "forWork",
3527
+ "pendingApproval",
3528
+ "record",
3529
+ "submit",
3530
+ "approve"
3531
+ ]
3532
+ },
3533
+ "mcp": {
3534
+ "include": [
3535
+ "list",
3536
+ "get",
3537
+ "forWork",
3538
+ "pendingApproval"
3539
+ ]
3540
+ },
3541
+ "cli": false,
2290
3542
  "tableName": "service_time_entries"
2291
3543
  },
2292
3544
  "extends": "SmrtCollection",
@@ -2584,9 +3836,23 @@
2584
3836
  "_meta": {},
2585
3837
  "enum": [
2586
3838
  "open",
3839
+ "submitted",
2587
3840
  "confirmed"
2588
3841
  ]
2589
3842
  },
3843
+ "submittedAt": {
3844
+ "type": "datetime",
3845
+ "required": false
3846
+ },
3847
+ "submittedByProfileId": {
3848
+ "type": "crossPackageRef",
3849
+ "required": false,
3850
+ "related": "@happyvertical/smrt-profiles:Profile",
3851
+ "_meta": {
3852
+ "nullable": true,
3853
+ "onDelete": "RESTRICT"
3854
+ }
3855
+ },
2590
3856
  "confirmedAt": {
2591
3857
  "type": "datetime",
2592
3858
  "required": false
@@ -2678,7 +3944,7 @@
2678
3944
  ],
2679
3945
  "schema": {
2680
3946
  "tableName": "period_timecards",
2681
- "ddl": "CREATE TABLE IF NOT EXISTS \"period_timecards\" (\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 NOT NULL,\n \"profile_id\" UUID,\n \"starts_at\" TIMESTAMP,\n \"ends_at\" TIMESTAMP,\n \"timezone\" TEXT,\n \"rules_version\" TEXT,\n \"rules_snapshot\" TEXT,\n \"source_snapshot\" TEXT,\n \"regular_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"overtime_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"total_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"status\" TEXT,\n \"confirmed_at\" TIMESTAMP,\n \"confirmed_by_profile_id\" UUID\n);",
3947
+ "ddl": "CREATE TABLE IF NOT EXISTS \"period_timecards\" (\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 NOT NULL,\n \"profile_id\" UUID,\n \"starts_at\" TIMESTAMP,\n \"ends_at\" TIMESTAMP,\n \"timezone\" TEXT,\n \"rules_version\" TEXT,\n \"rules_snapshot\" TEXT,\n \"source_snapshot\" TEXT,\n \"regular_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"overtime_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"total_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"status\" TEXT,\n \"submitted_at\" TIMESTAMP,\n \"submitted_by_profile_id\" UUID,\n \"confirmed_at\" TIMESTAMP,\n \"confirmed_by_profile_id\" UUID\n);",
2682
3948
  "columns": {
2683
3949
  "id": {
2684
3950
  "type": "UUID",
@@ -2770,6 +4036,17 @@
2770
4036
  "notNull": false,
2771
4037
  "unique": false
2772
4038
  },
4039
+ "submitted_at": {
4040
+ "type": "TIMESTAMP",
4041
+ "notNull": false,
4042
+ "unique": false
4043
+ },
4044
+ "submitted_by_profile_id": {
4045
+ "type": "UUID",
4046
+ "referenceKind": "crossPackageRef",
4047
+ "notNull": false,
4048
+ "unique": false
4049
+ },
2773
4050
  "confirmed_at": {
2774
4051
  "type": "TIMESTAMP",
2775
4052
  "notNull": false,
@@ -2805,6 +4082,12 @@
2805
4082
  "profile_id"
2806
4083
  ]
2807
4084
  },
4085
+ {
4086
+ "name": "period_timecards_submitted_by_profile_id_idx",
4087
+ "columns": [
4088
+ "submitted_by_profile_id"
4089
+ ]
4090
+ },
2808
4091
  {
2809
4092
  "name": "period_timecards_confirmed_by_profile_id_idx",
2810
4093
  "columns": [
@@ -2812,7 +4095,7 @@
2812
4095
  ]
2813
4096
  }
2814
4097
  ],
2815
- "version": "8153dc2a"
4098
+ "version": "00299335"
2816
4099
  },
2817
4100
  "importPath": "@happyvertical/smrt-timesheets/rollup"
2818
4101
  },
@@ -2875,17 +4158,276 @@
2875
4158
  "required": true,
2876
4159
  "default": 0
2877
4160
  },
2878
- "overtimeSeconds": {
2879
- "type": "integer",
2880
- "required": true,
2881
- "default": 0
4161
+ "overtimeSeconds": {
4162
+ "type": "integer",
4163
+ "required": true,
4164
+ "default": 0
4165
+ },
4166
+ "reason": {
4167
+ "type": "text",
4168
+ "required": false
4169
+ }
4170
+ },
4171
+ "methods": {
4172
+ "save": {
4173
+ "name": "save",
4174
+ "async": true,
4175
+ "parameters": [],
4176
+ "returnType": "Promise<this>",
4177
+ "isStatic": false,
4178
+ "isPublic": true
4179
+ },
4180
+ "delete": {
4181
+ "name": "delete",
4182
+ "async": true,
4183
+ "parameters": [],
4184
+ "returnType": "Promise<void>",
4185
+ "isStatic": false,
4186
+ "isPublic": true
4187
+ }
4188
+ },
4189
+ "decoratorConfig": {
4190
+ "tableName": "timecard_adjustments",
4191
+ "sensitive": true,
4192
+ "api": {
4193
+ "include": []
4194
+ },
4195
+ "cli": {
4196
+ "include": []
4197
+ },
4198
+ "mcp": {
4199
+ "include": []
4200
+ },
4201
+ "tenantScoped": {
4202
+ "mode": "required"
4203
+ },
4204
+ "conflictColumns": [
4205
+ "tenant_id",
4206
+ "slug",
4207
+ "context"
4208
+ ]
4209
+ },
4210
+ "extends": "SmrtObject",
4211
+ "exportName": "TimecardAdjustment",
4212
+ "collectionExportName": "TimecardAdjustmentCollection",
4213
+ "validationRules": [
4214
+ {
4215
+ "field": "regularSeconds",
4216
+ "rule": "required",
4217
+ "fieldType": "integer"
4218
+ },
4219
+ {
4220
+ "field": "overtimeSeconds",
4221
+ "rule": "required",
4222
+ "fieldType": "integer"
4223
+ }
4224
+ ],
4225
+ "schema": {
4226
+ "tableName": "timecard_adjustments",
4227
+ "ddl": "CREATE TABLE IF NOT EXISTS \"timecard_adjustments\" (\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 NOT NULL,\n \"timecard_id\" UUID,\n \"profile_id\" UUID,\n \"actor_profile_id\" UUID,\n \"operation_id\" TEXT,\n \"regular_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"overtime_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"reason\" TEXT\n);",
4228
+ "columns": {
4229
+ "id": {
4230
+ "type": "UUID",
4231
+ "primaryKey": true,
4232
+ "referenceKind": "id",
4233
+ "notNull": true
4234
+ },
4235
+ "slug": {
4236
+ "type": "TEXT",
4237
+ "notNull": true
4238
+ },
4239
+ "context": {
4240
+ "type": "TEXT",
4241
+ "notNull": true,
4242
+ "default": ""
4243
+ },
4244
+ "created_at": {
4245
+ "type": "TIMESTAMP",
4246
+ "notNull": true,
4247
+ "default": "current_timestamp"
4248
+ },
4249
+ "updated_at": {
4250
+ "type": "TIMESTAMP",
4251
+ "notNull": true,
4252
+ "default": "current_timestamp"
4253
+ },
4254
+ "tenant_id": {
4255
+ "type": "UUID",
4256
+ "referenceKind": "tenantId",
4257
+ "notNull": true,
4258
+ "unique": false
4259
+ },
4260
+ "timecard_id": {
4261
+ "type": "UUID",
4262
+ "referenceKind": "foreignKey",
4263
+ "notNull": false,
4264
+ "unique": false,
4265
+ "foreignKey": {
4266
+ "table": "period_timecards",
4267
+ "column": "id",
4268
+ "onDelete": "RESTRICT",
4269
+ "onUpdate": "CASCADE"
4270
+ }
4271
+ },
4272
+ "profile_id": {
4273
+ "type": "UUID",
4274
+ "referenceKind": "crossPackageRef",
4275
+ "notNull": false,
4276
+ "unique": false
4277
+ },
4278
+ "actor_profile_id": {
4279
+ "type": "UUID",
4280
+ "referenceKind": "crossPackageRef",
4281
+ "notNull": false,
4282
+ "unique": false
4283
+ },
4284
+ "operation_id": {
4285
+ "type": "TEXT",
4286
+ "notNull": false,
4287
+ "unique": false
4288
+ },
4289
+ "regular_seconds": {
4290
+ "type": "INTEGER",
4291
+ "notNull": true,
4292
+ "unique": false,
4293
+ "default": 0
4294
+ },
4295
+ "overtime_seconds": {
4296
+ "type": "INTEGER",
4297
+ "notNull": true,
4298
+ "unique": false,
4299
+ "default": 0
4300
+ },
4301
+ "reason": {
4302
+ "type": "TEXT",
4303
+ "notNull": false,
4304
+ "unique": false
4305
+ }
4306
+ },
4307
+ "indexes": [
4308
+ {
4309
+ "name": "timecard_adjustments_slug_context_idx",
4310
+ "columns": [
4311
+ "tenant_id",
4312
+ "slug",
4313
+ "context"
4314
+ ],
4315
+ "unique": true
4316
+ },
4317
+ {
4318
+ "name": "timecard_adjustments_tenant_id_created_at_idx",
4319
+ "columns": [
4320
+ "tenant_id",
4321
+ "created_at"
4322
+ ]
4323
+ },
4324
+ {
4325
+ "name": "timecard_adjustments_timecard_id_idx",
4326
+ "columns": [
4327
+ "timecard_id"
4328
+ ]
4329
+ },
4330
+ {
4331
+ "name": "timecard_adjustments_profile_id_idx",
4332
+ "columns": [
4333
+ "profile_id"
4334
+ ]
4335
+ },
4336
+ {
4337
+ "name": "timecard_adjustments_actor_profile_id_idx",
4338
+ "columns": [
4339
+ "actor_profile_id"
4340
+ ]
4341
+ }
4342
+ ],
4343
+ "version": "582afe16"
4344
+ },
4345
+ "importPath": "@happyvertical/smrt-timesheets/rollup"
4346
+ },
4347
+ "@happyvertical/smrt-timesheets:TimecardReopening": {
4348
+ "name": "timecardreopening",
4349
+ "className": "TimecardReopening",
4350
+ "qualifiedName": "@happyvertical/smrt-timesheets:TimecardReopening",
4351
+ "collection": "timecardreopenings",
4352
+ "description": "Append-only audit row for one reopening of a submitted or confirmed card: who reopened whose period, why, and the totals it had at that moment (base, adjustments and effective, in integer seconds).",
4353
+ "filePath": "/home/runner/work/smrt/smrt/packages/timesheets/src/rollup/models.ts",
4354
+ "packageName": "@happyvertical/smrt-timesheets",
4355
+ "fields": {
4356
+ "tenantId": {
4357
+ "type": "text",
4358
+ "required": true,
4359
+ "_meta": {
4360
+ "sqlType": "UUID",
4361
+ "__tenancy": {
4362
+ "isTenantIdField": true,
4363
+ "autoFilter": true,
4364
+ "required": true,
4365
+ "autoPopulate": true,
4366
+ "nullable": false,
4367
+ "mode": "required",
4368
+ "field": "tenantId",
4369
+ "allowSuperAdminBypass": false
4370
+ }
4371
+ }
4372
+ },
4373
+ "timecardId": {
4374
+ "type": "foreignKey",
4375
+ "required": false,
4376
+ "related": "PeriodTimecard",
4377
+ "_meta": {
4378
+ "onDelete": "RESTRICT"
4379
+ }
4380
+ },
4381
+ "profileId": {
4382
+ "type": "crossPackageRef",
4383
+ "required": false,
4384
+ "related": "@happyvertical/smrt-profiles:Profile",
4385
+ "_meta": {
4386
+ "onDelete": "RESTRICT"
4387
+ }
4388
+ },
4389
+ "actorProfileId": {
4390
+ "type": "crossPackageRef",
4391
+ "required": false,
4392
+ "related": "@happyvertical/smrt-profiles:Profile",
4393
+ "_meta": {
4394
+ "onDelete": "RESTRICT"
4395
+ }
4396
+ },
4397
+ "operationId": {
4398
+ "type": "text",
4399
+ "required": false
4400
+ },
4401
+ "fromStatus": {
4402
+ "type": "text",
4403
+ "required": false,
4404
+ "_meta": {},
4405
+ "enum": [
4406
+ "open",
4407
+ "submitted",
4408
+ "confirmed"
4409
+ ]
2882
4410
  },
2883
4411
  "reason": {
2884
4412
  "type": "text",
2885
- "required": false
4413
+ "required": false,
4414
+ "_meta": {}
4415
+ },
4416
+ "previousState": {
4417
+ "type": "text",
4418
+ "required": false,
4419
+ "_meta": {}
2886
4420
  }
2887
4421
  },
2888
4422
  "methods": {
4423
+ "getPrevious": {
4424
+ "name": "getPrevious",
4425
+ "async": false,
4426
+ "parameters": [],
4427
+ "returnType": "T",
4428
+ "isStatic": false,
4429
+ "isPublic": true
4430
+ },
2889
4431
  "save": {
2890
4432
  "name": "save",
2891
4433
  "async": true,
@@ -2904,8 +4446,17 @@
2904
4446
  }
2905
4447
  },
2906
4448
  "decoratorConfig": {
2907
- "tableName": "timecard_adjustments",
4449
+ "tableName": "timecard_reopenings",
2908
4450
  "sensitive": true,
4451
+ "indexes": [
4452
+ {
4453
+ "name": "timecard_reopenings_card_idx",
4454
+ "columns": [
4455
+ "tenantId",
4456
+ "timecardId"
4457
+ ]
4458
+ }
4459
+ ],
2909
4460
  "api": {
2910
4461
  "include": []
2911
4462
  },
@@ -2925,23 +4476,12 @@
2925
4476
  ]
2926
4477
  },
2927
4478
  "extends": "SmrtObject",
2928
- "exportName": "TimecardAdjustment",
2929
- "collectionExportName": "TimecardAdjustmentCollection",
2930
- "validationRules": [
2931
- {
2932
- "field": "regularSeconds",
2933
- "rule": "required",
2934
- "fieldType": "integer"
2935
- },
2936
- {
2937
- "field": "overtimeSeconds",
2938
- "rule": "required",
2939
- "fieldType": "integer"
2940
- }
2941
- ],
4479
+ "exportName": "TimecardReopening",
4480
+ "collectionExportName": "TimecardReopeningCollection",
4481
+ "validationRules": [],
2942
4482
  "schema": {
2943
- "tableName": "timecard_adjustments",
2944
- "ddl": "CREATE TABLE IF NOT EXISTS \"timecard_adjustments\" (\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 NOT NULL,\n \"timecard_id\" UUID,\n \"profile_id\" UUID,\n \"actor_profile_id\" UUID,\n \"operation_id\" TEXT,\n \"regular_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"overtime_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"reason\" TEXT\n);",
4483
+ "tableName": "timecard_reopenings",
4484
+ "ddl": "CREATE TABLE IF NOT EXISTS \"timecard_reopenings\" (\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 NOT NULL,\n \"timecard_id\" UUID,\n \"profile_id\" UUID,\n \"actor_profile_id\" UUID,\n \"operation_id\" TEXT,\n \"from_status\" TEXT,\n \"reason\" TEXT,\n \"previous_state\" TEXT\n);",
2945
4485
  "columns": {
2946
4486
  "id": {
2947
4487
  "type": "UUID",
@@ -3003,27 +4543,25 @@
3003
4543
  "notNull": false,
3004
4544
  "unique": false
3005
4545
  },
3006
- "regular_seconds": {
3007
- "type": "INTEGER",
3008
- "notNull": true,
3009
- "unique": false,
3010
- "default": 0
3011
- },
3012
- "overtime_seconds": {
3013
- "type": "INTEGER",
3014
- "notNull": true,
3015
- "unique": false,
3016
- "default": 0
4546
+ "from_status": {
4547
+ "type": "TEXT",
4548
+ "notNull": false,
4549
+ "unique": false
3017
4550
  },
3018
4551
  "reason": {
3019
4552
  "type": "TEXT",
3020
4553
  "notNull": false,
3021
4554
  "unique": false
4555
+ },
4556
+ "previous_state": {
4557
+ "type": "TEXT",
4558
+ "notNull": false,
4559
+ "unique": false
3022
4560
  }
3023
4561
  },
3024
4562
  "indexes": [
3025
4563
  {
3026
- "name": "timecard_adjustments_slug_context_idx",
4564
+ "name": "timecard_reopenings_slug_context_idx",
3027
4565
  "columns": [
3028
4566
  "tenant_id",
3029
4567
  "slug",
@@ -3032,32 +4570,39 @@
3032
4570
  "unique": true
3033
4571
  },
3034
4572
  {
3035
- "name": "timecard_adjustments_tenant_id_created_at_idx",
4573
+ "name": "timecard_reopenings_card_idx",
4574
+ "columns": [
4575
+ "tenant_id",
4576
+ "timecard_id"
4577
+ ]
4578
+ },
4579
+ {
4580
+ "name": "timecard_reopenings_tenant_id_created_at_idx",
3036
4581
  "columns": [
3037
4582
  "tenant_id",
3038
4583
  "created_at"
3039
4584
  ]
3040
4585
  },
3041
4586
  {
3042
- "name": "timecard_adjustments_timecard_id_idx",
4587
+ "name": "timecard_reopenings_timecard_id_idx",
3043
4588
  "columns": [
3044
4589
  "timecard_id"
3045
4590
  ]
3046
4591
  },
3047
4592
  {
3048
- "name": "timecard_adjustments_profile_id_idx",
4593
+ "name": "timecard_reopenings_profile_id_idx",
3049
4594
  "columns": [
3050
4595
  "profile_id"
3051
4596
  ]
3052
4597
  },
3053
4598
  {
3054
- "name": "timecard_adjustments_actor_profile_id_idx",
4599
+ "name": "timecard_reopenings_actor_profile_id_idx",
3055
4600
  "columns": [
3056
4601
  "actor_profile_id"
3057
4602
  ]
3058
4603
  }
3059
4604
  ],
3060
- "version": "582afe16"
4605
+ "version": "0498ec40"
3061
4606
  },
3062
4607
  "importPath": "@happyvertical/smrt-timesheets/rollup"
3063
4608
  },
@@ -3080,7 +4625,7 @@
3080
4625
  "collectionExportName": "PeriodTimecardCollectionCollection",
3081
4626
  "schema": {
3082
4627
  "tableName": "period_timecards",
3083
- "ddl": "CREATE TABLE IF NOT EXISTS \"period_timecards\" (\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 NOT NULL,\n \"profile_id\" UUID,\n \"starts_at\" TIMESTAMP,\n \"ends_at\" TIMESTAMP,\n \"timezone\" TEXT,\n \"rules_version\" TEXT,\n \"rules_snapshot\" TEXT,\n \"source_snapshot\" TEXT,\n \"regular_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"overtime_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"total_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"status\" TEXT,\n \"confirmed_at\" TIMESTAMP,\n \"confirmed_by_profile_id\" UUID\n);",
4628
+ "ddl": "CREATE TABLE IF NOT EXISTS \"period_timecards\" (\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 NOT NULL,\n \"profile_id\" UUID,\n \"starts_at\" TIMESTAMP,\n \"ends_at\" TIMESTAMP,\n \"timezone\" TEXT,\n \"rules_version\" TEXT,\n \"rules_snapshot\" TEXT,\n \"source_snapshot\" TEXT,\n \"regular_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"overtime_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"total_seconds\" INTEGER NOT NULL DEFAULT 0,\n \"status\" TEXT,\n \"submitted_at\" TIMESTAMP,\n \"submitted_by_profile_id\" UUID,\n \"confirmed_at\" TIMESTAMP,\n \"confirmed_by_profile_id\" UUID\n);",
3084
4629
  "columns": {
3085
4630
  "id": {
3086
4631
  "type": "UUID",
@@ -3172,6 +4717,17 @@
3172
4717
  "notNull": false,
3173
4718
  "unique": false
3174
4719
  },
4720
+ "submitted_at": {
4721
+ "type": "TIMESTAMP",
4722
+ "notNull": false,
4723
+ "unique": false
4724
+ },
4725
+ "submitted_by_profile_id": {
4726
+ "type": "UUID",
4727
+ "referenceKind": "crossPackageRef",
4728
+ "notNull": false,
4729
+ "unique": false
4730
+ },
3175
4731
  "confirmed_at": {
3176
4732
  "type": "TIMESTAMP",
3177
4733
  "notNull": false,
@@ -3207,6 +4763,12 @@
3207
4763
  "profile_id"
3208
4764
  ]
3209
4765
  },
4766
+ {
4767
+ "name": "period_timecards_submitted_by_profile_id_idx",
4768
+ "columns": [
4769
+ "submitted_by_profile_id"
4770
+ ]
4771
+ },
3210
4772
  {
3211
4773
  "name": "period_timecards_confirmed_by_profile_id_idx",
3212
4774
  "columns": [
@@ -3214,7 +4776,7 @@
3214
4776
  ]
3215
4777
  }
3216
4778
  ],
3217
- "version": "8153dc2a"
4779
+ "version": "00299335"
3218
4780
  },
3219
4781
  "importPath": "@happyvertical/smrt-timesheets/rollup"
3220
4782
  },
@@ -3356,21 +4918,311 @@
3356
4918
  "version": "582afe16"
3357
4919
  },
3358
4920
  "importPath": "@happyvertical/smrt-timesheets/rollup"
4921
+ },
4922
+ "@happyvertical/smrt-timesheets:TimecardReopeningCollection": {
4923
+ "name": "timecardreopeningcollection",
4924
+ "className": "TimecardReopeningCollection",
4925
+ "qualifiedName": "@happyvertical/smrt-timesheets:TimecardReopeningCollection",
4926
+ "collection": "timecardreopenings",
4927
+ "description": "Scoped append-only reopening ledger.",
4928
+ "filePath": "/home/runner/work/smrt/smrt/packages/timesheets/src/rollup/models.ts",
4929
+ "packageName": "@happyvertical/smrt-timesheets",
4930
+ "fields": {},
4931
+ "methods": {},
4932
+ "decoratorConfig": {
4933
+ "tableName": "timecard_reopenings"
4934
+ },
4935
+ "extends": "SmrtCollection",
4936
+ "extendsTypeArg": "TimecardReopening",
4937
+ "exportName": "TimecardReopeningCollection",
4938
+ "collectionExportName": "TimecardReopeningCollectionCollection",
4939
+ "schema": {
4940
+ "tableName": "timecard_reopenings",
4941
+ "ddl": "CREATE TABLE IF NOT EXISTS \"timecard_reopenings\" (\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 NOT NULL,\n \"timecard_id\" UUID,\n \"profile_id\" UUID,\n \"actor_profile_id\" UUID,\n \"operation_id\" TEXT,\n \"from_status\" TEXT,\n \"reason\" TEXT,\n \"previous_state\" TEXT\n);",
4942
+ "columns": {
4943
+ "id": {
4944
+ "type": "UUID",
4945
+ "primaryKey": true,
4946
+ "referenceKind": "id",
4947
+ "notNull": true
4948
+ },
4949
+ "slug": {
4950
+ "type": "TEXT",
4951
+ "notNull": true
4952
+ },
4953
+ "context": {
4954
+ "type": "TEXT",
4955
+ "notNull": true,
4956
+ "default": ""
4957
+ },
4958
+ "created_at": {
4959
+ "type": "TIMESTAMP",
4960
+ "notNull": true,
4961
+ "default": "current_timestamp"
4962
+ },
4963
+ "updated_at": {
4964
+ "type": "TIMESTAMP",
4965
+ "notNull": true,
4966
+ "default": "current_timestamp"
4967
+ },
4968
+ "tenant_id": {
4969
+ "type": "UUID",
4970
+ "referenceKind": "tenantId",
4971
+ "notNull": true,
4972
+ "unique": false
4973
+ },
4974
+ "timecard_id": {
4975
+ "type": "UUID",
4976
+ "referenceKind": "foreignKey",
4977
+ "notNull": false,
4978
+ "unique": false,
4979
+ "foreignKey": {
4980
+ "table": "period_timecards",
4981
+ "column": "id",
4982
+ "onDelete": "RESTRICT",
4983
+ "onUpdate": "CASCADE"
4984
+ }
4985
+ },
4986
+ "profile_id": {
4987
+ "type": "UUID",
4988
+ "referenceKind": "crossPackageRef",
4989
+ "notNull": false,
4990
+ "unique": false
4991
+ },
4992
+ "actor_profile_id": {
4993
+ "type": "UUID",
4994
+ "referenceKind": "crossPackageRef",
4995
+ "notNull": false,
4996
+ "unique": false
4997
+ },
4998
+ "operation_id": {
4999
+ "type": "TEXT",
5000
+ "notNull": false,
5001
+ "unique": false
5002
+ },
5003
+ "from_status": {
5004
+ "type": "TEXT",
5005
+ "notNull": false,
5006
+ "unique": false
5007
+ },
5008
+ "reason": {
5009
+ "type": "TEXT",
5010
+ "notNull": false,
5011
+ "unique": false
5012
+ },
5013
+ "previous_state": {
5014
+ "type": "TEXT",
5015
+ "notNull": false,
5016
+ "unique": false
5017
+ }
5018
+ },
5019
+ "indexes": [
5020
+ {
5021
+ "name": "timecard_reopenings_slug_context_idx",
5022
+ "columns": [
5023
+ "tenant_id",
5024
+ "slug",
5025
+ "context"
5026
+ ],
5027
+ "unique": true
5028
+ },
5029
+ {
5030
+ "name": "timecard_reopenings_card_idx",
5031
+ "columns": [
5032
+ "tenant_id",
5033
+ "timecard_id"
5034
+ ]
5035
+ },
5036
+ {
5037
+ "name": "timecard_reopenings_tenant_id_created_at_idx",
5038
+ "columns": [
5039
+ "tenant_id",
5040
+ "created_at"
5041
+ ]
5042
+ },
5043
+ {
5044
+ "name": "timecard_reopenings_timecard_id_idx",
5045
+ "columns": [
5046
+ "timecard_id"
5047
+ ]
5048
+ },
5049
+ {
5050
+ "name": "timecard_reopenings_profile_id_idx",
5051
+ "columns": [
5052
+ "profile_id"
5053
+ ]
5054
+ },
5055
+ {
5056
+ "name": "timecard_reopenings_actor_profile_id_idx",
5057
+ "columns": [
5058
+ "actor_profile_id"
5059
+ ]
5060
+ }
5061
+ ],
5062
+ "version": "0498ec40"
5063
+ },
5064
+ "importPath": "@happyvertical/smrt-timesheets/rollup"
3359
5065
  }
3360
5066
  },
3361
5067
  "moduleType": "smrt",
5068
+ "recipes": [
5069
+ {
5070
+ "id": "timesheets.time-entries",
5071
+ "className": "TimeEntriesRecipe",
5072
+ "label": "Time entries",
5073
+ "summary": "Record who worked how long on what, for approval.",
5074
+ "synonyms": [
5075
+ "timesheets",
5076
+ "time tracking",
5077
+ "hours",
5078
+ "billable hours",
5079
+ "timecards"
5080
+ ],
5081
+ "models": [
5082
+ "@happyvertical/smrt-timesheets:ServiceTimeEntry"
5083
+ ],
5084
+ "nav": [
5085
+ {
5086
+ "label": "Time entries",
5087
+ "model": "@happyvertical/smrt-timesheets:ServiceTimeEntry",
5088
+ "icon": "fileText",
5089
+ "description": "Hours worked, by person and by job, from draft to approved."
5090
+ }
5091
+ ],
5092
+ "requires": [],
5093
+ "section": {
5094
+ "id": "work",
5095
+ "label": "Work",
5096
+ "icon": "wrench",
5097
+ "description": "Time and costs: the work behind each job."
5098
+ },
5099
+ "options": {
5100
+ "@happyvertical/smrt-timesheets:ServiceTimeEntry": {
5101
+ "fields": {
5102
+ "participantProfileId": {
5103
+ "label": "Person",
5104
+ "order": 1
5105
+ },
5106
+ "description": {
5107
+ "order": 2,
5108
+ "help": "What the time was spent on, in a few words."
5109
+ },
5110
+ "startedAt": {
5111
+ "label": "Started",
5112
+ "order": 3
5113
+ },
5114
+ "endedAt": {
5115
+ "label": "Ended",
5116
+ "order": 4
5117
+ },
5118
+ "durationSeconds": {
5119
+ "label": "Duration (seconds)",
5120
+ "order": 5,
5121
+ "help": "Whole seconds: 3600 is one hour."
5122
+ },
5123
+ "workRefId": {
5124
+ "label": "Work reference",
5125
+ "order": 6,
5126
+ "help": "The job, project or case this time belongs to."
5127
+ },
5128
+ "workRefType": {
5129
+ "visibility": "hidden"
5130
+ },
5131
+ "participantKind": {
5132
+ "default": "human",
5133
+ "visibility": "hidden"
5134
+ },
5135
+ "agentRef": {
5136
+ "visibility": "hidden"
5137
+ },
5138
+ "source": {
5139
+ "default": "manual",
5140
+ "visibility": "hidden"
5141
+ },
5142
+ "evidence": {
5143
+ "visibility": "hidden"
5144
+ },
5145
+ "status": {
5146
+ "visibility": "hidden",
5147
+ "locked": true
5148
+ },
5149
+ "submittedAt": {
5150
+ "visibility": "hidden",
5151
+ "locked": true
5152
+ },
5153
+ "submittedByProfileId": {
5154
+ "visibility": "hidden",
5155
+ "locked": true
5156
+ },
5157
+ "approvedAt": {
5158
+ "visibility": "hidden",
5159
+ "locked": true
5160
+ },
5161
+ "approvedByProfileId": {
5162
+ "visibility": "hidden",
5163
+ "locked": true
5164
+ },
5165
+ "approvalPath": {
5166
+ "visibility": "hidden",
5167
+ "locked": true
5168
+ },
5169
+ "rejectedAt": {
5170
+ "visibility": "hidden",
5171
+ "locked": true
5172
+ },
5173
+ "rejectedByProfileId": {
5174
+ "visibility": "hidden",
5175
+ "locked": true
5176
+ },
5177
+ "rejectionReason": {
5178
+ "visibility": "hidden",
5179
+ "locked": true
5180
+ },
5181
+ "correctionOfId": {
5182
+ "visibility": "hidden",
5183
+ "locked": true
5184
+ },
5185
+ "metadata": {
5186
+ "visibility": "hidden"
5187
+ }
5188
+ }
5189
+ }
5190
+ },
5191
+ "help": {
5192
+ "markdown": "## Overview\n\nTime entries record who worked how long on what. Each entry names the person,\nwhat they did and when, and moves from draft to submitted to approved.\n\n## Tasks\n\n### Record time\n\n1. Create a new time entry.\n2. Pick the **{field:participantProfileId}** who did the work.\n3. Write a short **{field:description}** of what was done.\n4. Enter when it **{field:startedAt}** and **{field:endedAt}**, or type the\n **{field:durationSeconds}** directly (3600 is one hour).\n\n### Send it for approval\n\nApproval is not something you change on this form. It runs through your\napp's approval screen, which records who did each step and when.\n\n1. When an entry is ready to check, the person who did the work submits it.\n2. An approver, someone your app allows to approve time, approves it or sends\n it back with a reason. Approving fixes what the hours are charged and paid\n at, so an approved entry never changes; correct it with a new entry.\n3. If your app has no approval screen yet, entries stay as drafts until one is\n added.\n",
5193
+ "fieldRefs": [
5194
+ "description",
5195
+ "durationSeconds",
5196
+ "endedAt",
5197
+ "participantProfileId",
5198
+ "startedAt"
5199
+ ]
5200
+ },
5201
+ "demo": {
5202
+ "mode": "server",
5203
+ "reasons": [
5204
+ "Needs a server because its package does not build for a browser: node:crypto; and its package depends on @happyvertical/smrt-profiles, @happyvertical/smrt-tenancy, @happyvertical/smrt-users, which do not build for a browser (#3617, #3624, #3626)."
5205
+ ]
5206
+ }
5207
+ }
5208
+ ],
3362
5209
  "smrtDependencies": [
3363
5210
  "@happyvertical/smrt-core",
3364
- "@happyvertical/smrt-tenancy"
5211
+ "@happyvertical/smrt-tenancy",
5212
+ "@happyvertical/smrt-users"
3365
5213
  ],
3366
5214
  "browser": {
3367
5215
  "status": "server-only",
3368
5216
  "issues": [
3369
- "#3624"
5217
+ "#3617",
5218
+ "#3624",
5219
+ "#3626"
3370
5220
  ],
3371
5221
  "reason": "node:crypto",
3372
5222
  "via": [
3373
- "@happyvertical/smrt-tenancy"
5223
+ "@happyvertical/smrt-profiles",
5224
+ "@happyvertical/smrt-tenancy",
5225
+ "@happyvertical/smrt-users"
3374
5226
  ]
3375
5227
  },
3376
5228
  "stampsConstructors": true