@nbt-dev/nbt 0.0.1 → 0.0.4

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 (145) hide show
  1. package/LICENSE +177 -21
  2. package/README.md +16 -13
  3. package/TRADEMARKS.md +49 -0
  4. package/dist/nbt.js +398 -19
  5. package/package.json +5 -4
  6. package/stdlib/auth/README.md +83 -0
  7. package/stdlib/auth/migrations/20260424144652_initial/migration.nbt +48 -0
  8. package/stdlib/auth/migrations/20260424144652_initial/schema_snapshot.nbt +58 -0
  9. package/stdlib/auth/migrations/20260521191014_update_user/migration.nbt +3 -0
  10. package/stdlib/auth/migrations/20260521191014_update_user/schema_snapshot.nbt +59 -0
  11. package/stdlib/auth/schema.nbt +142 -0
  12. package/stdlib/calendar/adapters/gohighlevel/tests/fixtures/v2_calendar_pilot.json +12 -0
  13. package/stdlib/calendar/adapters/gohighlevel/tests/fixtures/webhooks/appointment_changed.json +70 -0
  14. package/stdlib/calendar/adapters/gohighlevel/tests/fixtures/webhooks/appointment_created.json +72 -0
  15. package/stdlib/calendar/migrations/20260501210107_initial/migration.nbt +60 -0
  16. package/stdlib/calendar/migrations/20260501210107_initial/schema_snapshot.nbt +66 -0
  17. package/stdlib/calendar/migrations/20260513151050_schema_update/migration.nbt +17 -0
  18. package/stdlib/calendar/migrations/20260513151050_schema_update/schema_snapshot.nbt +83 -0
  19. package/stdlib/calendar/schema.nbt +86 -0
  20. package/stdlib/chat/migrations/20260429222411_initial/migration.nbt +59 -0
  21. package/stdlib/chat/migrations/20260429222411_initial/schema_snapshot.nbt +71 -0
  22. package/stdlib/chat/migrations/20260430185225_add_messagereaction/migration.nbt +9 -0
  23. package/stdlib/chat/migrations/20260430185225_add_messagereaction/schema_snapshot.nbt +78 -0
  24. package/stdlib/chat/migrations/20260518191152_update_message/migration.nbt +3 -0
  25. package/stdlib/chat/migrations/20260518191152_update_message/schema_snapshot.nbt +81 -0
  26. package/stdlib/chat/schema.nbt +130 -0
  27. package/stdlib/crm/adapters/gohighlevel/README.md +85 -0
  28. package/stdlib/crm/adapters/gohighlevel/tests/README.md +159 -0
  29. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_138fields.json +222 -0
  30. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_140fields.json +219 -0
  31. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_alt.json +212 -0
  32. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_changed.json +102 -0
  33. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_created.json +95 -0
  34. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_full.json +213 -0
  35. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_sparse.json +161 -0
  36. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_update_a.json +197 -0
  37. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_update_b.json +197 -0
  38. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/opportunity_changed.json +85 -0
  39. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/opportunity_created.json +85 -0
  40. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_contact_pilot.json +43 -0
  41. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_contact_with_price_closed.json +7 -0
  42. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_contact_with_price_open.json +7 -0
  43. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_event_appointment_delete.json +1 -0
  44. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_event_calendar_update.json +1 -0
  45. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_event_contact_create.json +1 -0
  46. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_event_opp_status_update.json +1 -0
  47. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_opportunity_pilot.json +16 -0
  48. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_pipelines_pilot.json +137 -0
  49. package/stdlib/crm/migrations/20260501210107_initial/migration.nbt +63 -0
  50. package/stdlib/crm/migrations/20260501210107_initial/schema_snapshot.nbt +73 -0
  51. package/stdlib/crm/migrations/20260513151050_schema_update/migration.nbt +13 -0
  52. package/stdlib/crm/migrations/20260513151050_schema_update/schema_snapshot.nbt +86 -0
  53. package/stdlib/crm/schema.nbt +148 -0
  54. package/stdlib/design/migrations/20260501210107_initial/migration.nbt +19 -0
  55. package/stdlib/design/migrations/20260501210107_initial/schema_snapshot.nbt +21 -0
  56. package/stdlib/design/migrations/20260610130000_design_system/migration.nbt +50 -0
  57. package/stdlib/design/migrations/20260610130000_design_system/schema_snapshot.nbt +80 -0
  58. package/stdlib/design/schema.nbt +140 -0
  59. package/stdlib/dns/migrations/20260501210107_initial/migration.nbt +32 -0
  60. package/stdlib/dns/migrations/20260501210107_initial/schema_snapshot.nbt +36 -0
  61. package/stdlib/dns/schema.nbt +68 -0
  62. package/stdlib/email/migrations/20260427235207_initial/migration.nbt +75 -0
  63. package/stdlib/email/migrations/20260427235207_initial/schema_snapshot.nbt +87 -0
  64. package/stdlib/email/schema.nbt +145 -0
  65. package/stdlib/ingest/README.md +29 -0
  66. package/stdlib/ingest/migrations/20260424144652_initial/migration.nbt +18 -0
  67. package/stdlib/ingest/migrations/20260424144652_initial/schema_snapshot.nbt +20 -0
  68. package/stdlib/ingest/migrations/20260429203747_schema_update/migration.nbt +3 -0
  69. package/stdlib/ingest/migrations/20260429203747_schema_update/schema_snapshot.nbt +21 -0
  70. package/stdlib/ingest/schema.nbt +37 -0
  71. package/stdlib/notifications/README.md +118 -0
  72. package/stdlib/notifications/migrations/20260430204408_initial/migration.nbt +42 -0
  73. package/stdlib/notifications/migrations/20260430204408_initial/schema_snapshot.nbt +46 -0
  74. package/stdlib/notifications/schema.nbt +67 -0
  75. package/stdlib/phone/migrations/20260605205722_initial/migration.nbt +50 -0
  76. package/stdlib/phone/migrations/20260605205722_initial/schema_snapshot.nbt +56 -0
  77. package/stdlib/phone/schema.nbt +95 -0
  78. package/stdlib/registry/migrations/20260602181932_initial/migration.nbt +8 -0
  79. package/stdlib/registry/migrations/20260602181932_initial/schema_snapshot.nbt +8 -0
  80. package/stdlib/registry/schema.nbt +20 -0
  81. package/stdlib/workflows/schema.nbt +44 -0
  82. package/vendor/linux-x64/cartridges/auth/migrations/20260424144652_initial/migration.nbt +48 -0
  83. package/vendor/linux-x64/cartridges/auth/migrations/20260424144652_initial/schema_snapshot.nbt +58 -0
  84. package/vendor/linux-x64/cartridges/auth/migrations/20260521191014_update_user/migration.nbt +3 -0
  85. package/vendor/linux-x64/cartridges/auth/migrations/20260521191014_update_user/schema_snapshot.nbt +59 -0
  86. package/vendor/linux-x64/cartridges/auth/schema.nbt +142 -0
  87. package/vendor/linux-x64/cartridges/calendar/migrations/20260501210107_initial/migration.nbt +60 -0
  88. package/vendor/linux-x64/cartridges/calendar/migrations/20260501210107_initial/schema_snapshot.nbt +66 -0
  89. package/vendor/linux-x64/cartridges/calendar/migrations/20260513151050_schema_update/migration.nbt +17 -0
  90. package/vendor/linux-x64/cartridges/calendar/migrations/20260513151050_schema_update/schema_snapshot.nbt +83 -0
  91. package/vendor/linux-x64/cartridges/calendar/schema.nbt +86 -0
  92. package/vendor/linux-x64/cartridges/chat/migrations/20260429222411_initial/migration.nbt +59 -0
  93. package/vendor/linux-x64/cartridges/chat/migrations/20260429222411_initial/schema_snapshot.nbt +71 -0
  94. package/vendor/linux-x64/cartridges/chat/migrations/20260430185225_add_messagereaction/migration.nbt +9 -0
  95. package/vendor/linux-x64/cartridges/chat/migrations/20260430185225_add_messagereaction/schema_snapshot.nbt +78 -0
  96. package/vendor/linux-x64/cartridges/chat/migrations/20260518191152_update_message/migration.nbt +3 -0
  97. package/vendor/linux-x64/cartridges/chat/migrations/20260518191152_update_message/schema_snapshot.nbt +81 -0
  98. package/vendor/linux-x64/cartridges/chat/schema.nbt +130 -0
  99. package/vendor/linux-x64/cartridges/crm/migrations/20260501210107_initial/migration.nbt +63 -0
  100. package/vendor/linux-x64/cartridges/crm/migrations/20260501210107_initial/schema_snapshot.nbt +73 -0
  101. package/vendor/linux-x64/cartridges/crm/migrations/20260513151050_schema_update/migration.nbt +13 -0
  102. package/vendor/linux-x64/cartridges/crm/migrations/20260513151050_schema_update/schema_snapshot.nbt +86 -0
  103. package/vendor/linux-x64/cartridges/crm/schema.nbt +148 -0
  104. package/vendor/linux-x64/cartridges/design/migrations/20260501210107_initial/migration.nbt +19 -0
  105. package/vendor/linux-x64/cartridges/design/migrations/20260501210107_initial/schema_snapshot.nbt +21 -0
  106. package/vendor/linux-x64/cartridges/design/migrations/20260610130000_design_system/migration.nbt +50 -0
  107. package/vendor/linux-x64/cartridges/design/migrations/20260610130000_design_system/schema_snapshot.nbt +80 -0
  108. package/vendor/linux-x64/cartridges/design/schema.nbt +140 -0
  109. package/vendor/linux-x64/cartridges/dns/migrations/20260501210107_initial/migration.nbt +32 -0
  110. package/vendor/linux-x64/cartridges/dns/migrations/20260501210107_initial/schema_snapshot.nbt +36 -0
  111. package/vendor/linux-x64/cartridges/dns/schema.nbt +68 -0
  112. package/vendor/linux-x64/cartridges/email/migrations/20260427235207_initial/migration.nbt +75 -0
  113. package/vendor/linux-x64/cartridges/email/migrations/20260427235207_initial/schema_snapshot.nbt +87 -0
  114. package/vendor/linux-x64/cartridges/email/schema.nbt +145 -0
  115. package/vendor/linux-x64/cartridges/ingest/migrations/20260424144652_initial/migration.nbt +18 -0
  116. package/vendor/linux-x64/cartridges/ingest/migrations/20260424144652_initial/schema_snapshot.nbt +20 -0
  117. package/vendor/linux-x64/cartridges/ingest/migrations/20260429203747_schema_update/migration.nbt +3 -0
  118. package/vendor/linux-x64/cartridges/ingest/migrations/20260429203747_schema_update/schema_snapshot.nbt +21 -0
  119. package/vendor/linux-x64/cartridges/ingest/schema.nbt +37 -0
  120. package/vendor/linux-x64/cartridges/notifications/migrations/20260430204408_initial/migration.nbt +42 -0
  121. package/vendor/linux-x64/cartridges/notifications/migrations/20260430204408_initial/schema_snapshot.nbt +46 -0
  122. package/vendor/linux-x64/cartridges/notifications/schema.nbt +67 -0
  123. package/vendor/linux-x64/cartridges/phone/migrations/20260605205722_initial/migration.nbt +50 -0
  124. package/vendor/linux-x64/cartridges/phone/migrations/20260605205722_initial/schema_snapshot.nbt +56 -0
  125. package/vendor/linux-x64/cartridges/phone/schema.nbt +95 -0
  126. package/vendor/linux-x64/cartridges/registry/migrations/20260602181932_initial/migration.nbt +8 -0
  127. package/vendor/linux-x64/cartridges/registry/migrations/20260602181932_initial/schema_snapshot.nbt +8 -0
  128. package/vendor/linux-x64/cartridges/registry/schema.nbt +20 -0
  129. package/vendor/linux-x64/cartridges/workflows/schema.nbt +44 -0
  130. package/vendor/linux-x64/console +0 -0
  131. package/vendor/linux-x64/nbt +0 -0
  132. package/contracts/audit/.dist/contract.json +0 -56
  133. package/contracts/auth/.dist/contract.json +0 -252
  134. package/contracts/calendar/.dist/contract.json +0 -141
  135. package/contracts/chat/.dist/contract.json +0 -229
  136. package/contracts/crm/.dist/contract.json +0 -239
  137. package/contracts/design/.dist/contract.json +0 -85
  138. package/contracts/dns/.dist/contract.json +0 -123
  139. package/contracts/email/.dist/contract.json +0 -267
  140. package/contracts/embed/.dist/contract.json +0 -137
  141. package/contracts/ingest/.dist/contract.json +0 -86
  142. package/contracts/notifications/.dist/contract.json +0 -133
  143. package/contracts/phone/.dist/contract.json +0 -168
  144. package/contracts/registry/.dist/contract.json +0 -49
  145. package/contracts/workflows/.dist/contract.json +0 -106
@@ -0,0 +1,59 @@
1
+ entity User {
2
+ name: string
3
+ username?: string
4
+ email?: string
5
+ emailVerified: bool
6
+ externalId?: string
7
+ capsVersion: u32
8
+ @@index([email])
9
+ @@index([externalId])
10
+ @@unique([email])
11
+ }
12
+
13
+ entity UserRole {
14
+ userId: string
15
+ cart: string
16
+ role: string
17
+ @@index([userId])
18
+ }
19
+
20
+ entity Session {
21
+ userId: string
22
+ token: string
23
+ expiresAt: DateTime
24
+ ipAddress?: string
25
+ userAgent?: string
26
+ @@index([token])
27
+ @@index([userId])
28
+ }
29
+
30
+ entity Account {
31
+ userId: string
32
+ providerId: string
33
+ password: string
34
+ accessToken: string
35
+ refreshToken: string
36
+ idToken: string
37
+ accessTokenExpiresAt: DateTime
38
+ refreshTokenExpiresAt: DateTime
39
+ scope: string
40
+ @@index([userId])
41
+ }
42
+
43
+ entity Verification {
44
+ identifier: string
45
+ value: string
46
+ expiresAt: DateTime
47
+ @@index([identifier])
48
+ }
49
+
50
+ entity ApiKey {
51
+ name: string
52
+ projectId: string
53
+ start: string
54
+ prefix: string
55
+ key: string
56
+ permissions: string
57
+ roles: string
58
+ }
59
+
@@ -0,0 +1,142 @@
1
+ import crypto from "crypto"
2
+
3
+ # Auth policy for the hand-written routes in native/runtime.jai (formerly the
4
+ # @public actions + the `authenticate` middleware block). These keep the
5
+ # daemon's public-route + middleware manifest correct: public routes bypass the
6
+ # /api/* auth gate; @middleware tells the proxy this cart exports the global
7
+ # authenticate gate (registered at /_middleware/authenticate). The @authn
8
+ # (service) sync/role routes carry NO directive — they require auth, gated
9
+ # inline in the handler.
10
+ @public_route "/api/auth/user/signup"
11
+ @public_route "/api/auth/user/signin"
12
+ @public_route "/api/auth/session/signout"
13
+ @public_route "/api/auth/session/current"
14
+ @public_route "/api/auth/user/forgot_password"
15
+ @public_route "/api/auth/user/reset_password"
16
+ @public_route "/api/auth/user/verify_email"
17
+ @middleware "authenticate"
18
+
19
+ export entity User {
20
+ id: ulid
21
+ createdAt: DateTime @default(now())
22
+ updatedAt: DateTime @updatedAt
23
+ name: string
24
+ username?: string
25
+ email?: string
26
+ emailVerified: bool
27
+ externalId?: string
28
+ capsVersion: u32 # what is this?
29
+
30
+ @@index([email])
31
+ @@index([externalId])
32
+ @@unique([email])
33
+ }
34
+
35
+ # Per-cartridge role assignments. Role names refer to entries in the owning
36
+ # cartridge's `roles { }` block — this cartridge does not validate them.
37
+ entity UserRole {
38
+ id: ulid
39
+ createdAt: DateTime @default(now())
40
+ updatedAt: DateTime @updatedAt
41
+ userId: string
42
+ cart: string
43
+ role: string
44
+
45
+ @@index([userId])
46
+ }
47
+
48
+ entity Session {
49
+ id: ulid
50
+ createdAt: DateTime @default(now())
51
+ updatedAt: DateTime @updatedAt
52
+ userId: string
53
+ token: string
54
+ expiresAt: DateTime
55
+ ipAddress?: string
56
+ userAgent?: string
57
+
58
+ @@index([token])
59
+ @@index([userId])
60
+ }
61
+
62
+ entity Account {
63
+ id: ulid
64
+ createdAt: DateTime @default(now())
65
+ updatedAt: DateTime @updatedAt
66
+ userId: string
67
+ providerId: string
68
+ password: string
69
+ accessToken: string
70
+ refreshToken: string
71
+ idToken: string
72
+ accessTokenExpiresAt: DateTime
73
+ refreshTokenExpiresAt: DateTime
74
+ scope: string
75
+
76
+ @@index([userId])
77
+ }
78
+
79
+ entity Verification {
80
+ id: ulid
81
+ createdAt: DateTime @default(now())
82
+ updatedAt: DateTime @updatedAt
83
+ identifier: string
84
+ value: string
85
+ expiresAt: DateTime
86
+
87
+ @@index([identifier])
88
+ }
89
+
90
+ entity ApiKey {
91
+ id: ulid
92
+ createdAt: DateTime @default(now())
93
+ updatedAt: DateTime @updatedAt
94
+ name: string
95
+ projectId: string
96
+ start: string
97
+ prefix: string
98
+ key: string
99
+ permissions: string
100
+ roles: string
101
+ }
102
+
103
+ # Console-operator SSH public keys. The console daemon authenticates SSH
104
+ # connections by looking up rows here via modules/auth_lookup/ (in-process,
105
+ # direct storage read — auth cart liveness is not required).
106
+ entity SshKey {
107
+ id: ulid
108
+ createdAt: DateTime @default(now())
109
+ updatedAt: DateTime @updatedAt
110
+ userId: string
111
+ label: string
112
+ blob: string
113
+
114
+ @@index([userId])
115
+ @@unique([blob])
116
+ }
117
+
118
+ jai {
119
+ find_synced_user :: (requestedId: string, email: string) -> (User, bool) {
120
+ if requestedId.count > 0 {
121
+ by_id, by_id_ok := get_user(requestedId);
122
+ if by_id_ok return by_id, true;
123
+
124
+ by_external := find_users_by_externalId(requestedId);
125
+ if by_external.count > 0 {
126
+ u, ok := get_user(by_external[0].id);
127
+ if ok return u, true;
128
+ }
129
+ }
130
+
131
+ if email.count > 0 {
132
+ by_email := find_users_by_email(email);
133
+ if by_email.count > 0 {
134
+ u, ok := get_user(by_email[0].id);
135
+ if ok return u, true;
136
+ }
137
+ }
138
+
139
+ empty: User;
140
+ return empty, false;
141
+ }
142
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "createdAt": "2026-01-20T18:23:25.182Z",
3
+ "description": "<p style=\"margin:0px;color:#10182899\">Quick call with our local specialist to see if solar makes sense for you</p>",
4
+ "id": "zKW5Rx1wttNPLBXIYRh5",
5
+ "isActive": true,
6
+ "name": "Solar Discovery Call (ME FB BR)",
7
+ "slotDuration": 15,
8
+ "slotInterval": 15,
9
+ "source": "ghl",
10
+ "timezone": "America/Toronto",
11
+ "updatedAt": "2026-04-30T14:15:34.287Z"
12
+ }
@@ -0,0 +1,70 @@
1
+ {
2
+ "workflow": {"id": "f1d4c9b2-3a76-4ed8-bb12-9c4f0e5d7a01", "name": "Appointment Changed Sync"},
3
+ "type": "AppointmentUpdate",
4
+ "customData": {"org": "mlp", "project": "default", "type": "Appointment"},
5
+ "location": {
6
+ "id": "loc_test",
7
+ "name": "MyLocalPro Test",
8
+ "address": "22 Old Village Rd Sturbridge MA 01566",
9
+ "city": "Sturbridge",
10
+ "country": "US",
11
+ "fullAddress": "22 Old Village Rd Sturbridge MA 01566, Sturbridge MA 01566",
12
+ "postalCode": "01566",
13
+ "state": "MA"
14
+ },
15
+ "contact_id": "ctc_alice_001",
16
+ "first_name": "Alice",
17
+ "last_name": "Anderson-Smith",
18
+ "full_name": "Alice Anderson-Smith",
19
+ "email": "alice.smith@example.com",
20
+ "phone": "+15551234567",
21
+ "address1": "456 Updated Ave",
22
+ "full_address": "456 Updated Ave, Toronto ON M5V 2A2",
23
+ "city": "Toronto",
24
+ "state": "ON",
25
+ "country": "CA",
26
+ "postal_code": "M5V 2A2",
27
+ "timezone": "America/Toronto",
28
+ "tags": "solar,residential,rescheduled",
29
+ "contact_source": "Solar Survey MLP Skynet",
30
+ "contact_type": "lead",
31
+ "attributionSource": {},
32
+ "contact": {
33
+ "attributionSource": {
34
+ "campaign": "spring-solar",
35
+ "sessionSource": "Website"
36
+ },
37
+ "lastAttributionSource": {}
38
+ },
39
+ "calendar": {
40
+ "appointmentId": "apt_001",
41
+ "id": "cal_solar_consult",
42
+ "calendarName": "Solar Consultation",
43
+ "title": "Initial Solar Consult — Alice Anderson",
44
+ "address": "456 Updated Ave, Toronto, ON",
45
+ "notes": "Rescheduled per customer request; closer reassigned.",
46
+ "startTime": "2026-05-15T10:00:00",
47
+ "endTime": "2026-05-15T11:00:00",
48
+ "appoinmentStatus": "showed",
49
+ "appointmentStatus": "confirmed",
50
+ "selectedTimezone": "America/Toronto",
51
+ "assignedUserId": "usr_002"
52
+ },
53
+ "Setter": "Diana Davis",
54
+ "Setter Name": "Diana Davis",
55
+ "Closer": "Charlie Chen",
56
+ "Appointment Outcome": "showed",
57
+ "Appointment Time": "2026-05-15T10:00:00",
58
+ "Appointment Type": "Discovery Call",
59
+ "Average Electric Bill": "245",
60
+ "Shade?": "minimal",
61
+ "Utility": "Toronto Hydro",
62
+ "Total Contract Price": "",
63
+ "Date Sold": "",
64
+ "triggerData": {},
65
+ "user": {
66
+ "email": "charlie@example.com",
67
+ "firstName": "Charlie",
68
+ "lastName": "Chen"
69
+ }
70
+ }
@@ -0,0 +1,72 @@
1
+ {
2
+ "workflow": {"id": "f1d4c9b2-3a76-4ed8-bb12-9c4f0e5d7a01", "name": "Appointment Created Sync"},
3
+ "type": "AppointmentCreate",
4
+ "customData": {"org": "mlp", "project": "default", "type": "Appointment"},
5
+ "location": {
6
+ "id": "loc_test",
7
+ "name": "MyLocalPro Test",
8
+ "address": "22 Old Village Rd Sturbridge MA 01566",
9
+ "city": "Sturbridge",
10
+ "country": "US",
11
+ "fullAddress": "22 Old Village Rd Sturbridge MA 01566, Sturbridge MA 01566",
12
+ "postalCode": "01566",
13
+ "state": "MA"
14
+ },
15
+ "contact_id": "ctc_alice_001",
16
+ "first_name": "Alice",
17
+ "last_name": "Anderson",
18
+ "full_name": "Alice Anderson",
19
+ "email": "alice@example.com",
20
+ "phone": "+15551234567",
21
+ "address1": "123 Main St",
22
+ "full_address": "123 Main St, Toronto ON M5V 1A1",
23
+ "city": "Toronto",
24
+ "state": "ON",
25
+ "country": "CA",
26
+ "postal_code": "M5V 1A1",
27
+ "timezone": "America/Toronto",
28
+ "tags": "solar,residential",
29
+ "contact_source": "Solar Survey MLP Skynet",
30
+ "contact_type": "lead",
31
+ "attributionSource": {},
32
+ "contact": {
33
+ "attributionSource": {
34
+ "campaign": "spring-solar",
35
+ "medium": "cpc",
36
+ "sessionSource": "Website"
37
+ },
38
+ "lastAttributionSource": {}
39
+ },
40
+ "calendar": {
41
+ "appointmentId": "apt_001",
42
+ "id": "cal_solar_consult",
43
+ "calendarName": "Solar Consultation",
44
+ "title": "Initial Solar Consult — Alice Anderson",
45
+ "address": "123 Main St, Toronto, ON",
46
+ "notes": "Customer interested in 8kW system; financing questions.",
47
+ "startTime": "2026-05-12T14:00:00-04:00",
48
+ "endTime": "2026-05-12T15:00:00-04:00",
49
+ "appoinmentStatus": "confirmed",
50
+ "selectedTimezone": "America/Toronto",
51
+ "assignedUserId": "usr_001"
52
+ },
53
+ "Setter": "Diana Davis",
54
+ "Setter Name": "Diana Davis",
55
+ "Closer": "Bob Brown",
56
+ "Appointment Outcome": "",
57
+ "Appointment Time": "2026-05-12T14:00:00-04:00",
58
+ "Appointment Type": "Discovery Call",
59
+ "Average Electric Bill": "245",
60
+ "Shade?": "minimal",
61
+ "Utility": "Toronto Hydro",
62
+ "Total Contract Price": "",
63
+ "Date Sold": "",
64
+ "created_by": "Diana Davis",
65
+ "created_by_user_id": "usr_003",
66
+ "triggerData": {},
67
+ "user": {
68
+ "email": "diana@example.com",
69
+ "firstName": "Diana",
70
+ "lastName": "Davis"
71
+ }
72
+ }
@@ -0,0 +1,60 @@
1
+ migration initial {
2
+ add_entity Calendar
3
+ add_field Calendar name string default("")
4
+ add_field Calendar description string default("")
5
+ add_field Calendar timezone string default("")
6
+ add_field Calendar slotDuration u32 default(0)
7
+ add_field Calendar slotInterval u32 default(0)
8
+ add_field Calendar isActive bool default(false)
9
+ add_field Calendar source string default("")
10
+ add_entity Appointment
11
+ add_field Appointment calendar Calendar default(0)
12
+ add_field Appointment contact Contact default(0)
13
+ add_field Appointment title string default("")
14
+ add_field Appointment address string default("")
15
+ add_field Appointment notes string default("")
16
+ add_field Appointment startTime DateTime default(0)
17
+ add_field Appointment endTime DateTime default(0)
18
+ add_field Appointment timezone string default("")
19
+ add_field Appointment status string default("")
20
+ add_field Appointment source string default("")
21
+ add_field Appointment assignedUser User default(0)
22
+ add_field Appointment isRescheduled bool default(false)
23
+ add_field Appointment originalStartTime DateTime default(0)
24
+ add_field Appointment originalEndTime DateTime default(0)
25
+ add_index Appointment [contactId]
26
+ add_index Appointment [calendarId]
27
+ add_entity Contact
28
+ add_field Contact firstName string default("")
29
+ add_field Contact lastName string default("")
30
+ add_field Contact fullName string default("")
31
+ add_field Contact phone string default("")
32
+ add_field Contact mobile string default("")
33
+ add_field Contact email string default("")
34
+ add_field Contact address string default("")
35
+ add_field Contact fullAddress string default("")
36
+ add_field Contact postalCode string default("")
37
+ add_field Contact city string default("")
38
+ add_field Contact stateOrProvince string default("")
39
+ add_field Contact country string default("")
40
+ add_field Contact timezone string default("")
41
+ add_field Contact lat float default(0)
42
+ add_field Contact lon float default(0)
43
+ add_field Contact company string default("")
44
+ add_field Contact website string default("")
45
+ add_field Contact title string default("")
46
+ add_field Contact industry string default("")
47
+ add_field Contact source string default("")
48
+ add_field Contact notes string default("")
49
+ add_field Contact data document default(0)
50
+ add_field Contact customData document default(0)
51
+ add_entity User
52
+ add_field User name string default("")
53
+ add_field User username string default("")
54
+ add_field User email string default("")
55
+ add_field User emailVerified bool default(false)
56
+ add_field User externalId string default("")
57
+ add_field User capsVersion u32 default(0)
58
+ add_index User [email]
59
+ add_index User [externalId]
60
+ }
@@ -0,0 +1,66 @@
1
+ entity Calendar {
2
+ name: string
3
+ description?: string
4
+ timezone?: string
5
+ slotDuration?: u32
6
+ slotInterval?: u32
7
+ isActive: bool
8
+ source?: string
9
+ }
10
+
11
+ entity Appointment {
12
+ calendar: Calendar
13
+ contact: Contact
14
+ title?: string
15
+ address?: string
16
+ notes?: string
17
+ startTime: DateTime
18
+ endTime: DateTime
19
+ timezone?: string
20
+ status: string
21
+ source?: string
22
+ assignedUser?: User
23
+ isRescheduled: bool
24
+ originalStartTime?: DateTime
25
+ originalEndTime?: DateTime
26
+ @@index([contactId])
27
+ @@index([calendarId])
28
+ }
29
+
30
+ entity Contact {
31
+ firstName?: string
32
+ lastName?: string
33
+ fullName?: string
34
+ phone?: string
35
+ mobile?: string
36
+ email?: string
37
+ address?: string
38
+ fullAddress?: string
39
+ postalCode?: string
40
+ city?: string
41
+ stateOrProvince?: string
42
+ country?: string
43
+ timezone?: string
44
+ lat?: float
45
+ lon?: float
46
+ company?: string
47
+ website?: string
48
+ title?: string
49
+ industry?: string
50
+ source?: string
51
+ notes?: string
52
+ data: document
53
+ customData: document
54
+ }
55
+
56
+ entity User {
57
+ name: string
58
+ username?: string
59
+ email?: string
60
+ emailVerified: bool
61
+ externalId?: string
62
+ capsVersion: u32
63
+ @@index([email])
64
+ @@index([externalId])
65
+ }
66
+
@@ -0,0 +1,17 @@
1
+ migration schema_update {
2
+ add_field Appointment state string default("")
3
+ add_field Appointment outcomeClass string default("")
4
+ add_field Appointment embedText string default("")
5
+ add_index Appointment [state]
6
+ add_index Appointment [outcomeClass]
7
+ add_entity AppointmentParticipant
8
+ add_field AppointmentParticipant appointment Appointment default(0)
9
+ add_field AppointmentParticipant user User default(0)
10
+ add_field AppointmentParticipant role string default("")
11
+ add_field AppointmentParticipant assignedAt DateTime default(0)
12
+ add_field AppointmentParticipant assignedBy User default(0)
13
+ add_field AppointmentParticipant notes string default("")
14
+ add_index AppointmentParticipant [appointmentId]
15
+ add_index AppointmentParticipant [userId, role]
16
+ add_unique AppointmentParticipant [appointmentId, role, userId]
17
+ }
@@ -0,0 +1,83 @@
1
+ entity Calendar {
2
+ name: string
3
+ description?: string
4
+ timezone?: string
5
+ slotDuration?: u32
6
+ slotInterval?: u32
7
+ isActive: bool
8
+ source?: string
9
+ }
10
+
11
+ entity Appointment {
12
+ calendar: Calendar
13
+ contact: Contact
14
+ title?: string
15
+ address?: string
16
+ notes?: string
17
+ startTime: DateTime
18
+ endTime: DateTime
19
+ timezone?: string
20
+ status: string
21
+ source?: string
22
+ assignedUser?: User
23
+ isRescheduled: bool
24
+ originalStartTime?: DateTime
25
+ originalEndTime?: DateTime
26
+ state?: string
27
+ outcomeClass?: string
28
+ embedText?: string
29
+ @@index([contactId])
30
+ @@index([calendarId])
31
+ @@index([state])
32
+ @@index([outcomeClass])
33
+ }
34
+
35
+ entity AppointmentParticipant {
36
+ appointment: Appointment
37
+ user: User
38
+ role: string
39
+ assignedAt: DateTime
40
+ assignedBy?: User
41
+ notes?: string
42
+ @@unique([appointmentId, role, userId])
43
+ @@index([appointmentId])
44
+ @@index([userId, role])
45
+ }
46
+
47
+ entity Contact {
48
+ firstName?: string
49
+ lastName?: string
50
+ fullName?: string
51
+ phone?: string
52
+ mobile?: string
53
+ email?: string
54
+ address?: string
55
+ fullAddress?: string
56
+ postalCode?: string
57
+ city?: string
58
+ stateOrProvince?: string
59
+ country?: string
60
+ timezone?: string
61
+ lat?: float
62
+ lon?: float
63
+ company?: string
64
+ website?: string
65
+ title?: string
66
+ industry?: string
67
+ source?: string
68
+ notes?: string
69
+ data: document
70
+ customData: document
71
+ }
72
+
73
+ entity User {
74
+ name: string
75
+ username?: string
76
+ email?: string
77
+ emailVerified: bool
78
+ externalId?: string
79
+ capsVersion: u32
80
+ @@index([email])
81
+ @@index([externalId])
82
+ }
83
+
@@ -0,0 +1,86 @@
1
+ import {Contact} from "crm";
2
+ import {User} from "auth";
3
+
4
+ entity Calendar {
5
+ id: ulid
6
+ createdAt: DateTime @default(now())
7
+ updatedAt: DateTime @updatedAt
8
+ name: string
9
+ description?: string
10
+ timezone?: string
11
+ slotDuration?: u32
12
+ slotInterval?: u32
13
+ isActive: bool
14
+ source?: string
15
+ appointments: Appointment[]
16
+ }
17
+
18
+ export entity Appointment {
19
+ id: ulid
20
+ createdAt: DateTime @default(now())
21
+ updatedAt: DateTime @updatedAt
22
+ calendar: Calendar
23
+ contact: Contact @relation(onDelete: Restrict)
24
+ title?: string
25
+ address?: string
26
+ notes?: string
27
+ startTime: DateTime
28
+ endTime: DateTime
29
+ timezone?: string
30
+ status: string
31
+ source?: string
32
+ assignedUser?: User @relation(onDelete: SetNull)
33
+ isRescheduled: bool
34
+ originalStartTime?: DateTime
35
+ originalEndTime?: DateTime
36
+
37
+ # Geographic state (e.g. "CA", "TX") parsed from `address` at ingest. Indexed
38
+ # so customers can filter assignment candidates by state cheaply.
39
+ state?: string
40
+
41
+ # Generic outcome label for similarity-weighted aggregation. Customer fills
42
+ # via their domain's lifecycle hook ("won" for MyLocalPro, "positive" for
43
+ # therapy). Indexed for `Appointment.find_by_outcomeClass("won")` lookups.
44
+ outcomeClass?: string
45
+
46
+ # Rendered embedding-template text. Persisted alongside the Appointment so
47
+ # similarity search can score (target_text, candidate_text) pairs without
48
+ # re-rendering the customer's @embed template on every query. Populated at
49
+ # ingest by the customer's @embed binding
50
+ # (D09.10c). Generic surface — every customer composing similarity search
51
+ # over Appointments needs it; the *content* of the text is customer policy.
52
+ embedText?: string
53
+
54
+ participants: AppointmentParticipant[]
55
+
56
+ # contact + calendar are FK fields — indexed automatically.
57
+ @@index([state])
58
+ @@index([outcomeClass])
59
+ }
60
+
61
+ # Many-to-many linkage between Appointment and User with a client-defined
62
+ # role label. Lets a deployment encode any participant taxonomy without
63
+ # adding new columns to Appointment:
64
+ #
65
+ # MyLocalPro: role = "setter" | "closer" | "shadower"
66
+ # Therapy: role = "therapist" | "supervisor"
67
+ # Field service: role = "primary" | "backup" | "trainee"
68
+ #
69
+ # `Appointment.assignedUser` stays as the conventional "primary owner"
70
+ # pointer (single value, indexed) for clients that don't need multi-role.
71
+ # AppointmentParticipant is additive — clients pick the row when they
72
+ # want richer linkage.
73
+ export entity AppointmentParticipant {
74
+ id: ulid
75
+ createdAt: DateTime @default(now())
76
+ updatedAt: DateTime @updatedAt
77
+ appointment: Appointment @relation(onDelete: Cascade)
78
+ user: User @relation(onDelete: Cascade)
79
+ role: string # client-defined (e.g. "setter", "closer")
80
+ assignedAt: DateTime @default(now())
81
+ assignedBy?: User @relation(onDelete: SetNull) # who recorded this assignment (for audit)
82
+ notes?: string
83
+
84
+ @@unique([appointment, role, user])
85
+ @@index([user, role])
86
+ }