@contractspec/example.service-business-os 1.57.0 → 1.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/dist/browser/client/client.operations.js +72 -0
  2. package/dist/browser/client/client.schema.js +31 -0
  3. package/dist/browser/client/index.js +74 -0
  4. package/dist/browser/docs/index.js +96 -0
  5. package/dist/browser/docs/service-business-os.docblock.js +96 -0
  6. package/dist/browser/entities/index.js +246 -0
  7. package/dist/browser/events.js +135 -0
  8. package/dist/browser/example.js +39 -0
  9. package/dist/browser/handlers/index.js +5 -0
  10. package/dist/browser/index.js +752 -0
  11. package/dist/browser/invoice/index.js +77 -0
  12. package/dist/browser/invoice/invoice.operations.js +75 -0
  13. package/dist/browser/invoice/invoice.schema.js +34 -0
  14. package/dist/browser/job/index.js +175 -0
  15. package/dist/browser/job/job.operations.js +172 -0
  16. package/dist/browser/job/job.schema.js +41 -0
  17. package/dist/browser/operations/index.js +506 -0
  18. package/dist/browser/payment/index.js +69 -0
  19. package/dist/browser/payment/payment.operations.js +67 -0
  20. package/dist/browser/payment/payment.schema.js +30 -0
  21. package/dist/browser/presentations/index.js +13 -0
  22. package/dist/browser/presentations.js +172 -0
  23. package/dist/browser/quote/index.js +122 -0
  24. package/dist/browser/quote/quote.operations.js +119 -0
  25. package/dist/browser/quote/quote.schema.js +45 -0
  26. package/dist/browser/service-business-os.capability.js +28 -0
  27. package/dist/browser/service.feature.js +74 -0
  28. package/dist/client/client.operations.d.ts +54 -60
  29. package/dist/client/client.operations.d.ts.map +1 -1
  30. package/dist/client/client.operations.js +71 -51
  31. package/dist/client/client.schema.d.ts +54 -59
  32. package/dist/client/client.schema.d.ts.map +1 -1
  33. package/dist/client/client.schema.js +30 -75
  34. package/dist/client/index.d.ts +6 -3
  35. package/dist/client/index.d.ts.map +1 -0
  36. package/dist/client/index.js +74 -3
  37. package/dist/docs/index.d.ts +2 -1
  38. package/dist/docs/index.d.ts.map +1 -0
  39. package/dist/docs/index.js +97 -1
  40. package/dist/docs/service-business-os.docblock.d.ts +2 -1
  41. package/dist/docs/service-business-os.docblock.d.ts.map +1 -0
  42. package/dist/docs/service-business-os.docblock.js +52 -64
  43. package/dist/entities/index.d.ts +156 -161
  44. package/dist/entities/index.d.ts.map +1 -1
  45. package/dist/entities/index.js +236 -278
  46. package/dist/events.d.ts +253 -259
  47. package/dist/events.d.ts.map +1 -1
  48. package/dist/events.js +123 -217
  49. package/dist/example.d.ts +2 -6
  50. package/dist/example.d.ts.map +1 -1
  51. package/dist/example.js +38 -50
  52. package/dist/handlers/index.d.ts +11 -16
  53. package/dist/handlers/index.d.ts.map +1 -1
  54. package/dist/handlers/index.js +5 -5
  55. package/dist/index.d.ts +13 -18
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +752 -18
  58. package/dist/invoice/index.d.ts +6 -3
  59. package/dist/invoice/index.d.ts.map +1 -0
  60. package/dist/invoice/index.js +77 -3
  61. package/dist/invoice/invoice.operations.d.ts +54 -60
  62. package/dist/invoice/invoice.operations.d.ts.map +1 -1
  63. package/dist/invoice/invoice.operations.js +74 -55
  64. package/dist/invoice/invoice.schema.d.ts +54 -59
  65. package/dist/invoice/invoice.schema.d.ts.map +1 -1
  66. package/dist/invoice/invoice.schema.js +33 -75
  67. package/dist/job/index.d.ts +6 -3
  68. package/dist/job/index.d.ts.map +1 -0
  69. package/dist/job/index.js +175 -3
  70. package/dist/job/job.operations.d.ts +220 -226
  71. package/dist/job/job.operations.d.ts.map +1 -1
  72. package/dist/job/job.operations.js +167 -169
  73. package/dist/job/job.schema.d.ts +67 -72
  74. package/dist/job/job.schema.d.ts.map +1 -1
  75. package/dist/job/job.schema.js +39 -95
  76. package/dist/node/client/client.operations.js +72 -0
  77. package/dist/node/client/client.schema.js +31 -0
  78. package/dist/node/client/index.js +74 -0
  79. package/dist/node/docs/index.js +96 -0
  80. package/dist/node/docs/service-business-os.docblock.js +96 -0
  81. package/dist/node/entities/index.js +246 -0
  82. package/dist/node/events.js +135 -0
  83. package/dist/node/example.js +39 -0
  84. package/dist/node/handlers/index.js +5 -0
  85. package/dist/node/index.js +752 -0
  86. package/dist/node/invoice/index.js +77 -0
  87. package/dist/node/invoice/invoice.operations.js +75 -0
  88. package/dist/node/invoice/invoice.schema.js +34 -0
  89. package/dist/node/job/index.js +175 -0
  90. package/dist/node/job/job.operations.js +172 -0
  91. package/dist/node/job/job.schema.js +41 -0
  92. package/dist/node/operations/index.js +506 -0
  93. package/dist/node/payment/index.js +69 -0
  94. package/dist/node/payment/payment.operations.js +67 -0
  95. package/dist/node/payment/payment.schema.js +30 -0
  96. package/dist/node/presentations/index.js +13 -0
  97. package/dist/node/presentations.js +172 -0
  98. package/dist/node/quote/index.js +122 -0
  99. package/dist/node/quote/quote.operations.js +119 -0
  100. package/dist/node/quote/quote.schema.js +45 -0
  101. package/dist/node/service-business-os.capability.js +28 -0
  102. package/dist/node/service.feature.js +74 -0
  103. package/dist/operations/index.d.ts +6 -16
  104. package/dist/operations/index.d.ts.map +1 -0
  105. package/dist/operations/index.js +506 -16
  106. package/dist/payment/index.d.ts +6 -3
  107. package/dist/payment/index.d.ts.map +1 -0
  108. package/dist/payment/index.js +69 -3
  109. package/dist/payment/payment.operations.d.ts +50 -56
  110. package/dist/payment/payment.operations.d.ts.map +1 -1
  111. package/dist/payment/payment.operations.js +66 -51
  112. package/dist/payment/payment.schema.d.ts +50 -55
  113. package/dist/payment/payment.schema.d.ts.map +1 -1
  114. package/dist/payment/payment.schema.js +29 -71
  115. package/dist/presentations/index.d.ts +1 -4
  116. package/dist/presentations/index.d.ts.map +1 -1
  117. package/dist/presentations/index.js +13 -17
  118. package/dist/presentations.d.ts +7 -12
  119. package/dist/presentations.d.ts.map +1 -1
  120. package/dist/presentations.js +166 -172
  121. package/dist/quote/index.d.ts +6 -3
  122. package/dist/quote/index.d.ts.map +1 -0
  123. package/dist/quote/index.js +122 -3
  124. package/dist/quote/quote.operations.d.ts +120 -126
  125. package/dist/quote/quote.operations.d.ts.map +1 -1
  126. package/dist/quote/quote.operations.js +117 -96
  127. package/dist/quote/quote.schema.d.ts +83 -88
  128. package/dist/quote/quote.schema.d.ts.map +1 -1
  129. package/dist/quote/quote.schema.js +43 -111
  130. package/dist/service-business-os.capability.d.ts +2 -7
  131. package/dist/service-business-os.capability.d.ts.map +1 -1
  132. package/dist/service-business-os.capability.js +29 -29
  133. package/dist/service.feature.d.ts +1 -6
  134. package/dist/service.feature.d.ts.map +1 -1
  135. package/dist/service.feature.js +73 -164
  136. package/package.json +301 -64
  137. package/dist/client/client.operations.js.map +0 -1
  138. package/dist/client/client.schema.js.map +0 -1
  139. package/dist/docs/service-business-os.docblock.js.map +0 -1
  140. package/dist/entities/index.js.map +0 -1
  141. package/dist/events.js.map +0 -1
  142. package/dist/example.js.map +0 -1
  143. package/dist/handlers/index.js.map +0 -1
  144. package/dist/invoice/invoice.operations.js.map +0 -1
  145. package/dist/invoice/invoice.schema.js.map +0 -1
  146. package/dist/job/job.operations.js.map +0 -1
  147. package/dist/job/job.schema.js.map +0 -1
  148. package/dist/payment/payment.operations.js.map +0 -1
  149. package/dist/payment/payment.schema.js.map +0 -1
  150. package/dist/presentations/index.js.map +0 -1
  151. package/dist/presentations.js.map +0 -1
  152. package/dist/quote/quote.operations.js.map +0 -1
  153. package/dist/quote/quote.schema.js.map +0 -1
  154. package/dist/service-business-os.capability.js.map +0 -1
  155. package/dist/service.feature.js.map +0 -1
@@ -0,0 +1,72 @@
1
+ // src/client/client.schema.ts
2
+ import { defineSchemaModel, ScalarTypeEnum } from "@contractspec/lib.schema";
3
+ var ClientModel = defineSchemaModel({
4
+ name: "Client",
5
+ description: "Client profile",
6
+ fields: {
7
+ id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
8
+ name: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
9
+ contactEmail: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
10
+ phone: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
11
+ orgId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
12
+ ownerId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
13
+ createdAt: { type: ScalarTypeEnum.DateTime(), isOptional: false }
14
+ }
15
+ });
16
+ var CreateClientInputModel = defineSchemaModel({
17
+ name: "CreateClientInput",
18
+ description: "Input for creating a client",
19
+ fields: {
20
+ name: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
21
+ contactEmail: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
22
+ phone: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
23
+ orgId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
24
+ ownerId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
25
+ metadata: { type: ScalarTypeEnum.JSON(), isOptional: true }
26
+ }
27
+ });
28
+
29
+ // src/client/client.operations.ts
30
+ import { defineCommand } from "@contractspec/lib.contracts";
31
+ var OWNERS = ["@examples.service-business-os"];
32
+ var CreateClientContract = defineCommand({
33
+ meta: {
34
+ key: "service.client.create",
35
+ version: "1.0.0",
36
+ stability: "stable",
37
+ owners: [...OWNERS],
38
+ tags: ["service-business-os", "client", "create"],
39
+ description: "Create a new client.",
40
+ goal: "Onboard clients.",
41
+ context: "CRM."
42
+ },
43
+ io: {
44
+ input: CreateClientInputModel,
45
+ output: ClientModel
46
+ },
47
+ policy: { auth: "user" },
48
+ acceptance: {
49
+ scenarios: [
50
+ {
51
+ key: "create-client-happy-path",
52
+ given: ["User is authenticated"],
53
+ when: ["User creates a new client"],
54
+ then: ["Client is created"]
55
+ }
56
+ ],
57
+ examples: [
58
+ {
59
+ key: "create-basic",
60
+ input: {
61
+ name: "Acme Corp",
62
+ email: "contact@acme.com",
63
+ phone: "555-0123"
64
+ },
65
+ output: { id: "client-123", name: "Acme Corp" }
66
+ }
67
+ ]
68
+ }
69
+ });
70
+ export {
71
+ CreateClientContract
72
+ };
@@ -0,0 +1,31 @@
1
+ // src/client/client.schema.ts
2
+ import { defineSchemaModel, ScalarTypeEnum } from "@contractspec/lib.schema";
3
+ var ClientModel = defineSchemaModel({
4
+ name: "Client",
5
+ description: "Client profile",
6
+ fields: {
7
+ id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
8
+ name: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
9
+ contactEmail: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
10
+ phone: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
11
+ orgId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
12
+ ownerId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
13
+ createdAt: { type: ScalarTypeEnum.DateTime(), isOptional: false }
14
+ }
15
+ });
16
+ var CreateClientInputModel = defineSchemaModel({
17
+ name: "CreateClientInput",
18
+ description: "Input for creating a client",
19
+ fields: {
20
+ name: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
21
+ contactEmail: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
22
+ phone: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
23
+ orgId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
24
+ ownerId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
25
+ metadata: { type: ScalarTypeEnum.JSON(), isOptional: true }
26
+ }
27
+ });
28
+ export {
29
+ CreateClientInputModel,
30
+ ClientModel
31
+ };
@@ -0,0 +1,74 @@
1
+ // src/client/client.schema.ts
2
+ import { defineSchemaModel, ScalarTypeEnum } from "@contractspec/lib.schema";
3
+ var ClientModel = defineSchemaModel({
4
+ name: "Client",
5
+ description: "Client profile",
6
+ fields: {
7
+ id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
8
+ name: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
9
+ contactEmail: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
10
+ phone: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
11
+ orgId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
12
+ ownerId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
13
+ createdAt: { type: ScalarTypeEnum.DateTime(), isOptional: false }
14
+ }
15
+ });
16
+ var CreateClientInputModel = defineSchemaModel({
17
+ name: "CreateClientInput",
18
+ description: "Input for creating a client",
19
+ fields: {
20
+ name: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
21
+ contactEmail: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
22
+ phone: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
23
+ orgId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
24
+ ownerId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
25
+ metadata: { type: ScalarTypeEnum.JSON(), isOptional: true }
26
+ }
27
+ });
28
+
29
+ // src/client/client.operations.ts
30
+ import { defineCommand } from "@contractspec/lib.contracts";
31
+ var OWNERS = ["@examples.service-business-os"];
32
+ var CreateClientContract = defineCommand({
33
+ meta: {
34
+ key: "service.client.create",
35
+ version: "1.0.0",
36
+ stability: "stable",
37
+ owners: [...OWNERS],
38
+ tags: ["service-business-os", "client", "create"],
39
+ description: "Create a new client.",
40
+ goal: "Onboard clients.",
41
+ context: "CRM."
42
+ },
43
+ io: {
44
+ input: CreateClientInputModel,
45
+ output: ClientModel
46
+ },
47
+ policy: { auth: "user" },
48
+ acceptance: {
49
+ scenarios: [
50
+ {
51
+ key: "create-client-happy-path",
52
+ given: ["User is authenticated"],
53
+ when: ["User creates a new client"],
54
+ then: ["Client is created"]
55
+ }
56
+ ],
57
+ examples: [
58
+ {
59
+ key: "create-basic",
60
+ input: {
61
+ name: "Acme Corp",
62
+ email: "contact@acme.com",
63
+ phone: "555-0123"
64
+ },
65
+ output: { id: "client-123", name: "Acme Corp" }
66
+ }
67
+ ]
68
+ }
69
+ });
70
+ export {
71
+ CreateClientInputModel,
72
+ CreateClientContract,
73
+ ClientModel
74
+ };
@@ -0,0 +1,96 @@
1
+ // src/docs/service-business-os.docblock.ts
2
+ import { registerDocBlocks } from "@contractspec/lib.contracts/docs";
3
+ var serviceBusinessDocBlocks = [
4
+ {
5
+ id: "docs.examples.service-business-os",
6
+ title: "Service Business OS",
7
+ summary: "Field/service business flow from client intake to quote, job scheduling, invoicing, and payments with notifications and audit trail.",
8
+ kind: "reference",
9
+ visibility: "public",
10
+ route: "/docs/examples/service-business-os",
11
+ tags: ["services", "quotes", "jobs", "invoices", "payments"],
12
+ body: `## Flows
13
+
14
+ 1) **Client intake** → create client, capture contact + owner.
15
+ 2) **Quote** → draft, send, accept/reject (events + notifications).
16
+ 3) **Job** → schedule, assign technician, complete with notes and attachments.
17
+ 4) **Invoice** → issue after completion, track status.
18
+ 5) **Payment** → record payment and emit analytics/audit.
19
+
20
+ ## Modules reused
21
+ - Identity/RBAC for org + roles
22
+ - Files for attachments (proposals, receipts)
23
+ - Notifications for quote sent/accepted, job reminders, overdue invoices
24
+ - Jobs for reminder/schedule tasks
25
+ - Audit trail for all lifecycle changes
26
+
27
+ ## Presentations
28
+ - Dashboard, client list, quote list/detail, job board, invoice list, payment list (React + Markdown targets).
29
+ `
30
+ },
31
+ {
32
+ id: "docs.examples.service-business-os.goal",
33
+ title: "Service Business OS — Goal",
34
+ summary: "Why this field-service OS exists and outcomes it targets.",
35
+ kind: "goal",
36
+ visibility: "public",
37
+ route: "/docs/examples/service-business-os/goal",
38
+ tags: ["services", "goal"],
39
+ body: `## Why it matters
40
+ - Provides a regenerable, end-to-end service lifecycle (client → quote → job → invoice → payment).
41
+ - Keeps pricing, scheduling, invoicing, and payments consistent across surfaces.
42
+
43
+ ## Business/Product goal
44
+ - Deliver auditable quotes/jobs/invoices with notifications and reminders.
45
+ - Support attachments and PII-safe flows; stage new payment rules via feature flags.
46
+
47
+ ## Success criteria
48
+ - Spec changes regenerate UI/API/events cleanly across lifecycle steps.
49
+ - Audit/Notifications/Jobs remain wired for every mutation.`
50
+ },
51
+ {
52
+ id: "docs.examples.service-business-os.usage",
53
+ title: "Service Business OS — Usage",
54
+ summary: "How to operate, extend, and regenerate the service OS safely.",
55
+ kind: "usage",
56
+ visibility: "public",
57
+ route: "/docs/examples/service-business-os/usage",
58
+ tags: ["services", "usage"],
59
+ body: `## Setup
60
+ 1) Seed (if provided) or create client → quote → job → invoice → payment via UI.
61
+ 2) Configure Files for attachments and Notifications for quote/job/invoice events.
62
+
63
+ ## Extend & regenerate
64
+ 1) Adjust schemas: quote line items, job statuses, invoice terms, payment methods.
65
+ 2) Regenerate to sync UI/API/events; mark PII paths in policy.
66
+ 3) Use Feature Flags to trial new payment rules or reminder cadences.
67
+
68
+ ## Guardrails
69
+ - Emit events for quote accepted/rejected, job scheduled/completed, invoice overdue, payment recorded.
70
+ - Keep pricing/tax rules explicit in spec; avoid implicit handler math.
71
+ - Use Audit Trail for lifecycle mutations; schedule reminders via Jobs.`
72
+ },
73
+ {
74
+ id: "docs.examples.service-business-os.constraints",
75
+ title: "Service Business OS — Constraints & Safety",
76
+ summary: "Internal guardrails for quotes/jobs/invoices/payments and regeneration safety.",
77
+ kind: "reference",
78
+ visibility: "internal",
79
+ route: "/docs/examples/service-business-os/constraints",
80
+ tags: ["services", "constraints", "internal"],
81
+ body: `## Constraints
82
+ - Commission/tax/payment rules must be explicit in spec; no hidden handler math.
83
+ - Events to emit: quote.sent/accepted/rejected, job.scheduled/completed, invoice.issued/overdue, payment.recorded.
84
+ - Regeneration must not alter payment semantics without reviewed spec changes.
85
+
86
+ ## PII & Attachments
87
+ - Mark PII paths (client contact, address); redact in markdown/JSON.
88
+ - Files (quotes, receipts) should use presigned URLs with scoped access.
89
+
90
+ ## Verification
91
+ - Add fixtures for quote/job/invoice state transitions.
92
+ - Ensure Notifications/Audit/Jobs wiring persists after regeneration.
93
+ - Use Feature Flags to trial new payment rules/reminder cadences; default safe/off.`
94
+ }
95
+ ];
96
+ registerDocBlocks(serviceBusinessDocBlocks);
@@ -0,0 +1,96 @@
1
+ // src/docs/service-business-os.docblock.ts
2
+ import { registerDocBlocks } from "@contractspec/lib.contracts/docs";
3
+ var serviceBusinessDocBlocks = [
4
+ {
5
+ id: "docs.examples.service-business-os",
6
+ title: "Service Business OS",
7
+ summary: "Field/service business flow from client intake to quote, job scheduling, invoicing, and payments with notifications and audit trail.",
8
+ kind: "reference",
9
+ visibility: "public",
10
+ route: "/docs/examples/service-business-os",
11
+ tags: ["services", "quotes", "jobs", "invoices", "payments"],
12
+ body: `## Flows
13
+
14
+ 1) **Client intake** → create client, capture contact + owner.
15
+ 2) **Quote** → draft, send, accept/reject (events + notifications).
16
+ 3) **Job** → schedule, assign technician, complete with notes and attachments.
17
+ 4) **Invoice** → issue after completion, track status.
18
+ 5) **Payment** → record payment and emit analytics/audit.
19
+
20
+ ## Modules reused
21
+ - Identity/RBAC for org + roles
22
+ - Files for attachments (proposals, receipts)
23
+ - Notifications for quote sent/accepted, job reminders, overdue invoices
24
+ - Jobs for reminder/schedule tasks
25
+ - Audit trail for all lifecycle changes
26
+
27
+ ## Presentations
28
+ - Dashboard, client list, quote list/detail, job board, invoice list, payment list (React + Markdown targets).
29
+ `
30
+ },
31
+ {
32
+ id: "docs.examples.service-business-os.goal",
33
+ title: "Service Business OS — Goal",
34
+ summary: "Why this field-service OS exists and outcomes it targets.",
35
+ kind: "goal",
36
+ visibility: "public",
37
+ route: "/docs/examples/service-business-os/goal",
38
+ tags: ["services", "goal"],
39
+ body: `## Why it matters
40
+ - Provides a regenerable, end-to-end service lifecycle (client → quote → job → invoice → payment).
41
+ - Keeps pricing, scheduling, invoicing, and payments consistent across surfaces.
42
+
43
+ ## Business/Product goal
44
+ - Deliver auditable quotes/jobs/invoices with notifications and reminders.
45
+ - Support attachments and PII-safe flows; stage new payment rules via feature flags.
46
+
47
+ ## Success criteria
48
+ - Spec changes regenerate UI/API/events cleanly across lifecycle steps.
49
+ - Audit/Notifications/Jobs remain wired for every mutation.`
50
+ },
51
+ {
52
+ id: "docs.examples.service-business-os.usage",
53
+ title: "Service Business OS — Usage",
54
+ summary: "How to operate, extend, and regenerate the service OS safely.",
55
+ kind: "usage",
56
+ visibility: "public",
57
+ route: "/docs/examples/service-business-os/usage",
58
+ tags: ["services", "usage"],
59
+ body: `## Setup
60
+ 1) Seed (if provided) or create client → quote → job → invoice → payment via UI.
61
+ 2) Configure Files for attachments and Notifications for quote/job/invoice events.
62
+
63
+ ## Extend & regenerate
64
+ 1) Adjust schemas: quote line items, job statuses, invoice terms, payment methods.
65
+ 2) Regenerate to sync UI/API/events; mark PII paths in policy.
66
+ 3) Use Feature Flags to trial new payment rules or reminder cadences.
67
+
68
+ ## Guardrails
69
+ - Emit events for quote accepted/rejected, job scheduled/completed, invoice overdue, payment recorded.
70
+ - Keep pricing/tax rules explicit in spec; avoid implicit handler math.
71
+ - Use Audit Trail for lifecycle mutations; schedule reminders via Jobs.`
72
+ },
73
+ {
74
+ id: "docs.examples.service-business-os.constraints",
75
+ title: "Service Business OS — Constraints & Safety",
76
+ summary: "Internal guardrails for quotes/jobs/invoices/payments and regeneration safety.",
77
+ kind: "reference",
78
+ visibility: "internal",
79
+ route: "/docs/examples/service-business-os/constraints",
80
+ tags: ["services", "constraints", "internal"],
81
+ body: `## Constraints
82
+ - Commission/tax/payment rules must be explicit in spec; no hidden handler math.
83
+ - Events to emit: quote.sent/accepted/rejected, job.scheduled/completed, invoice.issued/overdue, payment.recorded.
84
+ - Regeneration must not alter payment semantics without reviewed spec changes.
85
+
86
+ ## PII & Attachments
87
+ - Mark PII paths (client contact, address); redact in markdown/JSON.
88
+ - Files (quotes, receipts) should use presigned URLs with scoped access.
89
+
90
+ ## Verification
91
+ - Add fixtures for quote/job/invoice state transitions.
92
+ - Ensure Notifications/Audit/Jobs wiring persists after regeneration.
93
+ - Use Feature Flags to trial new payment rules/reminder cadences; default safe/off.`
94
+ }
95
+ ];
96
+ registerDocBlocks(serviceBusinessDocBlocks);
@@ -0,0 +1,246 @@
1
+ // src/entities/index.ts
2
+ import {
3
+ defineEntity,
4
+ defineEntityEnum,
5
+ field,
6
+ index
7
+ } from "@contractspec/lib.schema";
8
+ var schema = "lssm_service_os";
9
+ var QuoteStatusEnum = defineEntityEnum({
10
+ name: "QuoteStatus",
11
+ schema,
12
+ values: ["DRAFT", "SENT", "ACCEPTED", "REJECTED", "EXPIRED"],
13
+ description: "Lifecycle for quotes/proposals."
14
+ });
15
+ var JobStatusEnum = defineEntityEnum({
16
+ name: "JobStatus",
17
+ schema,
18
+ values: ["SCHEDULED", "IN_PROGRESS", "COMPLETED", "CANCELLED"],
19
+ description: "Lifecycle for service jobs/interventions."
20
+ });
21
+ var InvoiceStatusEnum = defineEntityEnum({
22
+ name: "InvoiceStatus",
23
+ schema,
24
+ values: ["DRAFT", "SENT", "PAID", "OVERDUE", "CANCELLED"],
25
+ description: "Lifecycle for invoices."
26
+ });
27
+ var PaymentMethodEnum = defineEntityEnum({
28
+ name: "PaymentMethod",
29
+ schema,
30
+ values: ["CARD", "BANK_TRANSFER", "CASH", "CHECK"],
31
+ description: "Payment method used."
32
+ });
33
+ var ClientEntity = defineEntity({
34
+ name: "Client",
35
+ description: "Customer organization or individual.",
36
+ schema,
37
+ map: "client",
38
+ fields: {
39
+ id: field.id({ description: "Unique client identifier" }),
40
+ name: field.string({ description: "Client display name" }),
41
+ contactEmail: field.string({
42
+ description: "Primary contact email",
43
+ isOptional: true
44
+ }),
45
+ phone: field.string({ description: "Primary phone", isOptional: true }),
46
+ address: field.json({ description: "Mailing address", isOptional: true }),
47
+ industry: field.string({
48
+ description: "Industry/vertical",
49
+ isOptional: true
50
+ }),
51
+ orgId: field.string({ description: "Owning organization" }),
52
+ ownerId: field.string({ description: "Account owner" }),
53
+ metadata: field.json({
54
+ description: "Additional metadata",
55
+ isOptional: true
56
+ }),
57
+ createdAt: field.createdAt(),
58
+ updatedAt: field.updatedAt(),
59
+ quotes: field.hasMany("Quote"),
60
+ jobs: field.hasMany("Job")
61
+ },
62
+ indexes: [index.on(["orgId"]), index.on(["ownerId"]), index.on(["name"])]
63
+ });
64
+ var QuoteEntity = defineEntity({
65
+ name: "Quote",
66
+ description: "Proposal/quote for a job.",
67
+ schema,
68
+ map: "quote",
69
+ fields: {
70
+ id: field.id({ description: "Unique quote identifier" }),
71
+ clientId: field.foreignKey({ description: "Client receiving quote" }),
72
+ title: field.string({ description: "Quote title" }),
73
+ description: field.string({
74
+ description: "Work summary",
75
+ isOptional: true
76
+ }),
77
+ amount: field.float({ description: "Total quoted amount" }),
78
+ currency: field.string({ description: "Currency code", default: '"USD"' }),
79
+ status: field.enum("QuoteStatus", {
80
+ description: "Quote status",
81
+ default: "DRAFT"
82
+ }),
83
+ validUntil: field.dateTime({
84
+ description: "Expiration date",
85
+ isOptional: true
86
+ }),
87
+ terms: field.string({
88
+ description: "Payment/engagement terms",
89
+ isOptional: true
90
+ }),
91
+ orgId: field.string({ description: "Owning organization" }),
92
+ ownerId: field.string({ description: "Account owner" }),
93
+ createdAt: field.createdAt(),
94
+ updatedAt: field.updatedAt(),
95
+ client: field.belongsTo("Client", ["clientId"], ["id"], {
96
+ onDelete: "Cascade"
97
+ }),
98
+ jobs: field.hasMany("Job")
99
+ },
100
+ enums: [QuoteStatusEnum],
101
+ indexes: [
102
+ index.on(["orgId", "status"]),
103
+ index.on(["clientId"]),
104
+ index.on(["validUntil"])
105
+ ]
106
+ });
107
+ var JobEntity = defineEntity({
108
+ name: "Job",
109
+ description: "Service job/intervention derived from an accepted quote.",
110
+ schema,
111
+ map: "job",
112
+ fields: {
113
+ id: field.id({ description: "Unique job identifier" }),
114
+ quoteId: field.foreignKey({ description: "Source quote" }),
115
+ clientId: field.foreignKey({ description: "Client receiving service" }),
116
+ title: field.string({ description: "Job title" }),
117
+ status: field.enum("JobStatus", {
118
+ description: "Job status",
119
+ default: "SCHEDULED"
120
+ }),
121
+ scheduledAt: field.dateTime({
122
+ description: "Scheduled start date/time",
123
+ isOptional: true
124
+ }),
125
+ completedAt: field.dateTime({
126
+ description: "Completion timestamp",
127
+ isOptional: true
128
+ }),
129
+ assignedTo: field.string({
130
+ description: "Assignee/technician user ID",
131
+ isOptional: true
132
+ }),
133
+ location: field.json({ description: "Location details", isOptional: true }),
134
+ notes: field.string({ description: "Internal notes", isOptional: true }),
135
+ orgId: field.string({ description: "Owning organization" }),
136
+ createdAt: field.createdAt(),
137
+ updatedAt: field.updatedAt(),
138
+ quote: field.belongsTo("Quote", ["quoteId"], ["id"], {
139
+ onDelete: "SetNull"
140
+ }),
141
+ client: field.belongsTo("Client", ["clientId"], ["id"], {
142
+ onDelete: "Cascade"
143
+ }),
144
+ invoices: field.hasMany("Invoice")
145
+ },
146
+ enums: [JobStatusEnum],
147
+ indexes: [
148
+ index.on(["orgId", "status"]),
149
+ index.on(["clientId"]),
150
+ index.on(["assignedTo", "status"]),
151
+ index.on(["scheduledAt"])
152
+ ]
153
+ });
154
+ var InvoiceEntity = defineEntity({
155
+ name: "Invoice",
156
+ description: "Invoice issued for a completed job.",
157
+ schema,
158
+ map: "invoice",
159
+ fields: {
160
+ id: field.id({ description: "Unique invoice identifier" }),
161
+ jobId: field.foreignKey({ description: "Related job" }),
162
+ invoiceNumber: field.string({
163
+ description: "Invoice number",
164
+ isUnique: true
165
+ }),
166
+ amount: field.decimal({ description: "Invoice amount" }),
167
+ currency: field.string({ description: "Currency code", default: '"USD"' }),
168
+ status: field.enum("InvoiceStatus", {
169
+ description: "Invoice status",
170
+ default: "DRAFT"
171
+ }),
172
+ dueDate: field.dateTime({ description: "Due date", isOptional: true }),
173
+ issuedAt: field.dateTime({
174
+ description: "Issued timestamp",
175
+ isOptional: true
176
+ }),
177
+ paidAt: field.dateTime({ description: "Paid timestamp", isOptional: true }),
178
+ orgId: field.string({ description: "Owning organization" }),
179
+ notes: field.string({ description: "Invoice notes", isOptional: true }),
180
+ metadata: field.json({ description: "Metadata", isOptional: true }),
181
+ createdAt: field.createdAt(),
182
+ updatedAt: field.updatedAt(),
183
+ job: field.belongsTo("Job", ["jobId"], ["id"], { onDelete: "Cascade" }),
184
+ payments: field.hasMany("Payment")
185
+ },
186
+ enums: [InvoiceStatusEnum],
187
+ indexes: [
188
+ index.on(["invoiceNumber"]),
189
+ index.on(["orgId", "status"]),
190
+ index.on(["dueDate"])
191
+ ]
192
+ });
193
+ var PaymentEntity = defineEntity({
194
+ name: "Payment",
195
+ description: "Payment received for an invoice.",
196
+ schema,
197
+ map: "payment",
198
+ fields: {
199
+ id: field.id({ description: "Unique payment identifier" }),
200
+ invoiceId: field.foreignKey({ description: "Invoice being paid" }),
201
+ amount: field.decimal({ description: "Payment amount" }),
202
+ currency: field.string({ description: "Currency code", default: '"USD"' }),
203
+ method: field.enum("PaymentMethod", { description: "Payment method" }),
204
+ reference: field.string({
205
+ description: "Payment reference/transaction ID",
206
+ isOptional: true
207
+ }),
208
+ receivedAt: field.dateTime({ description: "When payment was received" }),
209
+ orgId: field.string({ description: "Owning organization" }),
210
+ createdAt: field.createdAt(),
211
+ invoice: field.belongsTo("Invoice", ["invoiceId"], ["id"], {
212
+ onDelete: "Cascade"
213
+ })
214
+ },
215
+ enums: [PaymentMethodEnum],
216
+ indexes: [
217
+ index.on(["invoiceId"]),
218
+ index.on(["orgId"]),
219
+ index.on(["receivedAt"])
220
+ ]
221
+ });
222
+ var serviceBusinessEntities = [
223
+ ClientEntity,
224
+ QuoteEntity,
225
+ JobEntity,
226
+ InvoiceEntity,
227
+ PaymentEntity
228
+ ];
229
+ var serviceBusinessSchemaContribution = {
230
+ moduleId: "@contractspec/example.service-business-os",
231
+ entities: serviceBusinessEntities,
232
+ enums: [QuoteStatusEnum, JobStatusEnum, InvoiceStatusEnum, PaymentMethodEnum]
233
+ };
234
+ export {
235
+ serviceBusinessSchemaContribution,
236
+ serviceBusinessEntities,
237
+ QuoteStatusEnum,
238
+ QuoteEntity,
239
+ PaymentMethodEnum,
240
+ PaymentEntity,
241
+ JobStatusEnum,
242
+ JobEntity,
243
+ InvoiceStatusEnum,
244
+ InvoiceEntity,
245
+ ClientEntity
246
+ };