@happyvertical/smrt-timesheets 0.0.0-stage → 0.53.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +105 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +7 -0
- package/README.md +242 -2
- package/dist/__smrt-register__.d.ts +2 -0
- package/dist/__smrt-register__.d.ts.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +495 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.json +1412 -0
- package/dist/models/index.d.ts +3 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/json.d.ts +6 -0
- package/dist/models/json.d.ts.map +1 -0
- package/dist/models/service-snapshots.d.ts +66 -0
- package/dist/models/service-snapshots.d.ts.map +1 -0
- package/dist/models/service-time-entry.d.ts +66 -0
- package/dist/models/service-time-entry.d.ts.map +1 -0
- package/dist/services/index.d.ts +2 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/service-evidence-service.d.ts +67 -0
- package/dist/services/service-evidence-service.d.ts.map +1 -0
- package/dist/smrt-knowledge.json +1016 -0
- package/dist/svelte/components/DurationDisplay.svelte +81 -0
- package/dist/svelte/components/DurationDisplay.svelte.d.ts +20 -0
- package/dist/svelte/components/DurationDisplay.svelte.d.ts.map +1 -0
- package/dist/svelte/components/TimeEntryApprovalQueue.svelte +253 -0
- package/dist/svelte/components/TimeEntryApprovalQueue.svelte.d.ts +15 -0
- package/dist/svelte/components/TimeEntryApprovalQueue.svelte.d.ts.map +1 -0
- package/dist/svelte/components/TimeEntryCard.svelte +304 -0
- package/dist/svelte/components/TimeEntryCard.svelte.d.ts +25 -0
- package/dist/svelte/components/TimeEntryCard.svelte.d.ts.map +1 -0
- package/dist/svelte/components/TimeEntryList.svelte +360 -0
- package/dist/svelte/components/TimeEntryList.svelte.d.ts +24 -0
- package/dist/svelte/components/TimeEntryList.svelte.d.ts.map +1 -0
- package/dist/svelte/components/TimeSummary.svelte +176 -0
- package/dist/svelte/components/TimeSummary.svelte.d.ts +30 -0
- package/dist/svelte/components/TimeSummary.svelte.d.ts.map +1 -0
- package/dist/svelte/components/__tests__/DurationDisplay.test.js +57 -0
- package/dist/svelte/components/__tests__/TimeEntryApprovalQueue.test.js +114 -0
- package/dist/svelte/components/__tests__/TimeEntryCard.test.js +45 -0
- package/dist/svelte/components/__tests__/TimeEntryList.test.js +50 -0
- package/dist/svelte/components/__tests__/TimeSummary.test.js +39 -0
- package/dist/svelte/components/utils.d.ts +51 -0
- package/dist/svelte/components/utils.d.ts.map +1 -0
- package/dist/svelte/components/utils.js +58 -0
- package/dist/svelte/i18n.d.ts +31 -0
- package/dist/svelte/i18n.d.ts.map +1 -0
- package/dist/svelte/i18n.js +31 -0
- package/dist/svelte/index.d.ts +25 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +27 -0
- package/dist/svelte/types.d.ts +41 -0
- package/dist/svelte/types.d.ts.map +1 -0
- package/dist/svelte/types.js +28 -0
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/dist/ui.d.ts +17 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +68 -0
- package/dist/ui.js.map +1 -0
- package/package.json +85 -3
package/AGENTS.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# smrt-timesheets
|
|
2
|
+
|
|
3
|
+
Shared time entries: who (a `smrt-profiles` Profile, or an agent) worked how
|
|
4
|
+
long on what (a generic work reference), whether it was approved, and the
|
|
5
|
+
immutable charge / compensation snapshots taken at approval. Moved out of
|
|
6
|
+
`smrt-projects` / `smrt-support` in #3288 so shops, builders, and service
|
|
7
|
+
desks share one model instead of re-implementing it.
|
|
8
|
+
|
|
9
|
+
This package is **layer 1 (entry)**. Attendance (punches, breaks, offline
|
|
10
|
+
replay) and period rollup (per-person timecards) are planned as later modules
|
|
11
|
+
of this same package; do not add them to projects or support.
|
|
12
|
+
|
|
13
|
+
## Models
|
|
14
|
+
|
|
15
|
+
| Model | Table | Notes |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| `ServiceTimeEntry` | `service_time_entries` | `workRefType` + `workRefId`, `participantKind` (`human` \| `agent`), `participantProfileId` / `agentRef`, `source`, `startedAt` / `endedAt` / `durationSeconds`, status machine, `correctionOfId` |
|
|
18
|
+
| `ServiceChargeSnapshot` | `service_charge_snapshots` | Client charge, integer minor units (#2401), one per entry |
|
|
19
|
+
| `ServiceCompensationSnapshot` | `service_compensation_snapshots` | Provider earning, integer minor units, one per entry |
|
|
20
|
+
|
|
21
|
+
`ServiceEvidenceService` records, submits, approves (writing both snapshots
|
|
22
|
+
through a `ServiceCommercialResolver`), and corrects. `smrt-projects` supplies
|
|
23
|
+
`SubscriptionServiceCommercialResolver` for #1925 pricing.
|
|
24
|
+
|
|
25
|
+
## Invariants
|
|
26
|
+
|
|
27
|
+
- **No domain foreign key on the base.** Work context is the generic
|
|
28
|
+
`workRefType` (qualified class name) + `workRefId`. A domain adds its own
|
|
29
|
+
context by subclassing over the same table — smrt-support's
|
|
30
|
+
`ServiceTimeEntry` adds `caseId` / `specialistId` and extends
|
|
31
|
+
`frozenFieldNames()` so they freeze on approval.
|
|
32
|
+
- **Entries carry no rate.** Money lives only on the snapshots, `= 0`
|
|
33
|
+
integer initializers (INTEGER columns). Never `= 0.0`. Snapshot `save()`
|
|
34
|
+
rejects an `amount` that is not a safe integer (`VALIDATION_INVALID_VALUE`),
|
|
35
|
+
so SQLite cannot silently store `19.99`; fix a fractional resolver at its
|
|
36
|
+
source rather than rounding here.
|
|
37
|
+
- **Approved evidence never changes.** `save()` enforces
|
|
38
|
+
`SERVICE_TIME_ENTRY_STATUS_TRANSITIONS` and compares the frozen fields with
|
|
39
|
+
the stored row. A correction is a new row (`correctionOfId`), the original
|
|
40
|
+
flips to `corrected`. Snapshots are immutable after their first save.
|
|
41
|
+
- **Old qualified names are aliases.** Each model declares its pre-#3288
|
|
42
|
+
`@happyvertical/smrt-projects:*` name in `previousQualifiedNames` (#3338;
|
|
43
|
+
`packages/core/agents/model-moves.md`). smrt-projects must never list these
|
|
44
|
+
classes in its manifests again (`CONFIG_QUALIFIED_NAME_ALIAS_COLLISION`),
|
|
45
|
+
and no subtype (smrt-support's, or a consumer's closing subclass) may
|
|
46
|
+
redeclare an alias (two claimants). Known gap: a same-named subtype that
|
|
47
|
+
replaces a moved class drops that class's alias, and the replaced class's
|
|
48
|
+
own `@happyvertical/smrt-timesheets:*` name stops resolving too — guidance
|
|
49
|
+
for apps with smrt-support must name `@happyvertical/smrt-support:ServiceTimeEntry`.
|
|
50
|
+
Support's vitest environment keeps both classes registered, so verify this
|
|
51
|
+
against built packages, not package tests. `projects/src/__tests__/legacy-qualified-identity.test.ts` pins
|
|
52
|
+
the projects-only contract.
|
|
53
|
+
- **Table names are a compatibility contract.** `service_time_entries` and the
|
|
54
|
+
two snapshot tables hold existing production rows from smrt-projects /
|
|
55
|
+
smrt-support; renaming any of them, or adding a discriminator, is a data
|
|
56
|
+
migration.
|
|
57
|
+
|
|
58
|
+
## One table family
|
|
59
|
+
|
|
60
|
+
Classes may share a table only as one inheritance chain, and the registry
|
|
61
|
+
resolves a chain of same-named classes by "child wins" on the simple name.
|
|
62
|
+
That works for exactly one subtype level per table (base → subtype); a third
|
|
63
|
+
same-named level makes the middle class look like it extends its own child on
|
|
64
|
+
the manifest path (`CONFIG_TABLE_NAME_COLLISION`). Therefore:
|
|
65
|
+
|
|
66
|
+
- `smrt-projects` **re-exports** these classes (no projects subclass).
|
|
67
|
+
- `smrt-support` subclasses `ServiceTimeEntry` directly from this package.
|
|
68
|
+
- A consumer that needs its own surface (e.g. teamworks-os closing every
|
|
69
|
+
generated route with `api: { include: [] }` and
|
|
70
|
+
`@TenantScoped({ mode: 'required' })`) declares a same-named subclass over
|
|
71
|
+
`service_time_entries`; its manifest entry replaces the package's. It cannot
|
|
72
|
+
also install smrt-support's subtype on the same table.
|
|
73
|
+
The same applies to both snapshots;
|
|
74
|
+
`src/__tests__/consumer-closed-surface.test.ts` holds that contract for all
|
|
75
|
+
three models. The snapshots' explicit `time_entry_id` conflict key is not
|
|
76
|
+
rewritten when a consumer requires tenancy; widening it is the consumer's
|
|
77
|
+
schema change, never a package default.
|
|
78
|
+
|
|
79
|
+
Subclasses restate their fields: package-isolated manifest scanning does not
|
|
80
|
+
read dependency sources, so an unrestated subclass manifest has no columns.
|
|
81
|
+
|
|
82
|
+
## Svelte UI
|
|
83
|
+
|
|
84
|
+
`./svelte` exports `TimeEntryCard`, `TimeEntryList`, `TimeSummary`,
|
|
85
|
+
`DurationDisplay`, and `TimeEntryApprovalQueue` (props-driven, plain view
|
|
86
|
+
objects, `smrt-ui` primitives, `smrtRawPrimitives: "strict"`). smrt-projects
|
|
87
|
+
and smrt-support re-export them from their own `./svelte` subpaths.
|
|
88
|
+
Card/list/summary message keys keep their `projects.*` namespace: tenant
|
|
89
|
+
language overrides are stored by key, and renaming would orphan them. New
|
|
90
|
+
keys use `timesheets.*`.
|
|
91
|
+
|
|
92
|
+
## Validation
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
pnpm --filter @happyvertical/smrt-timesheets test
|
|
96
|
+
pnpm --filter @happyvertical/smrt-timesheets test:postgres
|
|
97
|
+
pnpm --filter @happyvertical/smrt-timesheets typecheck
|
|
98
|
+
pnpm --filter @happyvertical/smrt-timesheets build
|
|
99
|
+
pnpm --filter @happyvertical/smrt-projects test
|
|
100
|
+
pnpm --filter @happyvertical/smrt-support test
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Schema-affecting edits must keep `service-time-entry-compat.test.ts` (projects,
|
|
104
|
+
support) and `service-time-entry-migration-plan.test.ts` (support) green: a
|
|
105
|
+
pre-move table must plan no DDL.
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright <2025> <Happy Vertical Corporation>
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,243 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @happyvertical/smrt-timesheets
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Shared time entries for s-m-r-t: who worked how long on what, whether someone
|
|
4
|
+
approved it, and what it was charged and paid at approval. One model for
|
|
5
|
+
professional services, shop floors, and job sites, instead of one per vertical.
|
|
6
|
+
|
|
7
|
+
- **Who** — a `smrt-profiles` Profile (`participantKind: 'human'`) or an agent
|
|
8
|
+
(`participantKind: 'agent'`, `agentRef`).
|
|
9
|
+
- **What** — a generic work reference: `workRefType` (a qualified class name)
|
|
10
|
+
and `workRefId`. No domain-specific foreign key on the base entry.
|
|
11
|
+
- **How long** — `startedAt`, `endedAt`, `durationSeconds`, and the `source`
|
|
12
|
+
(`timer`, `manual`, `import`, `agent`).
|
|
13
|
+
- **Approval** — `draft → submitted → approved | rejected`; approved entries
|
|
14
|
+
never change. A correction is a new row whose `correctionOfId` points at the
|
|
15
|
+
entry it corrects, which flips to `corrected`.
|
|
16
|
+
- **Money** — never on the entry. Approval writes one immutable
|
|
17
|
+
`ServiceChargeSnapshot` and one `ServiceCompensationSnapshot`, in integer
|
|
18
|
+
minor units (`$19.99` is `1999`), consistent with
|
|
19
|
+
[`smrt-commerce`](../commerce/README.md).
|
|
20
|
+
|
|
21
|
+
See [AGENTS.md](./AGENTS.md) for invariants and extension rules.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm add @happyvertical/smrt-timesheets
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Add `svelte` for the optional UI components. Application schemas are created
|
|
30
|
+
by migrations (`smrt db:migrate`); the package never creates tables at
|
|
31
|
+
runtime.
|
|
32
|
+
|
|
33
|
+
## Record, approve, and correct time
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { ServiceEvidenceService } from '@happyvertical/smrt-timesheets';
|
|
37
|
+
|
|
38
|
+
const timesheets = await ServiceEvidenceService.create({ db }, {
|
|
39
|
+
// Your pricing and pay rules; amounts are integer minor units.
|
|
40
|
+
priceClient: async (entry) => ({
|
|
41
|
+
amount: Math.round(entry.durationHours() * 9500),
|
|
42
|
+
version: 'rates-2026',
|
|
43
|
+
terms: { hourlyRate: 9500 },
|
|
44
|
+
}),
|
|
45
|
+
compensateProvider: async (entry) => ({
|
|
46
|
+
amount: Math.round(entry.durationHours() * 6000),
|
|
47
|
+
version: 'pay-2026',
|
|
48
|
+
terms: { hourlyRate: 6000 },
|
|
49
|
+
}),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const entry = await timesheets.record({
|
|
53
|
+
workRefType: '@acme/jobs:WorkPackage',
|
|
54
|
+
workRefId: 'wp-7',
|
|
55
|
+
participantKind: 'human',
|
|
56
|
+
participantProfileId: profile.id,
|
|
57
|
+
source: 'timer',
|
|
58
|
+
description: 'Framed the north wall',
|
|
59
|
+
startedAt: new Date('2026-07-01T08:00:00Z'),
|
|
60
|
+
endedAt: new Date('2026-07-01T10:30:00Z'),
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
await timesheets.submit(entry, profile.id);
|
|
64
|
+
await timesheets.approve(entry, { approvalPath: 'operator' });
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`record()` rejects a missing or half work reference, a human entry without a
|
|
68
|
+
Profile, an agent entry without `agentRef`, a reversed period, and a
|
|
69
|
+
non-positive duration. `correct(entry, input)` records the replacement and
|
|
70
|
+
marks the approved entry `corrected`.
|
|
71
|
+
|
|
72
|
+
## Svelte components
|
|
73
|
+
|
|
74
|
+
```svelte
|
|
75
|
+
<script lang="ts">
|
|
76
|
+
import { TimeEntryList, TimeSummary } from '@happyvertical/smrt-timesheets/svelte';
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<TimeSummary totalHours={12.5} totalAmount={118750} currency="CAD" />
|
|
80
|
+
<TimeEntryList {entries} selectable />
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`TimeEntryCard`, `TimeEntryList`, `TimeSummary`, `DurationDisplay`, and
|
|
84
|
+
`TimeEntryApprovalQueue` are props-driven: hosts load entries and pass plain
|
|
85
|
+
view objects (`TimeEntry`, `TimeEntryApprovalView`).
|
|
86
|
+
|
|
87
|
+
## Closing the generated surface
|
|
88
|
+
|
|
89
|
+
The entry and both snapshots expose generated `list` / `get` on REST, CLI,
|
|
90
|
+
and MCP, with optional tenant scoping. An application that routes all time
|
|
91
|
+
and money through its own permission-gated services declares a same-named
|
|
92
|
+
subclass over each table and closes it:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import {
|
|
96
|
+
ServiceChargeSnapshot as SharedServiceChargeSnapshot,
|
|
97
|
+
ServiceCompensationSnapshot as SharedServiceCompensationSnapshot,
|
|
98
|
+
ServiceTimeEntry as SharedServiceTimeEntry,
|
|
99
|
+
} from '@happyvertical/smrt-timesheets';
|
|
100
|
+
|
|
101
|
+
const CLOSED = { include: [] };
|
|
102
|
+
|
|
103
|
+
@TenantScoped({ mode: 'required' })
|
|
104
|
+
@smrt({
|
|
105
|
+
tableName: 'service_time_entries',
|
|
106
|
+
api: CLOSED,
|
|
107
|
+
cli: CLOSED,
|
|
108
|
+
mcp: CLOSED,
|
|
109
|
+
})
|
|
110
|
+
export class ServiceTimeEntry extends SharedServiceTimeEntry {
|
|
111
|
+
// restate the fields — see AGENTS.md
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@TenantScoped({ mode: 'required' })
|
|
115
|
+
@smrt({
|
|
116
|
+
tableName: 'service_charge_snapshots',
|
|
117
|
+
conflictColumns: ['time_entry_id'],
|
|
118
|
+
api: CLOSED,
|
|
119
|
+
cli: CLOSED,
|
|
120
|
+
mcp: CLOSED,
|
|
121
|
+
})
|
|
122
|
+
export class ServiceChargeSnapshot extends SharedServiceChargeSnapshot {
|
|
123
|
+
// restate the fields — see AGENTS.md
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
@TenantScoped({ mode: 'required' })
|
|
127
|
+
@smrt({
|
|
128
|
+
tableName: 'service_compensation_snapshots',
|
|
129
|
+
conflictColumns: ['time_entry_id'],
|
|
130
|
+
api: CLOSED,
|
|
131
|
+
cli: CLOSED,
|
|
132
|
+
mcp: CLOSED,
|
|
133
|
+
})
|
|
134
|
+
export class ServiceCompensationSnapshot extends SharedServiceCompensationSnapshot {
|
|
135
|
+
// restate the fields — see AGENTS.md
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Do not copy `previousQualifiedNames` into these subclasses: an old name may
|
|
140
|
+
have only one claimant. Replacing the timesheets classes drops their
|
|
141
|
+
smrt-projects aliases (see the known gap under "Stored and declared class
|
|
142
|
+
names").
|
|
143
|
+
|
|
144
|
+
Restate `conflictColumns` exactly as shown unless you mean to change it. The
|
|
145
|
+
snapshots' conflict key is `time_entry_id` alone — one snapshot per entry —
|
|
146
|
+
and, being an explicit key, it is never rewritten to lead with `tenant_id`
|
|
147
|
+
when you require tenancy. That is safe as long as entry ids are unique across
|
|
148
|
+
tenants (they are UUIDs). Widening it to `['tenant_id', 'time_entry_id']` is
|
|
149
|
+
your decision, and it is a schema change for your database (a new unique
|
|
150
|
+
index replacing `service_*_snapshots_time_entry_id_idx`), so it goes through
|
|
151
|
+
`smrt db:migrate` like any other key change; the package default stays
|
|
152
|
+
`['time_entry_id']`.
|
|
153
|
+
|
|
154
|
+
## Migrating from smrt-projects / smrt-support
|
|
155
|
+
|
|
156
|
+
`ServiceTimeEntry`, its collection, `ServiceChargeSnapshot`,
|
|
157
|
+
`ServiceCompensationSnapshot`, their collections, and
|
|
158
|
+
`ServiceEvidenceService` moved here in #3288.
|
|
159
|
+
|
|
160
|
+
**Consumers already holding `service_time_entries` rows need no schema change
|
|
161
|
+
and no data migration.** The table names, columns, indexes, and conflict keys
|
|
162
|
+
are unchanged, and the tables carry no type discriminator, so existing rows
|
|
163
|
+
load through every package's classes as they are. References stored under
|
|
164
|
+
the old smrt-projects class names keep resolving as deprecated aliases (see
|
|
165
|
+
"Stored and declared class names" below; one gap applies with smrt-support).
|
|
166
|
+
|
|
167
|
+
> **pnpm: add a direct `@happyvertical/smrt-timesheets` dependency.** The
|
|
168
|
+
> CLI's manifest discovery (`smrt db:migrate`, `db:status`, `db:diff`) reads
|
|
169
|
+
> only packages installed at the top level of `node_modules`. Under pnpm a
|
|
170
|
+
> transitive dependency is not there, so an application that depends on
|
|
171
|
+
> smrt-projects or smrt-support but not on smrt-timesheets stops planning
|
|
172
|
+
> `service_time_entries`, `service_charge_snapshots`, and
|
|
173
|
+
> `service_compensation_snapshots`: a fresh database never gets them (and
|
|
174
|
+
> `ServiceEvidenceService` then fails the runtime table check), and an
|
|
175
|
+
> existing one reports them as orphan tables. Add
|
|
176
|
+
> `pnpm add @happyvertical/smrt-timesheets`. npm and Yarn hoist the package
|
|
177
|
+
> and are unaffected.
|
|
178
|
+
|
|
179
|
+
| Before | After |
|
|
180
|
+
|---|---|
|
|
181
|
+
| `@happyvertical/smrt-projects` / `@happyvertical/smrt-support` in `dependencies` | Also add `@happyvertical/smrt-timesheets` under pnpm, or the CLI stops planning the three time tables (see the note above) |
|
|
182
|
+
| `ServiceTimeEntry`, `ServiceEvidenceService`, snapshots from `@happyvertical/smrt-projects` | Same names, still exported from smrt-projects (re-exports); new code imports `@happyvertical/smrt-timesheets` |
|
|
183
|
+
| `ServiceTimeEntry` from `@happyvertical/smrt-support` | Unchanged: support's subtype, now extending the timesheets entry |
|
|
184
|
+
| `caseId` / `specialistId`, `forCase()` / `forSpecialist()` on the projects export | Support subtype only — import `ServiceTimeEntry` / `ServiceTimeEntryCollection` from smrt-support |
|
|
185
|
+
| `ServiceEvidenceService.record({ caseId })` | Requires `workRefType` + `workRefId`; record case time through smrt-support's `ServiceTimeEntryService` |
|
|
186
|
+
| `@happyvertical/smrt-projects:ServiceTimeEntry` (and the two snapshot names) stored in `meta_type` or declared in `@crossPackageRef` / playbook `model:` | Resolves as a deprecated alias of `@happyvertical/smrt-timesheets:*`; move declarations to the class that is registered in your app — `@happyvertical/smrt-timesheets:*`, except `@happyvertical/smrt-support:ServiceTimeEntry` when smrt-support is installed (or your own closing subclass) — and optionally backfill stored rows with `smrt db:migrate-qualified-names` (see below) |
|
|
187
|
+
| `TimeEntryList`, `TimeEntryCard`, `TimeSummary`, `DurationDisplay` from `@happyvertical/smrt-projects/svelte`; `TimeEntryApprovalQueue` from `@happyvertical/smrt-support/svelte` | Still exported there; canonical home `@happyvertical/smrt-timesheets/svelte` |
|
|
188
|
+
|
|
189
|
+
An application with smrt-projects but not smrt-support keeps its existing
|
|
190
|
+
`case_id` / `specialist_id` columns: `db:migrate` reports them as orphan
|
|
191
|
+
columns and never alters or drops them, and saves through the shared entry
|
|
192
|
+
leave their values untouched.
|
|
193
|
+
|
|
194
|
+
### Stored and declared class names
|
|
195
|
+
|
|
196
|
+
The moved models' registered names changed from
|
|
197
|
+
`@happyvertical/smrt-projects:*` to `@happyvertical/smrt-timesheets:*`. Each
|
|
198
|
+
class declares its old name in `previousQualifiedNames` (#3338), so references
|
|
199
|
+
that stored or declared it keep resolving as a **deprecated alias**:
|
|
200
|
+
polymorphic association rows (`metaType`, including smrt-assets
|
|
201
|
+
`AssetAssociation`), `ObjectRegistry.getClassByQualifiedName()`,
|
|
202
|
+
`@crossPackageRef` and relationship targets, and playbook step `model:`
|
|
203
|
+
names. The first resolution of each old name per process logs a deprecation
|
|
204
|
+
warning; new association writes store the current name. Generated routes,
|
|
205
|
+
MCP tool names, and permission slugs derive from simple and collection names
|
|
206
|
+
and are unchanged.
|
|
207
|
+
|
|
208
|
+
- `smrt doctor --db` counts stored references that still use an old name
|
|
209
|
+
("Deprecated Qualified Names").
|
|
210
|
+
- `smrt db:migrate-qualified-names` is an opt-in backfill that rewrites them
|
|
211
|
+
to the current names (`--dry-run` first); it is never run automatically.
|
|
212
|
+
- Move source references — `@crossPackageRef(...)`, relationship targets,
|
|
213
|
+
playbook `model:` names — to the name of the class your application
|
|
214
|
+
actually registers, now. That is `@happyvertical/smrt-timesheets:*`, except
|
|
215
|
+
where a same-named subclass replaces the timesheets class: with smrt-support
|
|
216
|
+
installed, reference `@happyvertical/smrt-support:ServiceTimeEntry` (the
|
|
217
|
+
timesheets name is not registered there, so a `@crossPackageRef` to it
|
|
218
|
+
fails to load and an association stored under it hydrates to `null`); with
|
|
219
|
+
your own closing subclass, reference your subclass's qualified name. The
|
|
220
|
+
snapshots keep their timesheets names unless you subclass them. The aliases
|
|
221
|
+
will be removed in a later **breaking** release, once `smrt doctor --db`
|
|
222
|
+
reports no stored references.
|
|
223
|
+
|
|
224
|
+
> **Known gap: same-named subtypes drop the alias.** A same-named subclass
|
|
225
|
+
> over a moved table — smrt-support's `ServiceTimeEntry`, or an
|
|
226
|
+
> application's closing subclass (see "Closing the generated surface") —
|
|
227
|
+
> replaces the timesheets class in the registry, and that class's alias does
|
|
228
|
+
> not carry over to it yet. With smrt-support installed,
|
|
229
|
+
> `@happyvertical/smrt-projects:ServiceTimeEntry` therefore does not resolve
|
|
230
|
+
> (hydration returns `null`) and `smrt doctor --db` /
|
|
231
|
+
> `db:migrate-qualified-names` do not see it; the snapshot aliases still work
|
|
232
|
+
> unless the application subclasses the snapshots too. A subclass must not
|
|
233
|
+
> redeclare the alias (two claimants of one old name collide). Until core
|
|
234
|
+
> carries aliases across the replacement, rewrite affected stored references
|
|
235
|
+
> (typically `meta_type` columns) to the replacing class's current name, e.g.
|
|
236
|
+
> `@happyvertical/smrt-support:ServiceTimeEntry`.
|
|
237
|
+
|
|
238
|
+
## Related packages
|
|
239
|
+
|
|
240
|
+
- [`smrt-projects`](../projects/README.md) — delivery work and
|
|
241
|
+
`SubscriptionServiceCommercialResolver` pricing for these entries.
|
|
242
|
+
- [`smrt-support`](../support/README.md) — support-case time on the same table.
|
|
243
|
+
- [`smrt-profiles`](../profiles/README.md) — the participants.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"__smrt-register__.d.ts","sourceRoot":"","sources":["../src/__smrt-register__.ts"],"names":[],"mappings":""}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @happyvertical/smrt-timesheets
|
|
3
|
+
*
|
|
4
|
+
* Shared time entries: who (a smrt-profiles Profile or an agent) worked how
|
|
5
|
+
* long on what (a generic work reference), approval and correction, and the
|
|
6
|
+
* immutable charge / compensation snapshots taken at approval.
|
|
7
|
+
*
|
|
8
|
+
* `smrt-projects` re-exports all of these classes unchanged under their
|
|
9
|
+
* existing names. `smrt-support` subclasses only `ServiceTimeEntry` (adding
|
|
10
|
+
* `caseId` / `specialistId`) over the same table; the snapshots and
|
|
11
|
+
* `ServiceEvidenceService` are used from this package as they are.
|
|
12
|
+
*
|
|
13
|
+
* @packageDocumentation
|
|
14
|
+
*/
|
|
15
|
+
import './__smrt-register__.js';
|
|
16
|
+
export * from './models/index.js';
|
|
17
|
+
export * from './services/index.js';
|
|
18
|
+
export { SERVICE_TIME_ENTRY_STATUS_TRANSITIONS, type ServiceEvidence, type ServiceParticipantKind, type ServiceTimeEntrySource, type ServiceTimeEntryStatus, } from './types.js';
|
|
19
|
+
export { TIMESHEETS_MODULE_META, TIMESHEETS_UI_SLOTS } from './ui.js';
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,wBAAwB,CAAC;AAEhC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,OAAO,EACL,qCAAqC,EACrC,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,GAC5B,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC"}
|