@happyvertical/smrt-timesheets 0.53.1 → 0.53.3

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 (46) hide show
  1. package/AGENTS.md +32 -21
  2. package/README.md +124 -58
  3. package/agents/period-rollup.md +130 -0
  4. package/dist/attendance/models.d.ts +59 -0
  5. package/dist/attendance/models.d.ts.map +1 -0
  6. package/dist/attendance/service.d.ts +64 -0
  7. package/dist/attendance/service.d.ts.map +1 -0
  8. package/dist/attendance.d.ts +5 -0
  9. package/dist/attendance.d.ts.map +1 -0
  10. package/dist/attendance.js +323 -0
  11. package/dist/attendance.js.map +1 -0
  12. package/dist/chunks/attendance-Dg_5VkMj.js +60 -0
  13. package/dist/chunks/attendance-Dg_5VkMj.js.map +1 -0
  14. package/dist/chunks/models-DRj8BOuG.js +166 -0
  15. package/dist/chunks/models-DRj8BOuG.js.map +1 -0
  16. package/dist/chunks/rollup-C_dHTdJs.js +425 -0
  17. package/dist/chunks/rollup-C_dHTdJs.js.map +1 -0
  18. package/dist/chunks/service-time-entry-BeOsL7Uv.js +190 -0
  19. package/dist/chunks/service-time-entry-BeOsL7Uv.js.map +1 -0
  20. package/dist/index.d.ts +2 -0
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +25 -205
  23. package/dist/index.js.map +1 -1
  24. package/dist/manifest.json +2553 -652
  25. package/dist/rollup/attendance.d.ts +8 -0
  26. package/dist/rollup/attendance.d.ts.map +1 -0
  27. package/dist/rollup/calculation.d.ts +7 -0
  28. package/dist/rollup/calculation.d.ts.map +1 -0
  29. package/dist/rollup/models.d.ts +47 -0
  30. package/dist/rollup/models.d.ts.map +1 -0
  31. package/dist/rollup/service.d.ts +37 -0
  32. package/dist/rollup/service.d.ts.map +1 -0
  33. package/dist/rollup/types.d.ts +38 -0
  34. package/dist/rollup/types.d.ts.map +1 -0
  35. package/dist/rollup/write.d.ts +4 -0
  36. package/dist/rollup/write.d.ts.map +1 -0
  37. package/dist/rollup.d.ts +5 -0
  38. package/dist/rollup.d.ts.map +1 -0
  39. package/dist/rollup.js +2 -0
  40. package/dist/smrt-knowledge.json +1319 -433
  41. package/package.json +19 -10
  42. package/dist/svelte/components/__tests__/DurationDisplay.test.js +0 -57
  43. package/dist/svelte/components/__tests__/TimeEntryApprovalQueue.test.js +0 -114
  44. package/dist/svelte/components/__tests__/TimeEntryCard.test.js +0 -45
  45. package/dist/svelte/components/__tests__/TimeEntryList.test.js +0 -50
  46. package/dist/svelte/components/__tests__/TimeSummary.test.js +0 -39
@@ -3,18 +3,21 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-timesheets",
6
- "packageVersion": "0.53.1",
6
+ "packageVersion": "0.53.3",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "52dc7207ce4f40ef17360ef2956cb519741830f57b744640bc1a5c2084993164",
11
- "packageJson": "3b966965edaa33570f9c7cc9015766eff72113decda22001c779f5c546e095bc",
12
- "agents": "a6b055ef3df46c1dc653d96c8fc5983f223fbfcfd9a6b3c5be8382068c515096"
10
+ "manifest": "d61b7ce978a0467d489c8f87487cf7e2d6a7859e9f8d9824d6d204a3fb1a8dd1",
11
+ "packageJson": "a52a56bdab00ac2e1da8e3a8c02db1c97fd63869ec07db53eaba264845cf0c39",
12
+ "agents": "21421ad5f02335e4c994227122c13b881d10e9f9d55ae09c3ac8ffa4bc2a7e09",
13
+ "moduleDoc:agents/period-rollup.md": "0c28783f8911c20911a2c640e89f2190df886d86749b5b03219afea4c83ab75d"
13
14
  },
14
15
  "exports": [
15
16
  ".",
17
+ "./attendance",
16
18
  "./manifest",
17
19
  "./manifest.json",
20
+ "./rollup",
18
21
  "./svelte",
19
22
  "./ui"
20
23
  ],
@@ -23,8 +26,8 @@
23
26
  "@happyvertical/smrt-tenancy": "workspace:*",
24
27
  "@happyvertical/smrt-types": "workspace:*",
25
28
  "@happyvertical/smrt-ui": "workspace:*",
26
- "@happyvertical/smrt-vitest": "workspace:*",
27
29
  "@happyvertical/sql": "catalog:",
30
+ "@happyvertical/smrt-vitest": "workspace:*",
28
31
  "@sveltejs/package": "^2.5.8",
29
32
  "@sveltejs/vite-plugin-svelte": "^7.3.0",
30
33
  "@types/node": "24.13.6",
@@ -54,97 +57,105 @@
54
57
  "timesheets"
55
58
  ],
56
59
  "risks": [
57
- "cross-package-refs:4",
60
+ "cross-package-refs:9",
58
61
  "sensitive-fields-excluded"
59
62
  ],
60
63
  "objects": [
61
64
  {
62
- "name": "ServiceChargeSnapshot",
63
- "qualifiedName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot",
64
- "previousQualifiedNames": [
65
- "@happyvertical/smrt-projects:ServiceChargeSnapshot"
66
- ],
67
- "collection": "servicechargesnapshots",
68
- "tableName": "service_charge_snapshots",
65
+ "name": "AttendancePunch",
66
+ "qualifiedName": "@happyvertical/smrt-timesheets:AttendancePunch",
67
+ "collection": "attendancepunches",
68
+ "tableName": "attendance_punches",
69
69
  "packageName": "@happyvertical/smrt-timesheets",
70
70
  "extends": "SmrtObject",
71
71
  "fields": [
72
72
  {
73
73
  "name": "tenantId",
74
74
  "type": "text",
75
- "required": false,
75
+ "required": true,
76
76
  "columnType": "UUID"
77
77
  },
78
78
  {
79
- "name": "timeEntryId",
80
- "type": "foreignKey",
81
- "required": true,
82
- "related": "ServiceTimeEntry",
79
+ "name": "profileId",
80
+ "type": "crossPackageRef",
81
+ "required": false,
82
+ "related": "@happyvertical/smrt-profiles:Profile",
83
83
  "columnType": "UUID"
84
84
  },
85
85
  {
86
- "name": "amount",
87
- "type": "integer",
86
+ "name": "startedAt",
87
+ "type": "datetime",
88
+ "required": false,
89
+ "columnType": "TIMESTAMP"
90
+ },
91
+ {
92
+ "name": "endedAt",
93
+ "type": "datetime",
88
94
  "required": false,
95
+ "columnType": "TIMESTAMP"
96
+ },
97
+ {
98
+ "name": "durationSeconds",
99
+ "type": "integer",
100
+ "required": true,
89
101
  "columnType": "INTEGER",
90
102
  "default": 0
91
103
  },
92
104
  {
93
- "name": "currency",
94
- "type": "text",
95
- "required": false,
96
- "columnType": "TEXT"
105
+ "name": "unpaidBreakSeconds",
106
+ "type": "integer",
107
+ "required": true,
108
+ "columnType": "INTEGER",
109
+ "default": 0
97
110
  },
98
111
  {
99
- "name": "pricingVersion",
100
- "type": "text",
101
- "required": false,
102
- "columnType": "TEXT"
112
+ "name": "reviewRequired",
113
+ "type": "boolean",
114
+ "required": true,
115
+ "columnType": "BOOLEAN",
116
+ "default": false
103
117
  },
104
118
  {
105
- "name": "strategy",
106
- "type": "text",
107
- "required": false,
108
- "columnType": "TEXT"
119
+ "name": "recordedOffline",
120
+ "type": "boolean",
121
+ "required": true,
122
+ "columnType": "BOOLEAN",
123
+ "default": false
109
124
  },
110
125
  {
111
- "name": "rateSnapshot",
112
- "type": "text",
126
+ "name": "serviceTimeEntryId",
127
+ "type": "foreignKey",
113
128
  "required": false,
114
- "columnType": "TEXT"
129
+ "related": "ServiceTimeEntry",
130
+ "columnType": "UUID"
115
131
  },
116
132
  {
117
- "name": "sourceChargeRef",
133
+ "name": "openSlot",
118
134
  "type": "text",
119
- "required": false,
135
+ "required": true,
120
136
  "columnType": "TEXT"
121
- },
122
- {
123
- "name": "createdAt",
124
- "type": "datetime",
125
- "required": false,
126
- "columnType": "TIMESTAMP"
127
137
  }
128
138
  ],
129
139
  "relationships": [
130
140
  {
131
- "name": "timeEntryId",
141
+ "name": "profileId",
142
+ "type": "crossPackageRef",
143
+ "required": false,
144
+ "related": "@happyvertical/smrt-profiles:Profile",
145
+ "columnType": "UUID"
146
+ },
147
+ {
148
+ "name": "serviceTimeEntryId",
132
149
  "type": "foreignKey",
133
- "required": true,
150
+ "required": false,
134
151
  "related": "ServiceTimeEntry",
135
152
  "columnType": "UUID"
136
153
  }
137
154
  ],
138
155
  "methods": [
139
- "initialize",
140
156
  "save"
141
157
  ],
142
158
  "methodSignatures": [
143
- {
144
- "name": "initialize",
145
- "async": true,
146
- "returns": "Promise<this>"
147
- },
148
159
  {
149
160
  "name": "save",
150
161
  "async": true,
@@ -153,71 +164,67 @@
153
164
  ],
154
165
  "tenant": {
155
166
  "scoped": true,
156
- "mode": "optional",
167
+ "mode": "required",
157
168
  "field": "tenantId"
158
169
  },
159
170
  "conflictColumns": [
160
- "time_entry_id"
171
+ "tenant_id",
172
+ "slug",
173
+ "context"
161
174
  ],
162
175
  "surfaces": [
163
176
  {
164
177
  "kind": "api",
165
- "name": "servicechargesnapshots.list",
178
+ "name": "attendancepunches.list",
166
179
  "operation": "list",
167
- "objectName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot",
168
- "path": "/servicechargesnapshots",
180
+ "objectName": "@happyvertical/smrt-timesheets:AttendancePunch",
181
+ "path": "/attendancepunches",
169
182
  "method": "GET"
170
183
  },
171
184
  {
172
185
  "kind": "api",
173
- "name": "servicechargesnapshots.get",
186
+ "name": "attendancepunches.get",
174
187
  "operation": "get",
175
- "objectName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot",
176
- "path": "/servicechargesnapshots/[id]",
188
+ "objectName": "@happyvertical/smrt-timesheets:AttendancePunch",
189
+ "path": "/attendancepunches/[id]",
177
190
  "method": "GET"
178
191
  },
179
192
  {
180
193
  "kind": "cli",
181
- "name": "servicechargesnapshot_list",
194
+ "name": "attendancepunch_list",
182
195
  "operation": "list",
183
- "objectName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot"
196
+ "objectName": "@happyvertical/smrt-timesheets:AttendancePunch"
184
197
  },
185
198
  {
186
199
  "kind": "cli",
187
- "name": "servicechargesnapshot_get",
200
+ "name": "attendancepunch_get",
188
201
  "operation": "get",
189
- "objectName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot"
202
+ "objectName": "@happyvertical/smrt-timesheets:AttendancePunch"
190
203
  },
191
204
  {
192
205
  "kind": "mcp",
193
- "name": "servicechargesnapshot_list",
206
+ "name": "attendancepunch_list",
194
207
  "operation": "list",
195
- "objectName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot"
208
+ "objectName": "@happyvertical/smrt-timesheets:AttendancePunch"
196
209
  },
197
210
  {
198
211
  "kind": "mcp",
199
- "name": "servicechargesnapshot_get",
212
+ "name": "attendancepunch_get",
200
213
  "operation": "get",
201
- "objectName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot"
214
+ "objectName": "@happyvertical/smrt-timesheets:AttendancePunch"
202
215
  }
203
216
  ],
204
217
  "withheldSurfaces": [
205
- {
206
- "kind": "api",
207
- "operation": "initialize",
208
- "code": "lifecycle-method",
209
- "reason": "`initialize` is a framework lifecycle method, not a distinct operation",
210
- "objectName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot"
211
- },
212
218
  {
213
219
  "kind": "api",
214
220
  "operation": "save",
215
221
  "code": "lifecycle-method",
216
222
  "reason": "`save` is a framework lifecycle method, not a distinct operation",
217
- "objectName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot"
223
+ "objectName": "@happyvertical/smrt-timesheets:AttendancePunch"
218
224
  }
219
225
  ],
220
226
  "relationshipFeatures": [
227
+ "crossPackageRef",
221
228
  "foreignKey",
222
229
  "uuidColumns"
223
230
  ],
@@ -225,80 +232,65 @@
225
232
  "risks": []
226
233
  },
227
234
  {
228
- "name": "ServiceCompensationSnapshot",
229
- "qualifiedName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot",
230
- "previousQualifiedNames": [
231
- "@happyvertical/smrt-projects:ServiceCompensationSnapshot"
232
- ],
233
- "collection": "servicecompensationsnapshots",
234
- "tableName": "service_compensation_snapshots",
235
+ "name": "AttendanceBreak",
236
+ "qualifiedName": "@happyvertical/smrt-timesheets:AttendanceBreak",
237
+ "collection": "attendancebreaks",
238
+ "tableName": "attendance_breaks",
235
239
  "packageName": "@happyvertical/smrt-timesheets",
236
240
  "extends": "SmrtObject",
237
241
  "fields": [
238
242
  {
239
243
  "name": "tenantId",
240
244
  "type": "text",
241
- "required": false,
245
+ "required": true,
242
246
  "columnType": "UUID"
243
247
  },
244
248
  {
245
- "name": "timeEntryId",
249
+ "name": "punchId",
246
250
  "type": "foreignKey",
247
- "required": true,
248
- "related": "ServiceTimeEntry",
251
+ "required": false,
252
+ "related": "AttendancePunch",
249
253
  "columnType": "UUID"
250
254
  },
251
255
  {
252
- "name": "amount",
253
- "type": "integer",
256
+ "name": "startedAt",
257
+ "type": "datetime",
254
258
  "required": false,
255
- "columnType": "INTEGER",
256
- "default": 0
259
+ "columnType": "TIMESTAMP"
257
260
  },
258
261
  {
259
- "name": "currency",
260
- "type": "text",
262
+ "name": "endedAt",
263
+ "type": "datetime",
261
264
  "required": false,
262
- "columnType": "TEXT"
265
+ "columnType": "TIMESTAMP"
263
266
  },
264
267
  {
265
- "name": "termsVersion",
266
- "type": "text",
267
- "required": false,
268
- "columnType": "TEXT"
268
+ "name": "paid",
269
+ "type": "boolean",
270
+ "required": true,
271
+ "columnType": "BOOLEAN",
272
+ "default": false
269
273
  },
270
274
  {
271
- "name": "rateSnapshot",
275
+ "name": "openSlot",
272
276
  "type": "text",
273
- "required": false,
277
+ "required": true,
274
278
  "columnType": "TEXT"
275
- },
276
- {
277
- "name": "createdAt",
278
- "type": "datetime",
279
- "required": false,
280
- "columnType": "TIMESTAMP"
281
279
  }
282
280
  ],
283
281
  "relationships": [
284
282
  {
285
- "name": "timeEntryId",
283
+ "name": "punchId",
286
284
  "type": "foreignKey",
287
- "required": true,
288
- "related": "ServiceTimeEntry",
285
+ "required": false,
286
+ "related": "AttendancePunch",
289
287
  "columnType": "UUID"
290
288
  }
291
289
  ],
292
290
  "methods": [
293
- "initialize",
294
291
  "save"
295
292
  ],
296
293
  "methodSignatures": [
297
- {
298
- "name": "initialize",
299
- "async": true,
300
- "returns": "Promise<this>"
301
- },
302
294
  {
303
295
  "name": "save",
304
296
  "async": true,
@@ -307,68 +299,63 @@
307
299
  ],
308
300
  "tenant": {
309
301
  "scoped": true,
310
- "mode": "optional",
302
+ "mode": "required",
311
303
  "field": "tenantId"
312
304
  },
313
305
  "conflictColumns": [
314
- "time_entry_id"
306
+ "tenant_id",
307
+ "slug",
308
+ "context"
315
309
  ],
316
310
  "surfaces": [
317
311
  {
318
312
  "kind": "api",
319
- "name": "servicecompensationsnapshots.list",
313
+ "name": "attendancebreaks.list",
320
314
  "operation": "list",
321
- "objectName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot",
322
- "path": "/servicecompensationsnapshots",
315
+ "objectName": "@happyvertical/smrt-timesheets:AttendanceBreak",
316
+ "path": "/attendancebreaks",
323
317
  "method": "GET"
324
318
  },
325
319
  {
326
320
  "kind": "api",
327
- "name": "servicecompensationsnapshots.get",
321
+ "name": "attendancebreaks.get",
328
322
  "operation": "get",
329
- "objectName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot",
330
- "path": "/servicecompensationsnapshots/[id]",
323
+ "objectName": "@happyvertical/smrt-timesheets:AttendanceBreak",
324
+ "path": "/attendancebreaks/[id]",
331
325
  "method": "GET"
332
326
  },
333
327
  {
334
328
  "kind": "cli",
335
- "name": "servicecompensationsnapshot_list",
329
+ "name": "attendancebreak_list",
336
330
  "operation": "list",
337
- "objectName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot"
331
+ "objectName": "@happyvertical/smrt-timesheets:AttendanceBreak"
338
332
  },
339
333
  {
340
334
  "kind": "cli",
341
- "name": "servicecompensationsnapshot_get",
335
+ "name": "attendancebreak_get",
342
336
  "operation": "get",
343
- "objectName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot"
337
+ "objectName": "@happyvertical/smrt-timesheets:AttendanceBreak"
344
338
  },
345
339
  {
346
340
  "kind": "mcp",
347
- "name": "servicecompensationsnapshot_list",
341
+ "name": "attendancebreak_list",
348
342
  "operation": "list",
349
- "objectName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot"
343
+ "objectName": "@happyvertical/smrt-timesheets:AttendanceBreak"
350
344
  },
351
345
  {
352
346
  "kind": "mcp",
353
- "name": "servicecompensationsnapshot_get",
347
+ "name": "attendancebreak_get",
354
348
  "operation": "get",
355
- "objectName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot"
349
+ "objectName": "@happyvertical/smrt-timesheets:AttendanceBreak"
356
350
  }
357
351
  ],
358
352
  "withheldSurfaces": [
359
- {
360
- "kind": "api",
361
- "operation": "initialize",
362
- "code": "lifecycle-method",
363
- "reason": "`initialize` is a framework lifecycle method, not a distinct operation",
364
- "objectName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot"
365
- },
366
353
  {
367
354
  "kind": "api",
368
355
  "operation": "save",
369
356
  "code": "lifecycle-method",
370
357
  "reason": "`save` is a framework lifecycle method, not a distinct operation",
371
- "objectName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot"
358
+ "objectName": "@happyvertical/smrt-timesheets:AttendanceBreak"
372
359
  }
373
360
  ],
374
361
  "relationshipFeatures": [
@@ -379,124 +366,1013 @@
379
366
  "risks": []
380
367
  },
381
368
  {
382
- "name": "ServiceChargeSnapshotCollection",
383
- "qualifiedName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshotCollection",
384
- "collection": "servicechargesnapshots",
385
- "tableName": "service_charge_snapshots",
386
- "packageName": "@happyvertical/smrt-timesheets",
387
- "extends": "SmrtCollection",
388
- "fields": [],
389
- "relationships": [],
390
- "methods": [],
391
- "surfaces": [],
392
- "relationshipFeatures": [
393
- "uuidColumns"
394
- ],
395
- "tags": [],
396
- "risks": []
397
- },
398
- {
399
- "name": "ServiceCompensationSnapshotCollection",
400
- "qualifiedName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshotCollection",
401
- "collection": "servicecompensationsnapshots",
402
- "tableName": "service_compensation_snapshots",
403
- "packageName": "@happyvertical/smrt-timesheets",
404
- "extends": "SmrtCollection",
405
- "fields": [],
406
- "relationships": [],
407
- "methods": [],
408
- "surfaces": [],
409
- "relationshipFeatures": [
410
- "uuidColumns"
411
- ],
412
- "tags": [],
413
- "risks": []
414
- },
415
- {
416
- "name": "ServiceTimeEntry",
417
- "qualifiedName": "@happyvertical/smrt-timesheets:ServiceTimeEntry",
418
- "previousQualifiedNames": [
419
- "@happyvertical/smrt-projects:ServiceTimeEntry"
420
- ],
421
- "collection": "servicetimeentries",
422
- "tableName": "service_time_entries",
369
+ "name": "AttendanceReplay",
370
+ "qualifiedName": "@happyvertical/smrt-timesheets:AttendanceReplay",
371
+ "collection": "attendancereplays",
372
+ "tableName": "attendance_replays",
423
373
  "packageName": "@happyvertical/smrt-timesheets",
424
374
  "extends": "SmrtObject",
425
375
  "fields": [
426
376
  {
427
377
  "name": "tenantId",
428
378
  "type": "text",
429
- "required": false,
379
+ "required": true,
430
380
  "columnType": "UUID"
431
381
  },
432
382
  {
433
- "name": "workRefType",
383
+ "name": "replayKey",
434
384
  "type": "text",
435
- "required": false,
385
+ "required": true,
436
386
  "columnType": "TEXT"
437
387
  },
438
388
  {
439
- "name": "workRefId",
389
+ "name": "content",
440
390
  "type": "text",
441
391
  "required": false,
442
392
  "columnType": "TEXT"
443
393
  },
444
394
  {
445
- "name": "participantKind",
395
+ "name": "outcome",
446
396
  "type": "text",
447
397
  "required": false,
448
398
  "columnType": "TEXT"
449
- },
399
+ }
400
+ ],
401
+ "relationships": [],
402
+ "methods": [
403
+ "getOutcome",
404
+ "save",
405
+ "setOutcome"
406
+ ],
407
+ "methodSignatures": [
450
408
  {
451
- "name": "participantProfileId",
452
- "type": "crossPackageRef",
453
- "required": false,
454
- "related": "@happyvertical/smrt-profiles:Profile",
455
- "columnType": "UUID"
409
+ "name": "getOutcome",
410
+ "returns": "AttendanceReplayOutcome"
456
411
  },
457
412
  {
458
- "name": "agentRef",
459
- "type": "text",
460
- "required": false,
461
- "columnType": "TEXT"
413
+ "name": "save",
414
+ "async": true,
415
+ "returns": "Promise<this>"
462
416
  },
463
417
  {
464
- "name": "source",
418
+ "name": "setOutcome",
419
+ "params": [
420
+ "value: AttendanceReplayOutcome"
421
+ ],
422
+ "returns": "void"
423
+ }
424
+ ],
425
+ "tenant": {
426
+ "scoped": true,
427
+ "mode": "required",
428
+ "field": "tenantId"
429
+ },
430
+ "conflictColumns": [
431
+ "tenant_id",
432
+ "slug",
433
+ "context"
434
+ ],
435
+ "surfaces": [],
436
+ "withheldSurfaces": [
437
+ {
438
+ "kind": "api",
439
+ "operation": "getOutcome",
440
+ "code": "not-included",
441
+ "reason": "not listed in api.include",
442
+ "objectName": "@happyvertical/smrt-timesheets:AttendanceReplay"
443
+ },
444
+ {
445
+ "kind": "api",
446
+ "operation": "save",
447
+ "code": "lifecycle-method",
448
+ "reason": "`save` is a framework lifecycle method, not a distinct operation",
449
+ "objectName": "@happyvertical/smrt-timesheets:AttendanceReplay"
450
+ },
451
+ {
452
+ "kind": "api",
453
+ "operation": "setOutcome",
454
+ "code": "not-included",
455
+ "reason": "not listed in api.include",
456
+ "objectName": "@happyvertical/smrt-timesheets:AttendanceReplay"
457
+ }
458
+ ],
459
+ "relationshipFeatures": [
460
+ "uuidColumns"
461
+ ],
462
+ "tags": [],
463
+ "risks": []
464
+ },
465
+ {
466
+ "name": "AttendancePunchCollection",
467
+ "qualifiedName": "@happyvertical/smrt-timesheets:AttendancePunchCollection",
468
+ "collection": "attendancepunches",
469
+ "tableName": "attendance_punches",
470
+ "packageName": "@happyvertical/smrt-timesheets",
471
+ "extends": "SmrtCollection",
472
+ "fields": [],
473
+ "relationships": [],
474
+ "methods": [],
475
+ "surfaces": [],
476
+ "relationshipFeatures": [
477
+ "uuidColumns"
478
+ ],
479
+ "tags": [],
480
+ "risks": []
481
+ },
482
+ {
483
+ "name": "AttendanceBreakCollection",
484
+ "qualifiedName": "@happyvertical/smrt-timesheets:AttendanceBreakCollection",
485
+ "collection": "attendancebreaks",
486
+ "tableName": "attendance_breaks",
487
+ "packageName": "@happyvertical/smrt-timesheets",
488
+ "extends": "SmrtCollection",
489
+ "fields": [],
490
+ "relationships": [],
491
+ "methods": [],
492
+ "surfaces": [],
493
+ "relationshipFeatures": [
494
+ "uuidColumns"
495
+ ],
496
+ "tags": [],
497
+ "risks": []
498
+ },
499
+ {
500
+ "name": "AttendanceReplayCollection",
501
+ "qualifiedName": "@happyvertical/smrt-timesheets:AttendanceReplayCollection",
502
+ "collection": "attendancereplays",
503
+ "tableName": "attendance_replays",
504
+ "packageName": "@happyvertical/smrt-timesheets",
505
+ "extends": "SmrtCollection",
506
+ "fields": [],
507
+ "relationships": [],
508
+ "methods": [],
509
+ "surfaces": [],
510
+ "relationshipFeatures": [
511
+ "uuidColumns"
512
+ ],
513
+ "tags": [],
514
+ "risks": []
515
+ },
516
+ {
517
+ "name": "ServiceChargeSnapshot",
518
+ "qualifiedName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot",
519
+ "previousQualifiedNames": [
520
+ "@happyvertical/smrt-projects:ServiceChargeSnapshot"
521
+ ],
522
+ "collection": "servicechargesnapshots",
523
+ "tableName": "service_charge_snapshots",
524
+ "packageName": "@happyvertical/smrt-timesheets",
525
+ "extends": "SmrtObject",
526
+ "fields": [
527
+ {
528
+ "name": "tenantId",
529
+ "type": "text",
530
+ "required": false,
531
+ "columnType": "UUID"
532
+ },
533
+ {
534
+ "name": "timeEntryId",
535
+ "type": "foreignKey",
536
+ "required": true,
537
+ "related": "ServiceTimeEntry",
538
+ "columnType": "UUID"
539
+ },
540
+ {
541
+ "name": "amount",
542
+ "type": "integer",
543
+ "required": false,
544
+ "columnType": "INTEGER",
545
+ "default": 0
546
+ },
547
+ {
548
+ "name": "currency",
549
+ "type": "text",
550
+ "required": false,
551
+ "columnType": "TEXT"
552
+ },
553
+ {
554
+ "name": "pricingVersion",
555
+ "type": "text",
556
+ "required": false,
557
+ "columnType": "TEXT"
558
+ },
559
+ {
560
+ "name": "strategy",
561
+ "type": "text",
562
+ "required": false,
563
+ "columnType": "TEXT"
564
+ },
565
+ {
566
+ "name": "rateSnapshot",
567
+ "type": "text",
568
+ "required": false,
569
+ "columnType": "TEXT"
570
+ },
571
+ {
572
+ "name": "sourceChargeRef",
573
+ "type": "text",
574
+ "required": false,
575
+ "columnType": "TEXT"
576
+ },
577
+ {
578
+ "name": "createdAt",
579
+ "type": "datetime",
580
+ "required": false,
581
+ "columnType": "TIMESTAMP"
582
+ }
583
+ ],
584
+ "relationships": [
585
+ {
586
+ "name": "timeEntryId",
587
+ "type": "foreignKey",
588
+ "required": true,
589
+ "related": "ServiceTimeEntry",
590
+ "columnType": "UUID"
591
+ }
592
+ ],
593
+ "methods": [
594
+ "initialize",
595
+ "save"
596
+ ],
597
+ "methodSignatures": [
598
+ {
599
+ "name": "initialize",
600
+ "async": true,
601
+ "returns": "Promise<this>"
602
+ },
603
+ {
604
+ "name": "save",
605
+ "async": true,
606
+ "returns": "Promise<this>"
607
+ }
608
+ ],
609
+ "tenant": {
610
+ "scoped": true,
611
+ "mode": "optional",
612
+ "field": "tenantId"
613
+ },
614
+ "conflictColumns": [
615
+ "time_entry_id"
616
+ ],
617
+ "surfaces": [
618
+ {
619
+ "kind": "api",
620
+ "name": "servicechargesnapshots.list",
621
+ "operation": "list",
622
+ "objectName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot",
623
+ "path": "/servicechargesnapshots",
624
+ "method": "GET"
625
+ },
626
+ {
627
+ "kind": "api",
628
+ "name": "servicechargesnapshots.get",
629
+ "operation": "get",
630
+ "objectName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot",
631
+ "path": "/servicechargesnapshots/[id]",
632
+ "method": "GET"
633
+ },
634
+ {
635
+ "kind": "cli",
636
+ "name": "servicechargesnapshot_list",
637
+ "operation": "list",
638
+ "objectName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot"
639
+ },
640
+ {
641
+ "kind": "cli",
642
+ "name": "servicechargesnapshot_get",
643
+ "operation": "get",
644
+ "objectName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot"
645
+ },
646
+ {
647
+ "kind": "mcp",
648
+ "name": "servicechargesnapshot_list",
649
+ "operation": "list",
650
+ "objectName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot"
651
+ },
652
+ {
653
+ "kind": "mcp",
654
+ "name": "servicechargesnapshot_get",
655
+ "operation": "get",
656
+ "objectName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot"
657
+ }
658
+ ],
659
+ "withheldSurfaces": [
660
+ {
661
+ "kind": "api",
662
+ "operation": "initialize",
663
+ "code": "lifecycle-method",
664
+ "reason": "`initialize` is a framework lifecycle method, not a distinct operation",
665
+ "objectName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot"
666
+ },
667
+ {
668
+ "kind": "api",
669
+ "operation": "save",
670
+ "code": "lifecycle-method",
671
+ "reason": "`save` is a framework lifecycle method, not a distinct operation",
672
+ "objectName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshot"
673
+ }
674
+ ],
675
+ "relationshipFeatures": [
676
+ "foreignKey",
677
+ "uuidColumns"
678
+ ],
679
+ "tags": [],
680
+ "risks": []
681
+ },
682
+ {
683
+ "name": "ServiceCompensationSnapshot",
684
+ "qualifiedName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot",
685
+ "previousQualifiedNames": [
686
+ "@happyvertical/smrt-projects:ServiceCompensationSnapshot"
687
+ ],
688
+ "collection": "servicecompensationsnapshots",
689
+ "tableName": "service_compensation_snapshots",
690
+ "packageName": "@happyvertical/smrt-timesheets",
691
+ "extends": "SmrtObject",
692
+ "fields": [
693
+ {
694
+ "name": "tenantId",
695
+ "type": "text",
696
+ "required": false,
697
+ "columnType": "UUID"
698
+ },
699
+ {
700
+ "name": "timeEntryId",
701
+ "type": "foreignKey",
702
+ "required": true,
703
+ "related": "ServiceTimeEntry",
704
+ "columnType": "UUID"
705
+ },
706
+ {
707
+ "name": "amount",
708
+ "type": "integer",
709
+ "required": false,
710
+ "columnType": "INTEGER",
711
+ "default": 0
712
+ },
713
+ {
714
+ "name": "currency",
715
+ "type": "text",
716
+ "required": false,
717
+ "columnType": "TEXT"
718
+ },
719
+ {
720
+ "name": "termsVersion",
721
+ "type": "text",
722
+ "required": false,
723
+ "columnType": "TEXT"
724
+ },
725
+ {
726
+ "name": "rateSnapshot",
727
+ "type": "text",
728
+ "required": false,
729
+ "columnType": "TEXT"
730
+ },
731
+ {
732
+ "name": "createdAt",
733
+ "type": "datetime",
734
+ "required": false,
735
+ "columnType": "TIMESTAMP"
736
+ }
737
+ ],
738
+ "relationships": [
739
+ {
740
+ "name": "timeEntryId",
741
+ "type": "foreignKey",
742
+ "required": true,
743
+ "related": "ServiceTimeEntry",
744
+ "columnType": "UUID"
745
+ }
746
+ ],
747
+ "methods": [
748
+ "initialize",
749
+ "save"
750
+ ],
751
+ "methodSignatures": [
752
+ {
753
+ "name": "initialize",
754
+ "async": true,
755
+ "returns": "Promise<this>"
756
+ },
757
+ {
758
+ "name": "save",
759
+ "async": true,
760
+ "returns": "Promise<this>"
761
+ }
762
+ ],
763
+ "tenant": {
764
+ "scoped": true,
765
+ "mode": "optional",
766
+ "field": "tenantId"
767
+ },
768
+ "conflictColumns": [
769
+ "time_entry_id"
770
+ ],
771
+ "surfaces": [
772
+ {
773
+ "kind": "api",
774
+ "name": "servicecompensationsnapshots.list",
775
+ "operation": "list",
776
+ "objectName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot",
777
+ "path": "/servicecompensationsnapshots",
778
+ "method": "GET"
779
+ },
780
+ {
781
+ "kind": "api",
782
+ "name": "servicecompensationsnapshots.get",
783
+ "operation": "get",
784
+ "objectName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot",
785
+ "path": "/servicecompensationsnapshots/[id]",
786
+ "method": "GET"
787
+ },
788
+ {
789
+ "kind": "cli",
790
+ "name": "servicecompensationsnapshot_list",
791
+ "operation": "list",
792
+ "objectName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot"
793
+ },
794
+ {
795
+ "kind": "cli",
796
+ "name": "servicecompensationsnapshot_get",
797
+ "operation": "get",
798
+ "objectName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot"
799
+ },
800
+ {
801
+ "kind": "mcp",
802
+ "name": "servicecompensationsnapshot_list",
803
+ "operation": "list",
804
+ "objectName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot"
805
+ },
806
+ {
807
+ "kind": "mcp",
808
+ "name": "servicecompensationsnapshot_get",
809
+ "operation": "get",
810
+ "objectName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot"
811
+ }
812
+ ],
813
+ "withheldSurfaces": [
814
+ {
815
+ "kind": "api",
816
+ "operation": "initialize",
817
+ "code": "lifecycle-method",
818
+ "reason": "`initialize` is a framework lifecycle method, not a distinct operation",
819
+ "objectName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot"
820
+ },
821
+ {
822
+ "kind": "api",
823
+ "operation": "save",
824
+ "code": "lifecycle-method",
825
+ "reason": "`save` is a framework lifecycle method, not a distinct operation",
826
+ "objectName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshot"
827
+ }
828
+ ],
829
+ "relationshipFeatures": [
830
+ "foreignKey",
831
+ "uuidColumns"
832
+ ],
833
+ "tags": [],
834
+ "risks": []
835
+ },
836
+ {
837
+ "name": "ServiceChargeSnapshotCollection",
838
+ "qualifiedName": "@happyvertical/smrt-timesheets:ServiceChargeSnapshotCollection",
839
+ "collection": "servicechargesnapshots",
840
+ "tableName": "service_charge_snapshots",
841
+ "packageName": "@happyvertical/smrt-timesheets",
842
+ "extends": "SmrtCollection",
843
+ "fields": [],
844
+ "relationships": [],
845
+ "methods": [],
846
+ "surfaces": [],
847
+ "relationshipFeatures": [
848
+ "uuidColumns"
849
+ ],
850
+ "tags": [],
851
+ "risks": []
852
+ },
853
+ {
854
+ "name": "ServiceCompensationSnapshotCollection",
855
+ "qualifiedName": "@happyvertical/smrt-timesheets:ServiceCompensationSnapshotCollection",
856
+ "collection": "servicecompensationsnapshots",
857
+ "tableName": "service_compensation_snapshots",
858
+ "packageName": "@happyvertical/smrt-timesheets",
859
+ "extends": "SmrtCollection",
860
+ "fields": [],
861
+ "relationships": [],
862
+ "methods": [],
863
+ "surfaces": [],
864
+ "relationshipFeatures": [
865
+ "uuidColumns"
866
+ ],
867
+ "tags": [],
868
+ "risks": []
869
+ },
870
+ {
871
+ "name": "ServiceTimeEntry",
872
+ "qualifiedName": "@happyvertical/smrt-timesheets:ServiceTimeEntry",
873
+ "previousQualifiedNames": [
874
+ "@happyvertical/smrt-projects:ServiceTimeEntry"
875
+ ],
876
+ "collection": "servicetimeentries",
877
+ "tableName": "service_time_entries",
878
+ "packageName": "@happyvertical/smrt-timesheets",
879
+ "extends": "SmrtObject",
880
+ "fields": [
881
+ {
882
+ "name": "tenantId",
883
+ "type": "text",
884
+ "required": false,
885
+ "columnType": "UUID"
886
+ },
887
+ {
888
+ "name": "workRefType",
889
+ "type": "text",
890
+ "required": false,
891
+ "columnType": "TEXT"
892
+ },
893
+ {
894
+ "name": "workRefId",
895
+ "type": "text",
896
+ "required": false,
897
+ "columnType": "TEXT"
898
+ },
899
+ {
900
+ "name": "participantKind",
901
+ "type": "text",
902
+ "required": false,
903
+ "columnType": "TEXT"
904
+ },
905
+ {
906
+ "name": "participantProfileId",
907
+ "type": "crossPackageRef",
908
+ "required": false,
909
+ "related": "@happyvertical/smrt-profiles:Profile",
910
+ "columnType": "UUID"
911
+ },
912
+ {
913
+ "name": "agentRef",
914
+ "type": "text",
915
+ "required": false,
916
+ "columnType": "TEXT"
917
+ },
918
+ {
919
+ "name": "source",
920
+ "type": "text",
921
+ "required": false,
922
+ "columnType": "TEXT"
923
+ },
924
+ {
925
+ "name": "description",
926
+ "type": "text",
927
+ "required": false,
928
+ "columnType": "TEXT"
929
+ },
930
+ {
931
+ "name": "startedAt",
932
+ "type": "datetime",
933
+ "required": false,
934
+ "columnType": "TIMESTAMP"
935
+ },
936
+ {
937
+ "name": "endedAt",
938
+ "type": "datetime",
939
+ "required": false,
940
+ "columnType": "TIMESTAMP"
941
+ },
942
+ {
943
+ "name": "durationSeconds",
944
+ "type": "integer",
945
+ "required": false,
946
+ "columnType": "INTEGER",
947
+ "default": 0
948
+ },
949
+ {
950
+ "name": "evidence",
951
+ "type": "text",
952
+ "required": false,
953
+ "columnType": "TEXT"
954
+ },
955
+ {
956
+ "name": "status",
465
957
  "type": "text",
466
958
  "required": false,
467
959
  "columnType": "TEXT"
468
960
  },
469
961
  {
470
- "name": "description",
962
+ "name": "submittedAt",
963
+ "type": "datetime",
964
+ "required": false,
965
+ "columnType": "TIMESTAMP"
966
+ },
967
+ {
968
+ "name": "submittedByProfileId",
969
+ "type": "crossPackageRef",
970
+ "required": false,
971
+ "related": "@happyvertical/smrt-profiles:Profile",
972
+ "columnType": "UUID"
973
+ },
974
+ {
975
+ "name": "approvedAt",
976
+ "type": "datetime",
977
+ "required": false,
978
+ "columnType": "TIMESTAMP"
979
+ },
980
+ {
981
+ "name": "approvedByProfileId",
982
+ "type": "crossPackageRef",
983
+ "required": false,
984
+ "related": "@happyvertical/smrt-profiles:Profile",
985
+ "columnType": "UUID"
986
+ },
987
+ {
988
+ "name": "approvalPath",
989
+ "type": "text",
990
+ "required": false,
991
+ "columnType": "TEXT"
992
+ },
993
+ {
994
+ "name": "rejectedAt",
995
+ "type": "datetime",
996
+ "required": false,
997
+ "columnType": "TIMESTAMP"
998
+ },
999
+ {
1000
+ "name": "rejectedByProfileId",
1001
+ "type": "crossPackageRef",
1002
+ "required": false,
1003
+ "related": "@happyvertical/smrt-profiles:Profile",
1004
+ "columnType": "UUID"
1005
+ },
1006
+ {
1007
+ "name": "rejectionReason",
1008
+ "type": "text",
1009
+ "required": false,
1010
+ "columnType": "TEXT"
1011
+ },
1012
+ {
1013
+ "name": "correctionOfId",
1014
+ "type": "foreignKey",
1015
+ "required": false,
1016
+ "related": "ServiceTimeEntry",
1017
+ "columnType": "UUID"
1018
+ },
1019
+ {
1020
+ "name": "metadata",
1021
+ "type": "text",
1022
+ "required": false,
1023
+ "columnType": "TEXT"
1024
+ }
1025
+ ],
1026
+ "relationships": [
1027
+ {
1028
+ "name": "participantProfileId",
1029
+ "type": "crossPackageRef",
1030
+ "required": false,
1031
+ "related": "@happyvertical/smrt-profiles:Profile",
1032
+ "columnType": "UUID"
1033
+ },
1034
+ {
1035
+ "name": "submittedByProfileId",
1036
+ "type": "crossPackageRef",
1037
+ "required": false,
1038
+ "related": "@happyvertical/smrt-profiles:Profile",
1039
+ "columnType": "UUID"
1040
+ },
1041
+ {
1042
+ "name": "approvedByProfileId",
1043
+ "type": "crossPackageRef",
1044
+ "required": false,
1045
+ "related": "@happyvertical/smrt-profiles:Profile",
1046
+ "columnType": "UUID"
1047
+ },
1048
+ {
1049
+ "name": "rejectedByProfileId",
1050
+ "type": "crossPackageRef",
1051
+ "required": false,
1052
+ "related": "@happyvertical/smrt-profiles:Profile",
1053
+ "columnType": "UUID"
1054
+ },
1055
+ {
1056
+ "name": "correctionOfId",
1057
+ "type": "foreignKey",
1058
+ "required": false,
1059
+ "related": "ServiceTimeEntry",
1060
+ "columnType": "UUID"
1061
+ }
1062
+ ],
1063
+ "methods": [
1064
+ "durationHours",
1065
+ "getEvidence",
1066
+ "getMetadata",
1067
+ "initialize",
1068
+ "save",
1069
+ "setEvidence",
1070
+ "setMetadata"
1071
+ ],
1072
+ "methodSignatures": [
1073
+ {
1074
+ "name": "durationHours",
1075
+ "returns": "number"
1076
+ },
1077
+ {
1078
+ "name": "getEvidence",
1079
+ "returns": "ServiceEvidence[]"
1080
+ },
1081
+ {
1082
+ "name": "getMetadata",
1083
+ "returns": "Record<string, unknown>"
1084
+ },
1085
+ {
1086
+ "name": "initialize",
1087
+ "async": true,
1088
+ "returns": "Promise<this>"
1089
+ },
1090
+ {
1091
+ "name": "save",
1092
+ "async": true,
1093
+ "returns": "Promise<this>"
1094
+ },
1095
+ {
1096
+ "name": "setEvidence",
1097
+ "params": [
1098
+ "value: ServiceEvidence[]"
1099
+ ],
1100
+ "returns": "void"
1101
+ },
1102
+ {
1103
+ "name": "setMetadata",
1104
+ "params": [
1105
+ "value: Record<string, unknown>"
1106
+ ],
1107
+ "returns": "void"
1108
+ }
1109
+ ],
1110
+ "tenant": {
1111
+ "scoped": true,
1112
+ "mode": "optional",
1113
+ "field": "tenantId"
1114
+ },
1115
+ "conflictColumns": [
1116
+ "tenant_id",
1117
+ "slug",
1118
+ "context"
1119
+ ],
1120
+ "surfaces": [
1121
+ {
1122
+ "kind": "api",
1123
+ "name": "servicetimeentries.list",
1124
+ "operation": "list",
1125
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry",
1126
+ "path": "/servicetimeentries",
1127
+ "method": "GET"
1128
+ },
1129
+ {
1130
+ "kind": "api",
1131
+ "name": "servicetimeentries.get",
1132
+ "operation": "get",
1133
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry",
1134
+ "path": "/servicetimeentries/[id]",
1135
+ "method": "GET"
1136
+ },
1137
+ {
1138
+ "kind": "cli",
1139
+ "name": "servicetimeentry_list",
1140
+ "operation": "list",
1141
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
1142
+ },
1143
+ {
1144
+ "kind": "cli",
1145
+ "name": "servicetimeentry_get",
1146
+ "operation": "get",
1147
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
1148
+ },
1149
+ {
1150
+ "kind": "mcp",
1151
+ "name": "servicetimeentry_list",
1152
+ "operation": "list",
1153
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
1154
+ },
1155
+ {
1156
+ "kind": "mcp",
1157
+ "name": "servicetimeentry_get",
1158
+ "operation": "get",
1159
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
1160
+ }
1161
+ ],
1162
+ "withheldSurfaces": [
1163
+ {
1164
+ "kind": "api",
1165
+ "operation": "durationHours",
1166
+ "code": "not-included",
1167
+ "reason": "not listed in api.include",
1168
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
1169
+ },
1170
+ {
1171
+ "kind": "api",
1172
+ "operation": "getEvidence",
1173
+ "code": "not-included",
1174
+ "reason": "not listed in api.include",
1175
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
1176
+ },
1177
+ {
1178
+ "kind": "api",
1179
+ "operation": "getMetadata",
1180
+ "code": "not-included",
1181
+ "reason": "not listed in api.include",
1182
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
1183
+ },
1184
+ {
1185
+ "kind": "api",
1186
+ "operation": "initialize",
1187
+ "code": "lifecycle-method",
1188
+ "reason": "`initialize` is a framework lifecycle method, not a distinct operation",
1189
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
1190
+ },
1191
+ {
1192
+ "kind": "api",
1193
+ "operation": "save",
1194
+ "code": "lifecycle-method",
1195
+ "reason": "`save` is a framework lifecycle method, not a distinct operation",
1196
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
1197
+ },
1198
+ {
1199
+ "kind": "api",
1200
+ "operation": "setEvidence",
1201
+ "code": "not-included",
1202
+ "reason": "not listed in api.include",
1203
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
1204
+ },
1205
+ {
1206
+ "kind": "api",
1207
+ "operation": "setMetadata",
1208
+ "code": "not-included",
1209
+ "reason": "not listed in api.include",
1210
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
1211
+ }
1212
+ ],
1213
+ "relationshipFeatures": [
1214
+ "crossPackageRef",
1215
+ "foreignKey",
1216
+ "uuidColumns"
1217
+ ],
1218
+ "tags": [],
1219
+ "risks": []
1220
+ },
1221
+ {
1222
+ "name": "ServiceTimeEntryCollection",
1223
+ "qualifiedName": "@happyvertical/smrt-timesheets:ServiceTimeEntryCollection",
1224
+ "collection": "servicetimeentries",
1225
+ "tableName": "service_time_entries",
1226
+ "packageName": "@happyvertical/smrt-timesheets",
1227
+ "extends": "SmrtCollection",
1228
+ "fields": [],
1229
+ "relationships": [],
1230
+ "methods": [
1231
+ "forWork",
1232
+ "pendingApproval"
1233
+ ],
1234
+ "methodSignatures": [
1235
+ {
1236
+ "name": "forWork",
1237
+ "async": true,
1238
+ "params": [
1239
+ "workRefType: string",
1240
+ "workRefId: string"
1241
+ ],
1242
+ "returns": "Promise<ServiceTimeEntry[]>"
1243
+ },
1244
+ {
1245
+ "name": "pendingApproval",
1246
+ "async": true,
1247
+ "returns": "Promise<ServiceTimeEntry[]>"
1248
+ }
1249
+ ],
1250
+ "surfaces": [
1251
+ {
1252
+ "kind": "api",
1253
+ "name": "servicetimeentries.forWork",
1254
+ "operation": "forWork",
1255
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntryCollection",
1256
+ "path": "/servicetimeentries/forWork",
1257
+ "method": "POST"
1258
+ },
1259
+ {
1260
+ "kind": "api",
1261
+ "name": "servicetimeentries.pendingApproval",
1262
+ "operation": "pendingApproval",
1263
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntryCollection",
1264
+ "path": "/servicetimeentries/pendingApproval",
1265
+ "method": "POST"
1266
+ },
1267
+ {
1268
+ "kind": "cli",
1269
+ "name": "servicetimeentrycollection_forWork",
1270
+ "operation": "forWork",
1271
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntryCollection"
1272
+ },
1273
+ {
1274
+ "kind": "cli",
1275
+ "name": "servicetimeentrycollection_pendingApproval",
1276
+ "operation": "pendingApproval",
1277
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntryCollection"
1278
+ },
1279
+ {
1280
+ "kind": "mcp",
1281
+ "name": "servicetimeentrycollection_forwork",
1282
+ "operation": "forWork",
1283
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntryCollection"
1284
+ },
1285
+ {
1286
+ "kind": "mcp",
1287
+ "name": "servicetimeentrycollection_pendingapproval",
1288
+ "operation": "pendingApproval",
1289
+ "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntryCollection"
1290
+ }
1291
+ ],
1292
+ "relationshipFeatures": [
1293
+ "uuidColumns"
1294
+ ],
1295
+ "tags": [],
1296
+ "risks": []
1297
+ },
1298
+ {
1299
+ "name": "PeriodTimecard",
1300
+ "qualifiedName": "@happyvertical/smrt-timesheets:PeriodTimecard",
1301
+ "collection": "periodtimecards",
1302
+ "tableName": "period_timecards",
1303
+ "packageName": "@happyvertical/smrt-timesheets",
1304
+ "extends": "SmrtObject",
1305
+ "fields": [
1306
+ {
1307
+ "name": "tenantId",
471
1308
  "type": "text",
1309
+ "required": true,
1310
+ "columnType": "UUID"
1311
+ },
1312
+ {
1313
+ "name": "profileId",
1314
+ "type": "crossPackageRef",
472
1315
  "required": false,
473
- "columnType": "TEXT"
1316
+ "related": "@happyvertical/smrt-profiles:Profile",
1317
+ "columnType": "UUID"
474
1318
  },
475
1319
  {
476
- "name": "startedAt",
1320
+ "name": "startsAt",
477
1321
  "type": "datetime",
478
1322
  "required": false,
479
1323
  "columnType": "TIMESTAMP"
480
1324
  },
481
1325
  {
482
- "name": "endedAt",
1326
+ "name": "endsAt",
483
1327
  "type": "datetime",
484
1328
  "required": false,
485
1329
  "columnType": "TIMESTAMP"
486
1330
  },
487
1331
  {
488
- "name": "durationSeconds",
489
- "type": "integer",
1332
+ "name": "timezone",
1333
+ "type": "text",
490
1334
  "required": false,
491
- "columnType": "INTEGER",
492
- "default": 0
1335
+ "columnType": "TEXT"
493
1336
  },
494
1337
  {
495
- "name": "evidence",
1338
+ "name": "rulesVersion",
1339
+ "type": "text",
1340
+ "required": false,
1341
+ "columnType": "TEXT"
1342
+ },
1343
+ {
1344
+ "name": "rulesSnapshot",
1345
+ "type": "text",
1346
+ "required": false,
1347
+ "columnType": "TEXT"
1348
+ },
1349
+ {
1350
+ "name": "sourceSnapshot",
496
1351
  "type": "text",
497
1352
  "required": false,
498
1353
  "columnType": "TEXT"
499
1354
  },
1355
+ {
1356
+ "name": "regularSeconds",
1357
+ "type": "integer",
1358
+ "required": true,
1359
+ "columnType": "INTEGER",
1360
+ "default": 0
1361
+ },
1362
+ {
1363
+ "name": "overtimeSeconds",
1364
+ "type": "integer",
1365
+ "required": true,
1366
+ "columnType": "INTEGER",
1367
+ "default": 0
1368
+ },
1369
+ {
1370
+ "name": "totalSeconds",
1371
+ "type": "integer",
1372
+ "required": true,
1373
+ "columnType": "INTEGER",
1374
+ "default": 0
1375
+ },
500
1376
  {
501
1377
  "name": "status",
502
1378
  "type": "text",
@@ -504,65 +1380,159 @@
504
1380
  "columnType": "TEXT"
505
1381
  },
506
1382
  {
507
- "name": "submittedAt",
1383
+ "name": "confirmedAt",
508
1384
  "type": "datetime",
509
1385
  "required": false,
510
1386
  "columnType": "TIMESTAMP"
511
1387
  },
512
1388
  {
513
- "name": "submittedByProfileId",
1389
+ "name": "confirmedByProfileId",
514
1390
  "type": "crossPackageRef",
515
1391
  "required": false,
516
1392
  "related": "@happyvertical/smrt-profiles:Profile",
517
1393
  "columnType": "UUID"
518
- },
1394
+ }
1395
+ ],
1396
+ "relationships": [
519
1397
  {
520
- "name": "approvedAt",
521
- "type": "datetime",
1398
+ "name": "profileId",
1399
+ "type": "crossPackageRef",
522
1400
  "required": false,
523
- "columnType": "TIMESTAMP"
1401
+ "related": "@happyvertical/smrt-profiles:Profile",
1402
+ "columnType": "UUID"
524
1403
  },
525
1404
  {
526
- "name": "approvedByProfileId",
1405
+ "name": "confirmedByProfileId",
527
1406
  "type": "crossPackageRef",
528
1407
  "required": false,
529
1408
  "related": "@happyvertical/smrt-profiles:Profile",
530
1409
  "columnType": "UUID"
1410
+ }
1411
+ ],
1412
+ "methods": [
1413
+ "delete",
1414
+ "getRules",
1415
+ "getSources",
1416
+ "save"
1417
+ ],
1418
+ "methodSignatures": [
1419
+ {
1420
+ "name": "delete",
1421
+ "async": true,
1422
+ "returns": "Promise<void>"
531
1423
  },
532
1424
  {
533
- "name": "approvalPath",
1425
+ "name": "getRules",
1426
+ "returns": "Record<string, unknown>"
1427
+ },
1428
+ {
1429
+ "name": "getSources",
1430
+ "returns": "TimecardSource[]"
1431
+ },
1432
+ {
1433
+ "name": "save",
1434
+ "async": true,
1435
+ "returns": "Promise<this>"
1436
+ }
1437
+ ],
1438
+ "tenant": {
1439
+ "scoped": true,
1440
+ "mode": "required",
1441
+ "field": "tenantId"
1442
+ },
1443
+ "conflictColumns": [
1444
+ "tenant_id",
1445
+ "slug",
1446
+ "context"
1447
+ ],
1448
+ "surfaces": [],
1449
+ "withheldSurfaces": [
1450
+ {
1451
+ "kind": "api",
1452
+ "operation": "getRules",
1453
+ "code": "not-included",
1454
+ "reason": "not listed in api.include",
1455
+ "objectName": "@happyvertical/smrt-timesheets:PeriodTimecard"
1456
+ },
1457
+ {
1458
+ "kind": "api",
1459
+ "operation": "getSources",
1460
+ "code": "not-included",
1461
+ "reason": "not listed in api.include",
1462
+ "objectName": "@happyvertical/smrt-timesheets:PeriodTimecard"
1463
+ },
1464
+ {
1465
+ "kind": "api",
1466
+ "operation": "save",
1467
+ "code": "lifecycle-method",
1468
+ "reason": "`save` is a framework lifecycle method, not a distinct operation",
1469
+ "objectName": "@happyvertical/smrt-timesheets:PeriodTimecard"
1470
+ }
1471
+ ],
1472
+ "relationshipFeatures": [
1473
+ "crossPackageRef",
1474
+ "uuidColumns"
1475
+ ],
1476
+ "tags": [],
1477
+ "risks": []
1478
+ },
1479
+ {
1480
+ "name": "TimecardAdjustment",
1481
+ "qualifiedName": "@happyvertical/smrt-timesheets:TimecardAdjustment",
1482
+ "collection": "timecardadjustments",
1483
+ "tableName": "timecard_adjustments",
1484
+ "packageName": "@happyvertical/smrt-timesheets",
1485
+ "extends": "SmrtObject",
1486
+ "fields": [
1487
+ {
1488
+ "name": "tenantId",
534
1489
  "type": "text",
1490
+ "required": true,
1491
+ "columnType": "UUID"
1492
+ },
1493
+ {
1494
+ "name": "timecardId",
1495
+ "type": "foreignKey",
535
1496
  "required": false,
536
- "columnType": "TEXT"
1497
+ "related": "PeriodTimecard",
1498
+ "columnType": "UUID"
537
1499
  },
538
1500
  {
539
- "name": "rejectedAt",
540
- "type": "datetime",
1501
+ "name": "profileId",
1502
+ "type": "crossPackageRef",
541
1503
  "required": false,
542
- "columnType": "TIMESTAMP"
1504
+ "related": "@happyvertical/smrt-profiles:Profile",
1505
+ "columnType": "UUID"
543
1506
  },
544
1507
  {
545
- "name": "rejectedByProfileId",
1508
+ "name": "actorProfileId",
546
1509
  "type": "crossPackageRef",
547
1510
  "required": false,
548
1511
  "related": "@happyvertical/smrt-profiles:Profile",
549
1512
  "columnType": "UUID"
550
1513
  },
551
1514
  {
552
- "name": "rejectionReason",
1515
+ "name": "operationId",
553
1516
  "type": "text",
554
1517
  "required": false,
555
1518
  "columnType": "TEXT"
556
1519
  },
557
1520
  {
558
- "name": "correctionOfId",
559
- "type": "foreignKey",
560
- "required": false,
561
- "related": "ServiceTimeEntry",
562
- "columnType": "UUID"
1521
+ "name": "regularSeconds",
1522
+ "type": "integer",
1523
+ "required": true,
1524
+ "columnType": "INTEGER",
1525
+ "default": 0
563
1526
  },
564
1527
  {
565
- "name": "metadata",
1528
+ "name": "overtimeSeconds",
1529
+ "type": "integer",
1530
+ "required": true,
1531
+ "columnType": "INTEGER",
1532
+ "default": 0
1533
+ },
1534
+ {
1535
+ "name": "reason",
566
1536
  "type": "text",
567
1537
  "required": false,
568
1538
  "columnType": "TEXT"
@@ -570,91 +1540,46 @@
570
1540
  ],
571
1541
  "relationships": [
572
1542
  {
573
- "name": "participantProfileId",
574
- "type": "crossPackageRef",
575
- "required": false,
576
- "related": "@happyvertical/smrt-profiles:Profile",
577
- "columnType": "UUID"
578
- },
579
- {
580
- "name": "submittedByProfileId",
581
- "type": "crossPackageRef",
1543
+ "name": "timecardId",
1544
+ "type": "foreignKey",
582
1545
  "required": false,
583
- "related": "@happyvertical/smrt-profiles:Profile",
1546
+ "related": "PeriodTimecard",
584
1547
  "columnType": "UUID"
585
1548
  },
586
1549
  {
587
- "name": "approvedByProfileId",
1550
+ "name": "profileId",
588
1551
  "type": "crossPackageRef",
589
1552
  "required": false,
590
1553
  "related": "@happyvertical/smrt-profiles:Profile",
591
1554
  "columnType": "UUID"
592
1555
  },
593
1556
  {
594
- "name": "rejectedByProfileId",
1557
+ "name": "actorProfileId",
595
1558
  "type": "crossPackageRef",
596
1559
  "required": false,
597
1560
  "related": "@happyvertical/smrt-profiles:Profile",
598
1561
  "columnType": "UUID"
599
- },
600
- {
601
- "name": "correctionOfId",
602
- "type": "foreignKey",
603
- "required": false,
604
- "related": "ServiceTimeEntry",
605
- "columnType": "UUID"
606
1562
  }
607
1563
  ],
608
1564
  "methods": [
609
- "durationHours",
610
- "getEvidence",
611
- "getMetadata",
612
- "initialize",
613
- "save",
614
- "setEvidence",
615
- "setMetadata"
1565
+ "delete",
1566
+ "save"
616
1567
  ],
617
1568
  "methodSignatures": [
618
1569
  {
619
- "name": "durationHours",
620
- "returns": "number"
621
- },
622
- {
623
- "name": "getEvidence",
624
- "returns": "ServiceEvidence[]"
625
- },
626
- {
627
- "name": "getMetadata",
628
- "returns": "Record<string, unknown>"
629
- },
630
- {
631
- "name": "initialize",
1570
+ "name": "delete",
632
1571
  "async": true,
633
- "returns": "Promise<this>"
1572
+ "returns": "Promise<void>"
634
1573
  },
635
1574
  {
636
1575
  "name": "save",
637
1576
  "async": true,
638
1577
  "returns": "Promise<this>"
639
- },
640
- {
641
- "name": "setEvidence",
642
- "params": [
643
- "value: ServiceEvidence[]"
644
- ],
645
- "returns": "void"
646
- },
647
- {
648
- "name": "setMetadata",
649
- "params": [
650
- "value: Record<string, unknown>"
651
- ],
652
- "returns": "void"
653
1578
  }
654
1579
  ],
655
1580
  "tenant": {
656
1581
  "scoped": true,
657
- "mode": "optional",
1582
+ "mode": "required",
658
1583
  "field": "tenantId"
659
1584
  },
660
1585
  "conflictColumns": [
@@ -662,97 +1587,14 @@
662
1587
  "slug",
663
1588
  "context"
664
1589
  ],
665
- "surfaces": [
666
- {
667
- "kind": "api",
668
- "name": "servicetimeentries.list",
669
- "operation": "list",
670
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry",
671
- "path": "/servicetimeentries",
672
- "method": "GET"
673
- },
674
- {
675
- "kind": "api",
676
- "name": "servicetimeentries.get",
677
- "operation": "get",
678
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry",
679
- "path": "/servicetimeentries/[id]",
680
- "method": "GET"
681
- },
682
- {
683
- "kind": "cli",
684
- "name": "servicetimeentry_list",
685
- "operation": "list",
686
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
687
- },
688
- {
689
- "kind": "cli",
690
- "name": "servicetimeentry_get",
691
- "operation": "get",
692
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
693
- },
694
- {
695
- "kind": "mcp",
696
- "name": "servicetimeentry_list",
697
- "operation": "list",
698
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
699
- },
700
- {
701
- "kind": "mcp",
702
- "name": "servicetimeentry_get",
703
- "operation": "get",
704
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
705
- }
706
- ],
1590
+ "surfaces": [],
707
1591
  "withheldSurfaces": [
708
- {
709
- "kind": "api",
710
- "operation": "durationHours",
711
- "code": "not-included",
712
- "reason": "not listed in api.include",
713
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
714
- },
715
- {
716
- "kind": "api",
717
- "operation": "getEvidence",
718
- "code": "not-included",
719
- "reason": "not listed in api.include",
720
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
721
- },
722
- {
723
- "kind": "api",
724
- "operation": "getMetadata",
725
- "code": "not-included",
726
- "reason": "not listed in api.include",
727
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
728
- },
729
- {
730
- "kind": "api",
731
- "operation": "initialize",
732
- "code": "lifecycle-method",
733
- "reason": "`initialize` is a framework lifecycle method, not a distinct operation",
734
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
735
- },
736
1592
  {
737
1593
  "kind": "api",
738
1594
  "operation": "save",
739
1595
  "code": "lifecycle-method",
740
1596
  "reason": "`save` is a framework lifecycle method, not a distinct operation",
741
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
742
- },
743
- {
744
- "kind": "api",
745
- "operation": "setEvidence",
746
- "code": "not-included",
747
- "reason": "not listed in api.include",
748
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
749
- },
750
- {
751
- "kind": "api",
752
- "operation": "setMetadata",
753
- "code": "not-included",
754
- "reason": "not listed in api.include",
755
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntry"
1597
+ "objectName": "@happyvertical/smrt-timesheets:TimecardAdjustment"
756
1598
  }
757
1599
  ],
758
1600
  "relationshipFeatures": [
@@ -764,76 +1606,33 @@
764
1606
  "risks": []
765
1607
  },
766
1608
  {
767
- "name": "ServiceTimeEntryCollection",
768
- "qualifiedName": "@happyvertical/smrt-timesheets:ServiceTimeEntryCollection",
769
- "collection": "servicetimeentries",
770
- "tableName": "service_time_entries",
1609
+ "name": "PeriodTimecardCollection",
1610
+ "qualifiedName": "@happyvertical/smrt-timesheets:PeriodTimecardCollection",
1611
+ "collection": "periodtimecards",
1612
+ "tableName": "period_timecards",
771
1613
  "packageName": "@happyvertical/smrt-timesheets",
772
1614
  "extends": "SmrtCollection",
773
1615
  "fields": [],
774
1616
  "relationships": [],
775
- "methods": [
776
- "forWork",
777
- "pendingApproval"
778
- ],
779
- "methodSignatures": [
780
- {
781
- "name": "forWork",
782
- "async": true,
783
- "params": [
784
- "workRefType: string",
785
- "workRefId: string"
786
- ],
787
- "returns": "Promise<ServiceTimeEntry[]>"
788
- },
789
- {
790
- "name": "pendingApproval",
791
- "async": true,
792
- "returns": "Promise<ServiceTimeEntry[]>"
793
- }
794
- ],
795
- "surfaces": [
796
- {
797
- "kind": "api",
798
- "name": "servicetimeentries.forWork",
799
- "operation": "forWork",
800
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntryCollection",
801
- "path": "/servicetimeentries/forWork",
802
- "method": "POST"
803
- },
804
- {
805
- "kind": "api",
806
- "name": "servicetimeentries.pendingApproval",
807
- "operation": "pendingApproval",
808
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntryCollection",
809
- "path": "/servicetimeentries/pendingApproval",
810
- "method": "POST"
811
- },
812
- {
813
- "kind": "cli",
814
- "name": "servicetimeentrycollection_forWork",
815
- "operation": "forWork",
816
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntryCollection"
817
- },
818
- {
819
- "kind": "cli",
820
- "name": "servicetimeentrycollection_pendingApproval",
821
- "operation": "pendingApproval",
822
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntryCollection"
823
- },
824
- {
825
- "kind": "mcp",
826
- "name": "servicetimeentrycollection_forwork",
827
- "operation": "forWork",
828
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntryCollection"
829
- },
830
- {
831
- "kind": "mcp",
832
- "name": "servicetimeentrycollection_pendingapproval",
833
- "operation": "pendingApproval",
834
- "objectName": "@happyvertical/smrt-timesheets:ServiceTimeEntryCollection"
835
- }
1617
+ "methods": [],
1618
+ "surfaces": [],
1619
+ "relationshipFeatures": [
1620
+ "uuidColumns"
836
1621
  ],
1622
+ "tags": [],
1623
+ "risks": []
1624
+ },
1625
+ {
1626
+ "name": "TimecardAdjustmentCollection",
1627
+ "qualifiedName": "@happyvertical/smrt-timesheets:TimecardAdjustmentCollection",
1628
+ "collection": "timecardadjustments",
1629
+ "tableName": "timecard_adjustments",
1630
+ "packageName": "@happyvertical/smrt-timesheets",
1631
+ "extends": "SmrtCollection",
1632
+ "fields": [],
1633
+ "relationships": [],
1634
+ "methods": [],
1635
+ "surfaces": [],
837
1636
  "relationshipFeatures": [
838
1637
  "uuidColumns"
839
1638
  ],
@@ -842,6 +1641,86 @@
842
1641
  }
843
1642
  ],
844
1643
  "surfaces": [
1644
+ {
1645
+ "kind": "api",
1646
+ "name": "attendancepunches.list",
1647
+ "operation": "list",
1648
+ "objectName": "@happyvertical/smrt-timesheets:AttendancePunch",
1649
+ "path": "/attendancepunches",
1650
+ "method": "GET"
1651
+ },
1652
+ {
1653
+ "kind": "api",
1654
+ "name": "attendancepunches.get",
1655
+ "operation": "get",
1656
+ "objectName": "@happyvertical/smrt-timesheets:AttendancePunch",
1657
+ "path": "/attendancepunches/[id]",
1658
+ "method": "GET"
1659
+ },
1660
+ {
1661
+ "kind": "cli",
1662
+ "name": "attendancepunch_list",
1663
+ "operation": "list",
1664
+ "objectName": "@happyvertical/smrt-timesheets:AttendancePunch"
1665
+ },
1666
+ {
1667
+ "kind": "cli",
1668
+ "name": "attendancepunch_get",
1669
+ "operation": "get",
1670
+ "objectName": "@happyvertical/smrt-timesheets:AttendancePunch"
1671
+ },
1672
+ {
1673
+ "kind": "mcp",
1674
+ "name": "attendancepunch_list",
1675
+ "operation": "list",
1676
+ "objectName": "@happyvertical/smrt-timesheets:AttendancePunch"
1677
+ },
1678
+ {
1679
+ "kind": "mcp",
1680
+ "name": "attendancepunch_get",
1681
+ "operation": "get",
1682
+ "objectName": "@happyvertical/smrt-timesheets:AttendancePunch"
1683
+ },
1684
+ {
1685
+ "kind": "api",
1686
+ "name": "attendancebreaks.list",
1687
+ "operation": "list",
1688
+ "objectName": "@happyvertical/smrt-timesheets:AttendanceBreak",
1689
+ "path": "/attendancebreaks",
1690
+ "method": "GET"
1691
+ },
1692
+ {
1693
+ "kind": "api",
1694
+ "name": "attendancebreaks.get",
1695
+ "operation": "get",
1696
+ "objectName": "@happyvertical/smrt-timesheets:AttendanceBreak",
1697
+ "path": "/attendancebreaks/[id]",
1698
+ "method": "GET"
1699
+ },
1700
+ {
1701
+ "kind": "cli",
1702
+ "name": "attendancebreak_list",
1703
+ "operation": "list",
1704
+ "objectName": "@happyvertical/smrt-timesheets:AttendanceBreak"
1705
+ },
1706
+ {
1707
+ "kind": "cli",
1708
+ "name": "attendancebreak_get",
1709
+ "operation": "get",
1710
+ "objectName": "@happyvertical/smrt-timesheets:AttendanceBreak"
1711
+ },
1712
+ {
1713
+ "kind": "mcp",
1714
+ "name": "attendancebreak_list",
1715
+ "operation": "list",
1716
+ "objectName": "@happyvertical/smrt-timesheets:AttendanceBreak"
1717
+ },
1718
+ {
1719
+ "kind": "mcp",
1720
+ "name": "attendancebreak_get",
1721
+ "operation": "get",
1722
+ "objectName": "@happyvertical/smrt-timesheets:AttendanceBreak"
1723
+ },
845
1724
  {
846
1725
  "kind": "api",
847
1726
  "name": "servicechargesnapshots.list",
@@ -1005,12 +1884,19 @@
1005
1884
  ],
1006
1885
  "prompts": [],
1007
1886
  "relationshipsV2": {
1008
- "foreignKeyFields": 3,
1009
- "crossPackageRefFields": 4,
1887
+ "foreignKeyFields": 6,
1888
+ "crossPackageRefFields": 9,
1010
1889
  "junctionCollections": 0,
1011
1890
  "hierarchicalObjects": 0,
1012
1891
  "polymorphicAssociations": 0,
1013
- "uuidColumns": 26
1892
+ "uuidColumns": 62
1014
1893
  },
1015
- "agentDoc": "# smrt-timesheets\n\nShared time entries: who (a `smrt-profiles` Profile, or an agent) worked how\nlong on what (a generic work reference), whether it was approved, and the\nimmutable charge / compensation snapshots taken at approval. Moved out of\n`smrt-projects` / `smrt-support` in #3288 so shops, builders, and service\ndesks share one model instead of re-implementing it.\n\nThis package is **layer 1 (entry)**. Attendance (punches, breaks, offline\nreplay) and period rollup (per-person timecards) are planned as later modules\nof this same package; do not add them to projects or support.\n\n## Models\n\n| Model | Table | Notes |\n|---|---|---|\n| `ServiceTimeEntry` | `service_time_entries` | `workRefType` + `workRefId`, `participantKind` (`human` \\| `agent`), `participantProfileId` / `agentRef`, `source`, `startedAt` / `endedAt` / `durationSeconds`, status machine, `correctionOfId` |\n| `ServiceChargeSnapshot` | `service_charge_snapshots` | Client charge, integer minor units (#2401), one per entry |\n| `ServiceCompensationSnapshot` | `service_compensation_snapshots` | Provider earning, integer minor units, one per entry |\n\n`ServiceEvidenceService` records, submits, approves (writing both snapshots\nthrough a `ServiceCommercialResolver`), and corrects. `smrt-projects` supplies\n`SubscriptionServiceCommercialResolver` for #1925 pricing.\n\n## Invariants\n\n- **No domain foreign key on the base.** Work context is the generic\n `workRefType` (qualified class name) + `workRefId`. A domain adds its own\n context by subclassing over the same table — smrt-support's\n `ServiceTimeEntry` adds `caseId` / `specialistId` and extends\n `frozenFieldNames()` so they freeze on approval.\n- **Entries carry no rate.** Money lives only on the snapshots, `= 0`\n integer initializers (INTEGER columns). Never `= 0.0`. Snapshot `save()`\n rejects an `amount` that is not a safe integer (`VALIDATION_INVALID_VALUE`),\n so SQLite cannot silently store `19.99`; fix a fractional resolver at its\n source rather than rounding here.\n- **Approved evidence never changes.** `save()` enforces\n `SERVICE_TIME_ENTRY_STATUS_TRANSITIONS` and compares the frozen fields with\n the stored row. A correction is a new row (`correctionOfId`), the original\n flips to `corrected`. Snapshots are immutable after their first save.\n- **Old qualified names are aliases.** Each model declares its pre-#3288\n `@happyvertical/smrt-projects:*` name in `previousQualifiedNames` (#3338;\n `packages/core/agents/model-moves.md`). smrt-projects must never list these\n classes in its manifests again (`CONFIG_QUALIFIED_NAME_ALIAS_COLLISION`),\n and no subtype (smrt-support's, or a consumer's closing subclass) may\n redeclare an alias (two claimants). Known gap: a same-named subtype that\n replaces a moved class drops that class's alias, and the replaced class's\n own `@happyvertical/smrt-timesheets:*` name stops resolving too — guidance\n for apps with smrt-support must name `@happyvertical/smrt-support:ServiceTimeEntry`.\n Support's vitest environment keeps both classes registered, so verify this\n against built packages, not package tests. `projects/src/__tests__/legacy-qualified-identity.test.ts` pins\n the projects-only contract.\n- **Table names are a compatibility contract.** `service_time_entries` and the\n two snapshot tables hold existing production rows from smrt-projects /\n smrt-support; renaming any of them, or adding a discriminator, is a data\n migration.\n\n## One table family\n\nClasses may share a table only as one inheritance chain, and the registry\nresolves a chain of same-named classes by \"child wins\" on the simple name.\nThat works for exactly one subtype level per table (base → subtype); a third\nsame-named level makes the middle class look like it extends its own child on\nthe manifest path (`CONFIG_TABLE_NAME_COLLISION`). Therefore:\n\n- `smrt-projects` **re-exports** these classes (no projects subclass).\n- `smrt-support` subclasses `ServiceTimeEntry` directly from this package.\n- A consumer that needs its own surface (e.g. teamworks-os closing every\n generated route with `api: { include: [] }` and\n `@TenantScoped({ mode: 'required' })`) declares a same-named subclass over\n `service_time_entries`; its manifest entry replaces the package's. It cannot\n also install smrt-support's subtype on the same table.\n The same applies to both snapshots;\n `src/__tests__/consumer-closed-surface.test.ts` holds that contract for all\n three models. The snapshots' explicit `time_entry_id` conflict key is not\n rewritten when a consumer requires tenancy; widening it is the consumer's\n schema change, never a package default.\n\nSubclasses restate their fields: package-isolated manifest scanning does not\nread dependency sources, so an unrestated subclass manifest has no columns.\n\n## Svelte UI\n\n`./svelte` exports `TimeEntryCard`, `TimeEntryList`, `TimeSummary`,\n`DurationDisplay`, and `TimeEntryApprovalQueue` (props-driven, plain view\nobjects, `smrt-ui` primitives, `smrtRawPrimitives: \"strict\"`). smrt-projects\nand smrt-support re-export them from their own `./svelte` subpaths.\nCard/list/summary message keys keep their `projects.*` namespace: tenant\nlanguage overrides are stored by key, and renaming would orphan them. New\nkeys use `timesheets.*`.\n\n## Validation\n\n```sh\npnpm --filter @happyvertical/smrt-timesheets test\npnpm --filter @happyvertical/smrt-timesheets test:postgres\npnpm --filter @happyvertical/smrt-timesheets typecheck\npnpm --filter @happyvertical/smrt-timesheets build\npnpm --filter @happyvertical/smrt-projects test\npnpm --filter @happyvertical/smrt-support test\n```\n\nSchema-affecting edits must keep `service-time-entry-compat.test.ts` (projects,\nsupport) and `service-time-entry-migration-plan.test.ts` (support) green: a\npre-move table must plan no DDL.\n"
1894
+ "agentDoc": "# smrt-timesheets\n\nShared time entries: who (a `smrt-profiles` Profile, or an agent) worked how\nlong on what (a generic work reference), whether it was approved, and the\nimmutable charge / compensation snapshots taken at approval. Moved out of\n`smrt-projects` / `smrt-support` in #3288 so shops, builders, and service\ndesks share one model instead of re-implementing it.\n\nThis package contains **layer 1 (entry)**, **layer 2 (attendance)**, and\n**layer 3 (period rollup)**.\n`src/attendance/` owns punches, breaks, atomic transitions and durable offline\nreceipts; `./attendance` is the public subpath. Period rollup belongs in this\npackage too, never projects or support. See the README attendance contract.\nAttendance services accept trusted session actors, serialize mutations per\nactor, and bind every write to one executor. The new tables use non-null unique\nopen slots, not nullable unique keys. A linked entry is draft evidence, and\nrollups must deduplicate `AttendancePunch.serviceTimeEntryId`.\n\n## Models\n\n| Model | Table | Notes |\n|---|---|---|\n| `ServiceTimeEntry` | `service_time_entries` | `workRefType` + `workRefId`, `participantKind` (`human` \\| `agent`), `participantProfileId` / `agentRef`, `source`, `startedAt` / `endedAt` / `durationSeconds`, status machine, `correctionOfId` |\n| `ServiceChargeSnapshot` | `service_charge_snapshots` | Client charge, integer minor units (#2401), one per entry |\n| `ServiceCompensationSnapshot` | `service_compensation_snapshots` | Provider earning, integer minor units, one per entry |\n\n`ServiceEvidenceService` records, submits, approves (writing both snapshots\nthrough a `ServiceCommercialResolver`), and corrects. `smrt-projects` supplies\n`SubscriptionServiceCommercialResolver` for #1925 pricing.\n\n## Invariants\n\n- **No domain foreign key on the base.** Work context is the generic\n `workRefType` (qualified class name) + `workRefId`. A domain adds its own\n context by subclassing over the same table — smrt-support's\n `ServiceTimeEntry` adds `caseId` / `specialistId` and extends\n `frozenFieldNames()` so they freeze on approval.\n- **Entries carry no rate.** Money lives only on the snapshots, `= 0`\n integer initializers (INTEGER columns). Never `= 0.0`. Snapshot `save()`\n rejects an `amount` that is not a safe integer (`VALIDATION_INVALID_VALUE`),\n so SQLite cannot silently store `19.99`; fix a fractional resolver at its\n source rather than rounding here.\n- **Approved evidence never changes.** `save()` enforces\n `SERVICE_TIME_ENTRY_STATUS_TRANSITIONS` and compares the frozen fields with\n the stored row. A correction is a new row (`correctionOfId`), the original\n flips to `corrected`. Snapshots are immutable after their first save.\n- **Old qualified names are aliases.** Each model declares its pre-#3288\n `@happyvertical/smrt-projects:*` name in `previousQualifiedNames` (#3338;\n `packages/core/agents/model-moves.md`). smrt-projects must never list these\n classes in its manifests again (`CONFIG_QUALIFIED_NAME_ALIAS_COLLISION`),\n and no subtype (smrt-support's, or a consumer's closing subclass) may\n redeclare an alias (two claimants). Known gap: a same-named subtype that\n replaces a moved class drops that class's alias, and the replaced class's\n own `@happyvertical/smrt-timesheets:*` name stops resolving too — guidance\n for apps with smrt-support must name `@happyvertical/smrt-support:ServiceTimeEntry`.\n Support's vitest environment keeps both classes registered, so verify this\n against built packages, not package tests. `projects/src/__tests__/legacy-qualified-identity.test.ts` pins\n the projects-only contract.\n- **Table names are a compatibility contract.** `service_time_entries` and the\n two snapshot tables hold existing production rows from smrt-projects /\n smrt-support; renaming any of them, or adding a discriminator, is a data\n migration.\n\n## One table family\n\nClasses may share a table only as one inheritance chain. Core resolves\nsame-named subclasses by constructor ancestry at runtime and qualified manifest\nancestry at build registration; the deepest subtype wins across N levels.\nSibling or unrelated types cannot share the table. `smrt-projects` re-exports\nthe base; `smrt-support` subclasses it directly.\n\nConsumers closing package routes should call\n`ObjectRegistry.registerOverride(qualifiedName, { api: false, mcp: false,\ncli: false, tenancy: { mode: 'required' } })` after importing the model and before\nconstructing transports. This tightens the existing registration without a new\nsubtype. See core's README for startup order, static route generation, and reset\nsemantics. `src/__tests__/consumer-closed-surface.test.ts` also covers existing\nmanifest subclass consumers. The snapshots' explicit `time_entry_id` conflict\nkey is not rewritten when a consumer requires tenancy; widening it remains a\nconsumer schema change.\n\nSubclasses restate their fields: package-isolated manifest scanning does not\nread dependency sources, so an unrestated subclass manifest has no columns.\n\n## Svelte UI\n\n`./svelte` exports `TimeEntryCard`, `TimeEntryList`, `TimeSummary`,\n`DurationDisplay`, and `TimeEntryApprovalQueue` (props-driven, plain view\nobjects, `smrt-ui` primitives, `smrtRawPrimitives: \"strict\"`). smrt-projects\nand smrt-support re-export them from their own `./svelte` subpaths.\nCard/list/summary message keys keep their `projects.*` namespace: tenant\nlanguage overrides are stored by key, and renaming would orphan them. New\nkeys use `timesheets.*`.\n\n## Validation\n\n```sh\npnpm --filter @happyvertical/smrt-timesheets test\npnpm --filter @happyvertical/smrt-timesheets test:postgres\npnpm --filter @happyvertical/smrt-timesheets typecheck\npnpm --filter @happyvertical/smrt-timesheets build\npnpm --filter @happyvertical/smrt-projects test\npnpm --filter @happyvertical/smrt-support test\n```\n\nSchema-affecting edits must keep `service-time-entry-compat.test.ts` (projects,\nsupport) and `service-time-entry-migration-plan.test.ts` (support) green: a\npre-move table must plan no DDL.\n\n## Period rollup\n\nLayer 3 lives under `src/rollup/` and the `./rollup` subpath. See\n[period-rollup.md](agents/period-rollup.md) for resolver, source clipping,\nconfirmation, attributed adjustments, isolation, and transaction contracts.\nTimecards and adjustments have closed generated surfaces and service-only\nmodel writes; never bypass the instance capability with generic persistence.\n",
1895
+ "moduleDocs": [
1896
+ {
1897
+ "path": "agents/period-rollup.md",
1898
+ "module": "period-rollup",
1899
+ "content": "# Period timecards\n\n`@happyvertical/smrt-timesheets/rollup` exports `PeriodRollupService`,\n`PeriodTimecard`, `TimecardAdjustment`, their collections, and resolver types.\nThe package root also exports them. SQLite and PostgreSQL are supported.\nCreate application tables through normal migrations; neither service provisions\nschema. The attendance option additionally requires the attendance tables.\n\nConstruct a service only after authenticating and authorizing its trusted\n`{ tenantId, profileId }` scope. A conflicting ambient tenant is rejected.\n`options.actorProfileId` records a separately authorized supervisor; it defaults\nto the subject profile for self confirmation/correction. Never accept this\ntrusted scope or attribution unchecked from request input. Profile authorization\nis consumer-owned; the service filters every source/card/adjustment read by its\ntrusted subject and tenant. Generic API, CLI and MCP surfaces are closed by\ndefault; consumer registry overrides may further restrict them (#3318).\n\n## Resolver contract\n\n`periodFor(at, actor)` supplies half-open UTC `startsAt`/`endsAt`, an IANA\n`timezone`, a nonempty policy `version`, and a JSON `rules` snapshot.\nThe consumer owns period length, calendar start day, timezone and DST, overtime\nthresholds, holidays and classification. The requested instant must be inside\nthe window. Overlapping windows for existing cards are rejected: introduce a new\ncalendar at a boundary after existing windows, and use adjustments for already\nconfirmed periods.\n\n`classify(period, sources, actor)` returns nonnegative safe integer\n`regularSeconds` and `overtimeSeconds`, whose sum must equal source seconds.\nInputs are detached so resolver mutation cannot rewrite evidence. Resolver\nexceptions, malformed windows, invalid timezone, fractional/unsafe totals and\nnonconserving classification abort the transaction. No Alberta or other\njurisdiction rule is assumed, and no pay rate or money is stored.\n\nA configurable UTC calendar example (illustrative policy, not payroll advice):\n\n```ts\nimport { PeriodRollupService, type PeriodRulesResolver } from\n '@happyvertical/smrt-timesheets/rollup';\n\nconst settings = {\n lengthDays: 14, startDay: 1, timezone: 'UTC', // 0 = Sunday\n anchor: '2026-01-05T00:00:00Z', // aligned Monday; anchors fortnight phase\n thresholdSeconds: 80 * 3600,\n holidays: ['2026-12-25'],\n};\nconst resolver: PeriodRulesResolver = {\n async periodFor(at) {\n const anchor = new Date(settings.anchor);\n if (anchor.getUTCDay() !== settings.startDay || settings.timezone !== 'UTC')\n throw new Error('Use a timezone-aware calendar resolver for local periods');\n const length = settings.lengthDays * 86400000;\n const start = anchor.getTime() +\n Math.floor((at.getTime() - anchor.getTime()) / length) * length;\n return {\n startsAt: new Date(start), endsAt: new Date(start + length),\n timezone: settings.timezone, version: 'shop-policy-v1', rules: settings,\n };\n },\n async classify(period, sources) {\n const rules = period.rules as typeof settings;\n // This example assigns a contribution to its clipped start's UTC date.\n // Local daily rules should split contributions at their own local midnight.\n let regular = 0;\n let holiday = 0;\n for (const source of sources) {\n if (rules.holidays.includes(source.startsAt.slice(0, 10))) holiday += source.seconds;\n else regular += source.seconds;\n }\n return {\n regularSeconds: Math.min(regular, rules.thresholdSeconds),\n overtimeSeconds: holiday + Math.max(0, regular - rules.thresholdSeconds),\n };\n },\n};\nconst rollups = new PeriodRollupService(db, authorizedSubject, resolver,\n { attendance: true, actorProfileId: authenticatedSupervisorProfileId });\nconst card = await rollups.rollup(new Date());\nawait rollups.confirm(card.id!);\nawait rollups.adjust(card.id!, {\n operationId: requestId, regularSeconds: 900, overtimeSeconds: 0,\n reason: 'Approved correction after confirmation',\n});\nconst effectiveSeconds = await rollups.totals(card.id!);\n```\n\nA timezone-aware resolver must compute each local boundary separately: a local\nday crossing DST is not necessarily 86400 seconds. Resolvers can use an app's\nexisting calendar library; no new timezone dependency or implicit default is\nintroduced here.\n\n## Evidence and immutability\n\nOnly approved human `ServiceTimeEntry` rows for the subject count; corrected\nancestors do not. Correction chains must remain within that subject/tenant and\npoint to corrected parents. Multiple approved descendants of one root are\nrejected as ambiguous rather than double-counted. Entries with both `startedAt`\nand `endedAt` allocate their declared seconds\nproportionally across the period using exact integer prefix division, preserving\nseconds over adjacent periods. Unbounded entries count at `startedAt`, or, when\nabsent, `approvedAt`; an end-only timestamp does not create an interval. Missing\nboth attribution timestamps is an error. This is time attribution, not a\nclaim that a manual entry has a continuous wall-clock duration.\n\nWith `attendance: true`, closed punches without `reviewRequired` count, excluding\nunpaid breaks and retaining paid breaks. Open/review-required punches do not\ncount. Linked attendance is authoritative: its evidence entry and any approved\ncorrection descendants are excluded, including when the punch is still under\nreview or outside the requested period. Unlinked approved work entries and\nattendance both count; consumers must link overlapping evidence explicitly.\nSource snapshots preserve each paid attendance segment and entry identity.\n\nRepeated rollup updates one open card per tenant/person/start; a confirmed card\ncannot be recomputed. Confirmation is attributed and idempotent. Model save,\ncollection create/update/upsert and object/collection delete cannot bypass the\nservice. Model mutation capabilities are per-instance and not exported.\nDirect SQL is a trusted administrative boundary, not an exposed application API.\nProfile/card foreign keys restrict deletion to preserve history.\n\nAdjustments contain signed integer regular/overtime deltas, reason, operation\nkey and actor attribution. A retry reuses its row only for the exact same\npayload and actor. Effective totals may never become negative or unsafe.\nAdjustments never alter the confirmed row or source snapshot. Undo an adjustment\nwith a separately attributed compensating adjustment, never deletion.\n\nAll service mutations use a root transaction, transaction-bound collections,\nembedded writer serialization or a PostgreSQL tenant/person advisory lock.\nOutputs are reloaded on the root executor after commit. Rollup reads are an\napplication snapshot: subsequent source approvals/corrections appear on the\nnext open rollup, and confirmed cards require explicit adjustments.\n"
1900
+ }
1901
+ ]
1016
1902
  }