@hailer/mcp 1.1.12 → 1.1.13

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 (271) hide show
  1. package/CHANGELOG.md +0 -7
  2. package/{.claude → dist}/CLAUDE.md +2 -2
  3. package/dist/app.js +18 -5
  4. package/dist/bot/bot-config.d.ts +10 -1
  5. package/dist/bot/bot-config.js +64 -3
  6. package/dist/bot/bot-manager.d.ts +2 -0
  7. package/dist/bot/bot-manager.js +9 -2
  8. package/dist/bot/bot.d.ts +33 -0
  9. package/dist/bot/bot.js +461 -160
  10. package/dist/bot/services/message-classifier.js +17 -0
  11. package/dist/bot/services/permission-guard.d.ts +52 -0
  12. package/dist/bot/services/permission-guard.js +149 -0
  13. package/dist/bot/services/types.d.ts +5 -0
  14. package/dist/bot/services/typing-indicator.d.ts +6 -1
  15. package/dist/bot/services/typing-indicator.js +19 -3
  16. package/dist/cli.js +0 -0
  17. package/dist/config.d.ts +6 -1
  18. package/dist/config.js +43 -0
  19. package/dist/core.js +3 -6
  20. package/dist/lib/discussion-lock.d.ts +42 -0
  21. package/dist/lib/discussion-lock.js +110 -0
  22. package/dist/mcp/UserContextCache.d.ts +5 -0
  23. package/dist/mcp/UserContextCache.js +51 -19
  24. package/dist/mcp/hailer-clients.d.ts +19 -1
  25. package/dist/mcp/hailer-clients.js +158 -24
  26. package/dist/mcp/session-store.d.ts +68 -0
  27. package/dist/mcp/session-store.js +169 -0
  28. package/dist/mcp/signal-handler.js +2 -0
  29. package/dist/mcp/tool-registry.d.ts +17 -4
  30. package/dist/mcp/tool-registry.js +37 -7
  31. package/dist/mcp/tools/activity.js +99 -7
  32. package/dist/mcp/tools/app-scaffold.js +304 -336
  33. package/dist/mcp/tools/bot-config/constants.d.ts +23 -0
  34. package/dist/mcp/tools/bot-config/constants.js +94 -0
  35. package/dist/mcp/tools/bot-config/core.d.ts +253 -0
  36. package/dist/mcp/tools/bot-config/core.js +2456 -0
  37. package/dist/mcp/tools/bot-config/index.d.ts +10 -0
  38. package/dist/mcp/tools/bot-config/index.js +59 -0
  39. package/dist/mcp/tools/bot-config/tools.d.ts +7 -0
  40. package/dist/mcp/tools/bot-config/tools.js +15 -0
  41. package/dist/mcp/tools/bot-config/types.d.ts +50 -0
  42. package/dist/mcp/tools/bot-config/types.js +6 -0
  43. package/dist/mcp/tools/bug-fixer-tools.d.ts +45 -0
  44. package/dist/mcp/tools/bug-fixer-tools.js +1096 -0
  45. package/dist/mcp/tools/company.d.ts +9 -0
  46. package/dist/mcp/tools/company.js +88 -0
  47. package/dist/mcp/tools/discussion.js +68 -0
  48. package/dist/mcp/tools/document.d.ts +11 -0
  49. package/dist/mcp/tools/document.js +741 -0
  50. package/dist/mcp/tools/investigate.d.ts +9 -0
  51. package/dist/mcp/tools/investigate.js +254 -0
  52. package/dist/mcp/tools/workflow-permissions.d.ts +15 -0
  53. package/dist/mcp/tools/workflow-permissions.js +204 -0
  54. package/dist/mcp/tools/workflow.js +57 -18
  55. package/dist/mcp/utils/index.d.ts +2 -0
  56. package/dist/mcp/utils/index.js +12 -1
  57. package/dist/mcp/utils/role-utils.d.ts +74 -0
  58. package/dist/mcp/utils/role-utils.js +151 -0
  59. package/dist/mcp/utils/types.d.ts +43 -1
  60. package/dist/mcp/utils/types.js +14 -0
  61. package/dist/mcp/webhook-handler.d.ts +4 -0
  62. package/dist/mcp/webhook-handler.js +8 -0
  63. package/dist/mcp-server.d.ts +23 -2
  64. package/dist/mcp-server.js +639 -127
  65. package/dist/plugins/vipunen/client.d.ts +150 -0
  66. package/dist/plugins/vipunen/client.js +535 -0
  67. package/dist/plugins/vipunen/config/schema-config.json +19 -0
  68. package/dist/plugins/vipunen/config/schema-doc.json +22 -0
  69. package/dist/plugins/vipunen/index.d.ts +41 -0
  70. package/dist/plugins/vipunen/index.js +88 -0
  71. package/dist/plugins/vipunen/tools.d.ts +26 -0
  72. package/dist/plugins/vipunen/tools.js +501 -0
  73. package/dist/stdio-server.d.ts +14 -0
  74. package/dist/stdio-server.js +101 -0
  75. package/package.json +2 -1
  76. package/.claude/agents/agent-ada-skill-builder.md +0 -94
  77. package/.claude/agents/agent-alejandro-function-fields.md +0 -342
  78. package/.claude/agents/agent-bjorn-config-audit.md +0 -103
  79. package/.claude/agents/agent-builder-agent-creator.md +0 -130
  80. package/.claude/agents/agent-code-simplifier.md +0 -53
  81. package/.claude/agents/agent-dmitri-activity-crud.md +0 -159
  82. package/.claude/agents/agent-giuseppe-app-builder.md +0 -247
  83. package/.claude/agents/agent-gunther-mcp-tools.md +0 -39
  84. package/.claude/agents/agent-helga-workflow-config.md +0 -204
  85. package/.claude/agents/agent-igor-activity-mover-automation.md +0 -125
  86. package/.claude/agents/agent-ingrid-doc-templates.md +0 -261
  87. package/.claude/agents/agent-ivan-monolith.md +0 -154
  88. package/.claude/agents/agent-kenji-data-reader.md +0 -86
  89. package/.claude/agents/agent-lars-code-inspector.md +0 -102
  90. package/.claude/agents/agent-marco-mockup-builder.md +0 -110
  91. package/.claude/agents/agent-marcus-api-documenter.md +0 -323
  92. package/.claude/agents/agent-marketplace-publisher.md +0 -280
  93. package/.claude/agents/agent-marketplace-reviewer.md +0 -309
  94. package/.claude/agents/agent-permissions-handler.md +0 -208
  95. package/.claude/agents/agent-simple-writer.md +0 -48
  96. package/.claude/agents/agent-svetlana-code-review.md +0 -171
  97. package/.claude/agents/agent-tanya-test-runner.md +0 -333
  98. package/.claude/agents/agent-ui-designer.md +0 -100
  99. package/.claude/agents/agent-viktor-sql-insights.md +0 -212
  100. package/.claude/agents/agent-web-search.md +0 -55
  101. package/.claude/agents/agent-yevgeni-discussions.md +0 -45
  102. package/.claude/agents/agent-zara-zapier.md +0 -159
  103. package/.claude/commands/app-squad.md +0 -135
  104. package/.claude/commands/audit-squad.md +0 -158
  105. package/.claude/commands/autoplan.md +0 -563
  106. package/.claude/commands/cleanup-squad.md +0 -98
  107. package/.claude/commands/config-squad.md +0 -106
  108. package/.claude/commands/crud-squad.md +0 -87
  109. package/.claude/commands/data-squad.md +0 -97
  110. package/.claude/commands/debug-squad.md +0 -303
  111. package/.claude/commands/doc-squad.md +0 -65
  112. package/.claude/commands/handoff.md +0 -137
  113. package/.claude/commands/health.md +0 -49
  114. package/.claude/commands/help.md +0 -29
  115. package/.claude/commands/help:agents.md +0 -151
  116. package/.claude/commands/help:commands.md +0 -78
  117. package/.claude/commands/help:faq.md +0 -79
  118. package/.claude/commands/help:plugins.md +0 -50
  119. package/.claude/commands/help:skills.md +0 -93
  120. package/.claude/commands/help:tools.md +0 -75
  121. package/.claude/commands/hotfix-squad.md +0 -112
  122. package/.claude/commands/integration-squad.md +0 -82
  123. package/.claude/commands/janitor-squad.md +0 -167
  124. package/.claude/commands/learn-auto.md +0 -120
  125. package/.claude/commands/learn.md +0 -120
  126. package/.claude/commands/mcp-list.md +0 -27
  127. package/.claude/commands/onboard-squad.md +0 -140
  128. package/.claude/commands/plan-workspace.md +0 -732
  129. package/.claude/commands/prd.md +0 -130
  130. package/.claude/commands/project-status.md +0 -82
  131. package/.claude/commands/publish.md +0 -138
  132. package/.claude/commands/recap.md +0 -69
  133. package/.claude/commands/restore.md +0 -64
  134. package/.claude/commands/review-squad.md +0 -152
  135. package/.claude/commands/save.md +0 -24
  136. package/.claude/commands/stats.md +0 -19
  137. package/.claude/commands/swarm.md +0 -210
  138. package/.claude/commands/tool-builder.md +0 -39
  139. package/.claude/commands/ws-pull.md +0 -44
  140. package/.claude/hooks/_shared-memory.cjs +0 -305
  141. package/.claude/hooks/_utils.cjs +0 -108
  142. package/.claude/hooks/agent-failure-detector.cjs +0 -383
  143. package/.claude/hooks/agent-usage-logger.cjs +0 -204
  144. package/.claude/hooks/app-edit-guard.cjs +0 -494
  145. package/.claude/hooks/auto-learn.cjs +0 -304
  146. package/.claude/hooks/bash-guard.cjs +0 -272
  147. package/.claude/hooks/builder-mode-manager.cjs +0 -354
  148. package/.claude/hooks/bulk-activity-guard.cjs +0 -271
  149. package/.claude/hooks/context-watchdog.cjs +0 -230
  150. package/.claude/hooks/delegation-reminder.cjs +0 -465
  151. package/.claude/hooks/design-system-lint.cjs +0 -271
  152. package/.claude/hooks/post-scaffold-hook.cjs +0 -181
  153. package/.claude/hooks/prompt-guard.cjs +0 -354
  154. package/.claude/hooks/publish-template-guard.cjs +0 -147
  155. package/.claude/hooks/session-start.cjs +0 -35
  156. package/.claude/hooks/shared-memory-writer.cjs +0 -147
  157. package/.claude/hooks/skill-injector.cjs +0 -140
  158. package/.claude/hooks/skill-usage-logger.cjs +0 -258
  159. package/.claude/hooks/src-edit-guard.cjs +0 -240
  160. package/.claude/hooks/sync-marketplace-agents.cjs +0 -346
  161. package/.claude/settings.json +0 -257
  162. package/.claude/skills/SDK-activity-patterns/SKILL.md +0 -428
  163. package/.claude/skills/SDK-document-templates/SKILL.md +0 -1033
  164. package/.claude/skills/SDK-function-fields/SKILL.md +0 -542
  165. package/.claude/skills/SDK-generate-skill/SKILL.md +0 -92
  166. package/.claude/skills/SDK-init-skill/SKILL.md +0 -127
  167. package/.claude/skills/SDK-insight-queries/SKILL.md +0 -787
  168. package/.claude/skills/SDK-ws-config-skill/SKILL.md +0 -1139
  169. package/.claude/skills/agent-structure/SKILL.md +0 -98
  170. package/.claude/skills/api-documentation-patterns/SKILL.md +0 -474
  171. package/.claude/skills/chrome-mcp-reference/SKILL.md +0 -370
  172. package/.claude/skills/delegation-routing/SKILL.md +0 -202
  173. package/.claude/skills/frontend-design/SKILL.md +0 -254
  174. package/.claude/skills/hailer-activity-mover/SKILL.md +0 -213
  175. package/.claude/skills/hailer-api-client/SKILL.md +0 -518
  176. package/.claude/skills/hailer-app-builder/SKILL.md +0 -1434
  177. package/.claude/skills/hailer-apps-pictures/SKILL.md +0 -269
  178. package/.claude/skills/hailer-design-system/SKILL.md +0 -235
  179. package/.claude/skills/hailer-monolith-automations/SKILL.md +0 -686
  180. package/.claude/skills/hailer-permissions-system/SKILL.md +0 -121
  181. package/.claude/skills/hailer-project-protocol/SKILL.md +0 -488
  182. package/.claude/skills/hailer-rest-api/SKILL.md +0 -61
  183. package/.claude/skills/hailer-rest-api/hailer-activities.md +0 -184
  184. package/.claude/skills/hailer-rest-api/hailer-admin.md +0 -473
  185. package/.claude/skills/hailer-rest-api/hailer-calendar.md +0 -256
  186. package/.claude/skills/hailer-rest-api/hailer-feed.md +0 -249
  187. package/.claude/skills/hailer-rest-api/hailer-insights.md +0 -195
  188. package/.claude/skills/hailer-rest-api/hailer-messaging.md +0 -276
  189. package/.claude/skills/hailer-rest-api/hailer-workflows.md +0 -283
  190. package/.claude/skills/insight-join-patterns/SKILL.md +0 -174
  191. package/.claude/skills/integration-patterns/SKILL.md +0 -421
  192. package/.claude/skills/json-only-output/SKILL.md +0 -72
  193. package/.claude/skills/lsp-setup/SKILL.md +0 -160
  194. package/.claude/skills/mcp-direct-tools/SKILL.md +0 -153
  195. package/.claude/skills/optional-parameters/SKILL.md +0 -72
  196. package/.claude/skills/publish-hailer-app/SKILL.md +0 -244
  197. package/.claude/skills/testing-patterns/SKILL.md +0 -630
  198. package/.claude/skills/tool-builder/SKILL.md +0 -250
  199. package/.claude/skills/tool-parameter-usage/SKILL.md +0 -126
  200. package/.claude/skills/tool-response-verification/SKILL.md +0 -92
  201. package/.claude/skills/zapier-hailer-patterns/SKILL.md +0 -581
  202. package/.mcp.json +0 -13
  203. package/.opencode/agent/agent-ada-skill-builder.md +0 -35
  204. package/.opencode/agent/agent-alejandro-function-fields.md +0 -39
  205. package/.opencode/agent/agent-bjorn-config-audit.md +0 -36
  206. package/.opencode/agent/agent-builder-agent-creator.md +0 -39
  207. package/.opencode/agent/agent-code-simplifier.md +0 -31
  208. package/.opencode/agent/agent-dmitri-activity-crud.md +0 -40
  209. package/.opencode/agent/agent-giuseppe-app-builder.md +0 -37
  210. package/.opencode/agent/agent-gunther-mcp-tools.md +0 -39
  211. package/.opencode/agent/agent-helga-workflow-config.md +0 -203
  212. package/.opencode/agent/agent-igor-activity-mover-automation.md +0 -46
  213. package/.opencode/agent/agent-ingrid-doc-templates.md +0 -39
  214. package/.opencode/agent/agent-ivan-monolith.md +0 -46
  215. package/.opencode/agent/agent-kenji-data-reader.md +0 -53
  216. package/.opencode/agent/agent-lars-code-inspector.md +0 -28
  217. package/.opencode/agent/agent-marco-mockup-builder.md +0 -42
  218. package/.opencode/agent/agent-marcus-api-documenter.md +0 -53
  219. package/.opencode/agent/agent-marketplace-publisher.md +0 -44
  220. package/.opencode/agent/agent-marketplace-reviewer.md +0 -42
  221. package/.opencode/agent/agent-permissions-handler.md +0 -50
  222. package/.opencode/agent/agent-simple-writer.md +0 -45
  223. package/.opencode/agent/agent-svetlana-code-review.md +0 -39
  224. package/.opencode/agent/agent-tanya-test-runner.md +0 -57
  225. package/.opencode/agent/agent-ui-designer.md +0 -56
  226. package/.opencode/agent/agent-viktor-sql-insights.md +0 -34
  227. package/.opencode/agent/agent-web-search.md +0 -42
  228. package/.opencode/agent/agent-yevgeni-discussions.md +0 -37
  229. package/.opencode/agent/agent-zara-zapier.md +0 -53
  230. package/.opencode/commands/app-squad.md +0 -135
  231. package/.opencode/commands/audit-squad.md +0 -158
  232. package/.opencode/commands/autoplan.md +0 -563
  233. package/.opencode/commands/cleanup-squad.md +0 -98
  234. package/.opencode/commands/config-squad.md +0 -106
  235. package/.opencode/commands/crud-squad.md +0 -87
  236. package/.opencode/commands/data-squad.md +0 -97
  237. package/.opencode/commands/debug-squad.md +0 -303
  238. package/.opencode/commands/doc-squad.md +0 -65
  239. package/.opencode/commands/handoff.md +0 -137
  240. package/.opencode/commands/health.md +0 -49
  241. package/.opencode/commands/help-agents.md +0 -151
  242. package/.opencode/commands/help-commands.md +0 -32
  243. package/.opencode/commands/help-faq.md +0 -29
  244. package/.opencode/commands/help-plugins.md +0 -28
  245. package/.opencode/commands/help-skills.md +0 -7
  246. package/.opencode/commands/help-tools.md +0 -40
  247. package/.opencode/commands/help.md +0 -28
  248. package/.opencode/commands/hotfix-squad.md +0 -112
  249. package/.opencode/commands/integration-squad.md +0 -82
  250. package/.opencode/commands/janitor-squad.md +0 -167
  251. package/.opencode/commands/learn-auto.md +0 -120
  252. package/.opencode/commands/learn.md +0 -120
  253. package/.opencode/commands/mcp-list.md +0 -27
  254. package/.opencode/commands/onboard-squad.md +0 -140
  255. package/.opencode/commands/plan-workspace.md +0 -732
  256. package/.opencode/commands/prd.md +0 -131
  257. package/.opencode/commands/project-status.md +0 -82
  258. package/.opencode/commands/publish.md +0 -138
  259. package/.opencode/commands/recap.md +0 -69
  260. package/.opencode/commands/restore.md +0 -64
  261. package/.opencode/commands/review-squad.md +0 -152
  262. package/.opencode/commands/save.md +0 -24
  263. package/.opencode/commands/stats.md +0 -19
  264. package/.opencode/commands/swarm.md +0 -210
  265. package/.opencode/commands/tool-builder.md +0 -39
  266. package/.opencode/commands/ws-pull.md +0 -44
  267. package/.opencode/opencode.json +0 -28
  268. package/SESSION-HANDOFF.md +0 -68
  269. package/inbox/2026-03-04-bot-config-patterns.md +0 -24
  270. package/scripts/postinstall.cjs +0 -64
  271. package/scripts/test-hal-tools.ts +0 -154
@@ -1,686 +0,0 @@
1
- ---
2
- name: hailer-monolith-automations
3
- description: Understanding and building automations in the Hailer project-monolith
4
- version: 1.2.0
5
- triggers: monolith, automation, scheduled task, webhook automation, invoicing, data sync
6
- ---
7
-
8
- # Hailer Monolith Automations
9
-
10
- The project-monolith is a centralized backend service for running customer automations without deploying separate microservices.
11
-
12
- ## Architecture Overview
13
-
14
- ```
15
- ┌─────────────────────────────────────────────────────────────┐
16
- │ Internal Network Only │
17
- │ ┌─────────────────┐ ┌─────────────────┐ │
18
- │ │ Hailer API │───▶│ project-monolith │───▶ External │
19
- │ │ (webhooks) │ │ (Express.js) │ APIs │
20
- │ └─────────────────┘ └─────────────────┘ (Netvisor, │
21
- │ │ Procountor, │
22
- │ ▼ etc.) │
23
- │ ┌─────────────────┐ │
24
- │ │ node-schedule │ │
25
- │ │ (cron jobs) │ │
26
- │ └─────────────────┘ │
27
- └─────────────────────────────────────────────────────────────┘
28
-
29
- Config: AWS Secrets Manager
30
- Logs: Winston structured logging
31
- ```
32
-
33
- **Key Points:**
34
- - Internal-only access (no internet-facing endpoints)
35
- - NAT Gateway for outgoing requests to external APIs
36
- - Single server handles 50+ automations
37
- - Config stored in AWS Secrets Manager
38
-
39
- ---
40
-
41
- ## Automation Types
42
-
43
- ### 1. Webhook-Triggered Automations
44
-
45
- Receive Hailer activity data via POST request when activities are created/updated.
46
-
47
- **Trigger:** Hailer webhook on activity update → POST to monolith endpoint
48
-
49
- **⚠️ CRITICAL: Never use SDK enums in automations.** Webhooks receive raw MongoDB ObjectIds, not SDK enum names. Use real IDs from config or extract from payload.
50
-
51
- **SDK enums ARE available in monolith context** via imports from workspace, but webhook payloads use real ObjectIds. Example:
52
- ```typescript
53
- // Available: Import SDK enums for clarity
54
- import { WorkflowIds, FieldIds } from '../workspace/enums';
55
-
56
- // But webhook payload has real IDs
57
- const workflowId = request.process; // "507f1f77bcf86cd799439011"
58
- const fieldValue = request.fields.find(f => f.id === FieldIds.customer); // OK to use enum here
59
- ```
60
-
61
- **Request payload:**
62
- ```typescript
63
- interface WebhookPayload {
64
- _id: string; // Activity ID (MongoDB ObjectId)
65
- cid: string; // Workspace ID
66
- process: string; // Workflow ID (MongoDB ObjectId)
67
- currentPhase: string; // Phase ID (MongoDB ObjectId)
68
- name: string;
69
- fields: Array<{
70
- id: string; // Field ID (MongoDB ObjectId)
71
- type: string; // Field type
72
- value: any; // Field value
73
- key?: string; // Optional field key (human-readable)
74
- }>;
75
- // ... other activity fields
76
- }
77
-
78
- // Finding field values - two methods:
79
- // Method 1: By key (if field has key property - preferred when available)
80
- const tagValue = payload.fields.find(f => f.key === 'tag')?.value;
81
-
82
- // Method 2: By fieldId (always works)
83
- const tagValue = payload.fields.find(f => f.id === config.tagFieldId)?.value;
84
- ```
85
-
86
- **Example endpoint:**
87
- ```typescript
88
- router.post('/my-automation/trigger', jsonParser, async (req, res) => {
89
- if (req.headers['content-type'] !== 'application/json') {
90
- return res.status(415).send('Content-Type must be application/json');
91
- }
92
-
93
- const config = await fetchConfig('monolith-my-automation');
94
-
95
- // Validate trigger conditions
96
- if (config.triggerProcessId !== req.body.process) {
97
- return res.status(200).send('Not applicable');
98
- }
99
-
100
- // Run automation (async, don't block response)
101
- void myAutomation(req.body, config);
102
-
103
- res.status(200).send('Ok');
104
- });
105
- ```
106
-
107
- **Use Cases:**
108
- - Activity data sync to external system on phase change
109
- - Create linked activities when parent updated
110
- - Send notifications on specific field changes
111
- - XML/file import when activity created
112
-
113
- ---
114
-
115
- ### 2. Scheduled Automations
116
-
117
- Run on a schedule using node-schedule (cron-like).
118
-
119
- **Schedule patterns:**
120
- ```typescript
121
- // Run at 3:02 AM on 1st of month
122
- scheduleJob('Monthly Task', { date: 1, hour: 3, minute: 2 }, async () => {});
123
-
124
- // Run at 5:45 AM every day
125
- scheduleJob('Daily Task', { hour: 5, minute: 45 }, async () => {});
126
-
127
- // Run at specific dates
128
- scheduleJob('Bi-weekly', { date: [1, 15], hour: 3, minute: 0 }, async () => {});
129
-
130
- // Run every hour
131
- scheduleJob('Hourly', { minute: 0 }, async () => {});
132
- ```
133
-
134
- **Example:**
135
- ```typescript
136
- scheduleJob('Invoice Subscriptions', { date: 1, hour: 3, minute: 10 }, async () => {
137
- const config = await fetchConfig('monolith-subscription-invoicing');
138
- const result = await invoiceSubscriptions(config);
139
- Logger.info('Subscription invoicing complete', { content: result });
140
- });
141
- ```
142
-
143
- **Use Cases:**
144
- - Monthly invoicing runs
145
- - Daily data sync with external systems
146
- - Activity archiving (cleanup old completed activities)
147
- - Alarm/status checks
148
- - Currency rate updates
149
-
150
- ---
151
-
152
- ### 3. Third-Party Integration Automations
153
-
154
- Sync data between Hailer and external systems.
155
-
156
- **Supported Systems:**
157
- | System | Type | Direction |
158
- |--------|------|-----------|
159
- | Netvisor | Accounting | Hailer ↔ Netvisor |
160
- | Procountor | Accounting | Hailer → Procountor |
161
- | Severa | Project Management | Hailer ↔ Severa |
162
- | SignSpace | E-signatures | Hailer → SignSpace |
163
- | INTU | HR/Payroll | Hailer ↔ INTU |
164
- | Logiapp | Logistics | Hailer → Logiapp |
165
- | Torna | Forestry | Torna → Hailer |
166
-
167
- **Pattern:**
168
- 1. Authenticate with external API
169
- 2. Fetch data from Hailer (or external system)
170
- 3. Transform data format
171
- 4. Push to destination
172
- 5. Update status fields in Hailer
173
-
174
- ---
175
-
176
- ## Common Patterns
177
-
178
- ### Config from AWS Secrets Manager
179
-
180
- ```typescript
181
- import { fetchConfig } from './fetch-secrets';
182
-
183
- // Config name matches AWS secret: "monolith-{name}"
184
- const config = await fetchConfig('monolith-my-automation');
185
-
186
- // Config structure example
187
- interface AutomationConfig {
188
- credentials: {
189
- email: string;
190
- password: string;
191
- };
192
- triggerProcessId: string;
193
- targetProcessId: string;
194
- fieldMappings: Record<string, string>;
195
- // ... custom config
196
- }
197
- ```
198
-
199
- ### Hailer Client Connection
200
-
201
- ```typescript
202
- import { Client } from '@hailer/cli';
203
-
204
- // Connect with retry helper
205
- const client = await connectWithRetry(config, 5);
206
-
207
- // Or direct connection
208
- const client = await Client.create({
209
- host: 'https://api.hailer.com',
210
- username: config.credentials.email,
211
- password: config.credentials.password
212
- });
213
-
214
- // Always disconnect when done
215
- client.disconnect();
216
- ```
217
-
218
- ### Activity Operations
219
-
220
- ```typescript
221
- // List activities
222
- const { activities } = await client.request('v3.activity.list', [
223
- { processId: workflowId, phaseId: phaseId },
224
- { limit: 1000, filters: { status: { equalTo: 'Active' } }, returnFlat: true }
225
- ]);
226
-
227
- // Create activities
228
- const created = await client.request('v3.activity.createMany', [
229
- { processId: workflowId, phaseId: phaseId, name: 'New Activity', fields: { fieldId: value } }
230
- ]);
231
-
232
- // Update activities
233
- const updated = await client.request('v3.activity.updateMany', [
234
- { _id: activityId, fields: { fieldId: newValue }, phaseId: newPhaseId }
235
- ]);
236
- ```
237
-
238
- ### Structured Logging
239
-
240
- ```typescript
241
- // Local log array for aggregated logging
242
- const logArray: any[] = [];
243
- const log = (level: string, message: string, data?) => {
244
- logArray.push({ level, message, data, time: Date.now() });
245
- };
246
-
247
- log('info', 'Process started');
248
- log('info', 'Fetched activities', { count: activities.length });
249
-
250
- // Final structured log
251
- Logger.info('Automation complete', {
252
- content: logArray,
253
- workspaceId: req.body.cid,
254
- workflowId: req.body.process,
255
- activityId: req.body._id
256
- });
257
- ```
258
-
259
- ### Deduplication (Prevent Double Processing)
260
-
261
- ```typescript
262
- const processingActivities = new Set();
263
-
264
- router.post('/my-automation', jsonParser, async (req, res) => {
265
- const lockKey = `${req.body.cid}-${req.body._id}`;
266
-
267
- if (processingActivities.has(lockKey)) {
268
- return res.status(200).send('Already processing');
269
- }
270
-
271
- processingActivities.add(lockKey);
272
- try {
273
- await runAutomation(req.body, config);
274
- } finally {
275
- processingActivities.delete(lockKey);
276
- }
277
-
278
- res.status(200).send('Ok');
279
- });
280
- ```
281
-
282
- ---
283
-
284
- ## File Structure
285
-
286
- ```
287
- project-monolith/
288
- ├── src/
289
- │ ├── run.ts # Express server, all endpoints
290
- │ ├── schedules.ts # All scheduled jobs
291
- │ ├── fetch-secrets.ts # AWS Secrets Manager
292
- │ ├── logger.ts # Winston logger
293
- │ ├── types.ts # Common types
294
- │ ├── utils/
295
- │ │ └── hailer-utils.ts # Helper functions
296
- │ └── automations/
297
- │ ├── generic-handle-activities.ts # Reusable CRUD
298
- │ ├── netvisor/ # Netvisor integrations
299
- │ ├── procountor/ # Procountor integrations
300
- │ ├── hailer/ # Hailer-internal automations
301
- │ └── {customer}/ # Customer-specific automations
302
- └── package.json
303
- ```
304
-
305
- ---
306
-
307
- ## When to Use Monolith vs Other Options
308
-
309
- | Scenario | Solution |
310
- |----------|----------|
311
- | Simple webhook trigger → Hailer CRUD | **Monolith** |
312
- | Scheduled data sync | **Monolith** |
313
- | Accounting integration (Netvisor, Procountor) | **Monolith** (existing code) |
314
- | Real-time activity sync | **activity-mover** |
315
- | SCIM user provisioning | **microsoft-entra** |
316
- | Kafka event processing | **digione-integration** |
317
- | Complex stateful integration | **Dedicated microservice** |
318
-
319
- ---
320
-
321
- ## Adding a New Automation
322
-
323
- ### 1. Create automation file
324
-
325
- ```typescript
326
- // src/automations/{customer}/{automation-name}.ts
327
- import { Client } from '@hailer/cli';
328
- import { Logger } from '../../logger';
329
- import { connectWithRetry } from '../../utils/hailer-utils';
330
-
331
- export const myAutomation = async (request: any, config: any): Promise<boolean> => {
332
- const logArray: any[] = [];
333
- const log = (level: string, message: string, data?) => {
334
- logArray.push({ level, message, data, time: Date.now() });
335
- };
336
-
337
- try {
338
- log('info', 'Starting automation');
339
-
340
- const client = await connectWithRetry(config, 5);
341
-
342
- // Your automation logic here
343
-
344
- client.disconnect();
345
- Logger.info('Automation success', { content: logArray });
346
- return true;
347
- } catch (error) {
348
- log('error', 'Automation failed', error);
349
- Logger.error('Automation failed', { content: logArray, error });
350
- return false;
351
- }
352
- };
353
- ```
354
-
355
- ### 2. Add endpoint (webhook) or schedule
356
-
357
- **Webhook (run.ts):**
358
- ```typescript
359
- import { myAutomation } from './automations/{customer}/{automation-name}';
360
-
361
- router.post('/{customer}/my-automation', jsonParser, async (req, res) => {
362
- const config = await fetchConfig('monolith-my-automation');
363
- if (config.triggerProcessId === req.body.process) {
364
- void myAutomation(req.body, config);
365
- }
366
- res.status(200).send('Ok');
367
- });
368
- ```
369
-
370
- **Scheduled (schedules.ts):**
371
- ```typescript
372
- import { myAutomation } from './automations/{customer}/{automation-name}';
373
-
374
- scheduleJob('My Scheduled Task', { hour: 3, minute: 0 }, async () => {
375
- const config = await fetchConfig('monolith-my-automation');
376
- await myAutomation(null, config);
377
- });
378
- ```
379
-
380
- ### 3. Generate AWS Config (User Deploys)
381
-
382
- Claude generates the config JSON. User uploads to AWS Secrets Manager manually.
383
-
384
- **Secret name:** `monolith-{automation-name}`
385
-
386
- ```json
387
- {
388
- "credentials": {
389
- "email": "integration@customer.com",
390
- "password": "USER_PROVIDES_PASSWORD"
391
- },
392
- "triggerProcessId": "workflow-id",
393
- "targetProcessId": "target-workflow-id",
394
- "fieldMappings": {
395
- "sourceField": "targetField"
396
- }
397
- }
398
- ```
399
-
400
- **User action:**
401
- 1. Fill in the integration user password
402
- 2. Upload to AWS Secrets Manager as `monolith-{automation-name}`
403
-
404
- ### 4. Git Workflow with Symlink
405
-
406
- The automation file lives in hailer-integration (for git). The project workspace gets a symlink (for context).
407
-
408
- **Step 1: Create feature branch in hailer-integration**
409
- ```bash
410
- cd ~/hailer-integration
411
- git checkout -b feature/{customer}-{automation-name}
412
- mkdir -p packages/project-monolith/src/automations/{customer}
413
- ```
414
-
415
- **Step 2: Write the automation file**
416
- ```bash
417
- # Claude writes to:
418
- ~/hailer-integration/packages/project-monolith/src/automations/{customer}/{automation-name}.ts
419
- ```
420
-
421
- **Step 3: Symlink to project workspace**
422
- ```bash
423
- cd ~/path/to/project-workspace
424
- mkdir -p integrations
425
- ln -s ~/hailer-integration/packages/project-monolith/src/automations/{customer}/{automation-name}.ts \
426
- integrations/{automation-name}.ts
427
- ```
428
-
429
- **Step 4: Commit and push**
430
- ```bash
431
- cd ~/hailer-integration
432
- git add packages/project-monolith/src/automations/{customer}/
433
- git commit -m "Add {automation-name} automation for {customer}"
434
- git push -u origin feature/{customer}-{automation-name}
435
- ```
436
-
437
- **Result:**
438
- - File in hailer-integration → can push to git, create PR
439
- - Symlink in project workspace → Claude has context when working on project
440
- - After PR merge → CI/CD deploys to monolith
441
-
442
- ### 5. Configure Hailer webhook (for webhook-triggered)
443
-
444
- In Hailer admin:
445
- 1. Go to Integrations → Webhooks
446
- 2. Add webhook URL: `https://internal-lb/api/v1/{customer}/my-automation`
447
- 3. Select trigger workflow and events (create, update)
448
-
449
- ---
450
-
451
- ## Existing Automation Categories
452
-
453
- ### Invoicing Automations
454
- - `hailer-invoicing-subscription-v2` - Scheduled subscription billing
455
- - `hailer-invoicing-billable-work` - Bill tracked time/expenses
456
- - `hailer-invoicing-project-won` - Invoice on project completion
457
- - `3pl-invoicing-v2` - 3PL storage billing
458
- - `kspt-invoicing-v2-webhook` - KSPT rental invoicing
459
-
460
- ### Data Sync Automations
461
- - `netvisor-integration` - Netvisor ↔ Hailer sync
462
- - `procountor-integration-main` - Procountor invoicing
463
- - `severa-integration` - Severa project sync
464
- - `fin-forelia-*` - Forelia logistics/forestry
465
-
466
- ### Activity Management
467
- - `generic-handle-activities` - Reusable create/update
468
- - `activity-archiver` - Archive old activities
469
- - `porvoo-archive` - City-specific archiving
470
-
471
- ### Notifications & Alarms
472
- - `porvoo-alarms` - Status checks and alerts
473
- - `porvoo-notifications` - Send notification messages
474
- - `3pl-saldo-alarms` - Inventory level alerts
475
-
476
- ### HR/Employee Automations
477
- - `siskon-siivous-intu-*` - INTU HR sync
478
- - `pohjaset-employee-task-automation` - Onboarding tasks
479
- - `siskon-siivous-synttarionnittelut` - Birthday greetings
480
-
481
- ---
482
-
483
- ## Built-in Automation Reference
484
-
485
- These are reusable, config-driven automations already in the monolith.
486
-
487
- ### Email Automation
488
-
489
- Webhook-based endpoints for sending emails triggered by Hailer workflow events.
490
-
491
- **Source:** `packages/project-monolith/src/automations/hailer/email-automation.ts`
492
- **AWS Secret:** `monolith-hailer-email-automation-{workspaceId}`
493
-
494
- **Endpoints:**
495
- | Endpoint | Method | Purpose |
496
- |----------|--------|---------|
497
- | `/api/email-automation/send-emails` | POST | Send emails to mailing list |
498
- | `/api/email-automation/form-response` | POST | Handle form responses (unsubscribe) |
499
-
500
- **Flow:**
501
- 1. Activity enters trigger phase in Hailer
502
- 2. Webhook fires → POST to `/email-automation/send-emails`
503
- 3. Monolith reads email content from activity fields
504
- 4. Fetches mailing list from referenced workflow
505
- 5. Filters out blocklisted and unsubscribed recipients
506
- 6. Sends emails in batches via Mailgun or Nodemailer
507
- 7. Creates batch result activities for tracking
508
-
509
- **Config Structure:**
510
- ```typescript
511
- {
512
- email: string; // Hailer login
513
- password: string;
514
- senderEmail: string; // From address
515
- actions: {
516
- [phaseId: string]: string; // Phase → action ("send email" | "unsubscribe")
517
- };
518
- processes: {
519
- blockList: { processId, phaseId }; // Global unsubscribe
520
- batchResults: { processId, phaseId }; // Result tracking
521
- unsubscribe?: { phaseId }; // Unsubscribe target
522
- };
523
- sendWith?: 'nodemailer'; // Default: Mailgun
524
- mailgun?: { url, apiKey };
525
- nodemailer?: { host, port, username, password };
526
- emailBatchSize: number; // Default: 250
527
- }
528
- ```
529
-
530
- **Required Workflow Fields:**
531
-
532
- | Workflow | Field Key | Type | Purpose |
533
- |----------|-----------|------|---------|
534
- | Email Campaign | `subject` | TEXT | Email subject |
535
- | Email Campaign | `html` | TEXT | HTML body |
536
- | Email Campaign | `plaintext` | TEXT | Plain text body |
537
- | Email Campaign | `process` | TEXT | Mailing list workflow ID |
538
- | Email Campaign | `phase` | TEXT | Mailing list phase ID |
539
- | Mailing List | `email` | TEXT | Recipient email |
540
- | Mailing List | `unsubscribed` | NUMBER | 1 = unsubscribed |
541
- | Block List | `email` | TEXT | Blocked email |
542
-
543
- **Personalization (Nodemailer only):** Use `%recipient.id%` in HTML - replaced with activity ID.
544
-
545
- **Setup Steps:**
546
-
547
- 1. **Create AWS Config** - Add `monolith-hailer-email-automation-{workspaceId}` to AWS Secrets Manager with config structure above.
548
-
549
- 2. **Create Required Workflows** in Hailer:
550
- - Email Campaign workflow (with trigger phase, fields: subject, html, plaintext, process, phase)
551
- - Mailing List workflow (fields: email, unsubscribed)
552
- - Block List workflow (field: email)
553
- - Batch Results workflow (for tracking)
554
-
555
- 3. **Configure Webhook**:
556
- - URL: `https://monolith-url/api/email-automation/send-emails`
557
- - Trigger: Activity enters "Ready to Send" phase
558
- - Phase ID must match key in `config.actions`
559
-
560
- ---
561
-
562
- ### Generic Activity CRUD
563
-
564
- Webhook-based endpoints for bulk creating/updating activities via function fields.
565
-
566
- **Source:** `packages/project-monolith/src/automations/generic-handle-activities.ts`
567
- **AWS Secret:** `monolith-generic-create-update`
568
-
569
- **Endpoints:**
570
- | Endpoint | Method | Purpose |
571
- |----------|--------|---------|
572
- | `/api/create-activities` | POST | Bulk create activities |
573
- | `/api/update-activities` | POST | Bulk update activities |
574
-
575
- **Flow:**
576
- 1. User changes Activity A in Hailer
577
- 2. Function field calculates JSON payload for createMany/updateMany
578
- 3. Webhook fires → POST to endpoint
579
- 4. Monolith reads the function field's JSON value
580
- 5. Executes `v3.activity.createMany` or `v3.activity.updateMany`
581
-
582
- **Critical Constraints:**
583
-
584
- - **Single-workflow per call:** `updateMany` operates on ONE workflow at a time. For cascading updates to multiple target workflows, create separate function fields and separate config entries (one per target).
585
- - **Config key uniqueness:** When one source workflow triggers updates to multiple target workflows, use pattern `"workflowId_suffix"` (e.g., `"68ca89ca..._tila"`, `"68ca89ca..._henkilo"`). Each config entry points to a different function field.
586
-
587
- **Config Structure:**
588
- ```typescript
589
- {
590
- "[workspaceId]": {
591
- "credentials": { email, password },
592
- "[workflowId_suffix]": {
593
- "fieldId": "field-id-containing-json-payload",
594
- "description": "Human-readable description"
595
- }
596
- }
597
- }
598
- ```
599
-
600
- **Field Payload Format:**
601
-
602
- For `/create-activities`:
603
- ```json
604
- [
605
- { "name": "New Activity", "fields": { "amount": 100 } }
606
- ]
607
- ```
608
-
609
- For `/update-activities`:
610
- ```json
611
- [
612
- { "_id": "activity-id", "fields": { "status": "completed" } }
613
- ]
614
- ```
615
-
616
- **CRITICAL: Double-Wrapped Array for Updates**
617
-
618
- The monolith generic handler spreads parsed JSON as arguments to `client.request()`. Function fields must output **double-wrapped array** `[[{_id, phaseId}, ...]]` so the first argument to `updateMany` is the array of updates.
619
-
620
- **Correct (double-wrapped):**
621
- ```javascript
622
- const updates = linkedFrom('tasks-workflow').map(task => ({
623
- _id: task._id,
624
- fields: { parentStatus: field('status') }
625
- }));
626
- return JSON.stringify([updates]); // ← double wrap
627
- ```
628
-
629
- **Wrong (single-wrapped):** Causes "must be an array" validation error
630
- ```javascript
631
- return JSON.stringify(updates); // ← single wrap - FAILS
632
- ```
633
-
634
- **Example function field (builds payload):**
635
- ```javascript
636
- const tasks = linkedFrom('tasks-workflow');
637
- const newStatus = field('status');
638
- return JSON.stringify([
639
- tasks.map(task => ({
640
- _id: task._id,
641
- fields: { parentStatus: newStatus }
642
- }))
643
- ]);
644
- ```
645
-
646
- **Setup Steps:**
647
-
648
- 1. **Create AWS Config** - Add workspace to `monolith-generic-create-update` in AWS Secrets Manager:
649
- ```json
650
- {
651
- "your-workspace-id": {
652
- "credentials": { "email": "bot@company.com", "password": "xxx" },
653
- "your-workflow-id": {
654
- "fieldId": "your-json-field-id",
655
- "description": "What this automation does"
656
- }
657
- }
658
- }
659
- ```
660
-
661
- 2. **Create Function Field** - In Hailer workflow, create a TEXT or function field that outputs the JSON payload (the `fieldId` in config must match this field).
662
-
663
- 3. **Configure Webhook** - In Hailer workflow settings:
664
- - URL: `https://monolith-url/api/create-activities` or `/api/update-activities`
665
- - Trigger: On activity update (or specific phase)
666
- - Method: POST
667
-
668
- **Use Cases:**
669
- - Create child records (order → line items)
670
- - Cascade updates (project status → task statuses)
671
- - Sync calculated data (pricing → quotes)
672
-
673
- ---
674
-
675
- ## Reference
676
-
677
- **Location:** `~/hailer-integration/packages/project-monolith/`
678
-
679
- **Run locally:**
680
- ```bash
681
- npm run start:local
682
- ```
683
-
684
- **Deploy:** Via GitLab CI/CD pipeline
685
-
686
- **Logs:** CloudWatch (production), console (local)