@cakemail-org/cakemail-cli 1.5.0 → 2.0.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 (234) hide show
  1. package/.claude/settings.local.json +12 -0
  2. package/.env.example +40 -0
  3. package/.env.test.example +45 -0
  4. package/CHANGELOG.md +1031 -0
  5. package/README.md +319 -15
  6. package/audit-formats.js +128 -0
  7. package/cakemail.rb +20 -0
  8. package/dist/cli.js +27 -10
  9. package/dist/cli.js.map +1 -1
  10. package/dist/client.d.ts +2 -0
  11. package/dist/client.d.ts.map +1 -1
  12. package/dist/client.js +16 -6
  13. package/dist/client.js.map +1 -1
  14. package/dist/commands/account.js +1 -1
  15. package/dist/commands/account.js.map +1 -1
  16. package/dist/commands/attributes.js +1 -1
  17. package/dist/commands/attributes.js.map +1 -1
  18. package/dist/commands/campaigns.d.ts.map +1 -1
  19. package/dist/commands/campaigns.js +103 -8
  20. package/dist/commands/campaigns.js.map +1 -1
  21. package/dist/commands/config.d.ts.map +1 -1
  22. package/dist/commands/config.js +63 -4
  23. package/dist/commands/config.js.map +1 -1
  24. package/dist/commands/contacts.d.ts.map +1 -1
  25. package/dist/commands/contacts.js +91 -12
  26. package/dist/commands/contacts.js.map +1 -1
  27. package/dist/commands/emails.js +1 -1
  28. package/dist/commands/emails.js.map +1 -1
  29. package/dist/commands/interests.d.ts +5 -0
  30. package/dist/commands/interests.d.ts.map +1 -0
  31. package/dist/commands/interests.js +172 -0
  32. package/dist/commands/interests.js.map +1 -0
  33. package/dist/commands/lists.d.ts.map +1 -1
  34. package/dist/commands/lists.js +6 -8
  35. package/dist/commands/lists.js.map +1 -1
  36. package/dist/commands/logs.d.ts +5 -0
  37. package/dist/commands/logs.d.ts.map +1 -0
  38. package/dist/commands/logs.js +237 -0
  39. package/dist/commands/logs.js.map +1 -0
  40. package/dist/commands/reports.js +1 -1
  41. package/dist/commands/reports.js.map +1 -1
  42. package/dist/commands/segments.js +1 -1
  43. package/dist/commands/segments.js.map +1 -1
  44. package/dist/commands/senders.d.ts.map +1 -1
  45. package/dist/commands/senders.js +11 -8
  46. package/dist/commands/senders.js.map +1 -1
  47. package/dist/commands/suppressed.js +1 -1
  48. package/dist/commands/suppressed.js.map +1 -1
  49. package/dist/commands/tags.d.ts +5 -0
  50. package/dist/commands/tags.d.ts.map +1 -0
  51. package/dist/commands/tags.js +124 -0
  52. package/dist/commands/tags.js.map +1 -0
  53. package/dist/commands/templates.js +1 -1
  54. package/dist/commands/templates.js.map +1 -1
  55. package/dist/commands/transactional-templates.d.ts +5 -0
  56. package/dist/commands/transactional-templates.d.ts.map +1 -0
  57. package/dist/commands/transactional-templates.js +354 -0
  58. package/dist/commands/transactional-templates.js.map +1 -0
  59. package/dist/commands/webhooks.js +1 -1
  60. package/dist/commands/webhooks.js.map +1 -1
  61. package/dist/utils/auth.d.ts +8 -1
  62. package/dist/utils/auth.d.ts.map +1 -1
  63. package/dist/utils/auth.js +39 -11
  64. package/dist/utils/auth.js.map +1 -1
  65. package/dist/utils/config-file.d.ts +7 -0
  66. package/dist/utils/config-file.d.ts.map +1 -1
  67. package/dist/utils/config-file.js +15 -0
  68. package/dist/utils/config-file.js.map +1 -1
  69. package/dist/utils/config.d.ts +2 -0
  70. package/dist/utils/config.d.ts.map +1 -1
  71. package/dist/utils/config.js +12 -4
  72. package/dist/utils/config.js.map +1 -1
  73. package/dist/utils/errors.js +1 -1
  74. package/dist/utils/errors.js.map +1 -1
  75. package/dist/utils/list-defaults.d.ts +33 -0
  76. package/dist/utils/list-defaults.d.ts.map +1 -0
  77. package/dist/utils/list-defaults.js +52 -0
  78. package/dist/utils/list-defaults.js.map +1 -0
  79. package/dist/utils/output.d.ts.map +1 -1
  80. package/dist/utils/output.js +36 -13
  81. package/dist/utils/output.js.map +1 -1
  82. package/dist/utils/progress.d.ts.map +1 -1
  83. package/dist/utils/progress.js +32 -4
  84. package/dist/utils/progress.js.map +1 -1
  85. package/dist/utils/spinner.d.ts +17 -0
  86. package/dist/utils/spinner.d.ts.map +1 -0
  87. package/dist/utils/spinner.js +43 -0
  88. package/dist/utils/spinner.js.map +1 -0
  89. package/docs/DOCUMENTATION-STANDARD.md +1068 -0
  90. package/docs/README.md +161 -0
  91. package/docs/developer/ARCHITECTURE.md +516 -0
  92. package/docs/developer/AUTH.md +204 -0
  93. package/docs/developer/CONTRIBUTING.md +227 -0
  94. package/docs/developer/DOCUMENTATION_SUMMARY.md +346 -0
  95. package/docs/developer/PROJECT_INDEX.md +365 -0
  96. package/docs/planning/API_COVERAGE.md +1045 -0
  97. package/docs/planning/BACKLOG.md +1159 -0
  98. package/docs/planning/PROFILE_SYSTEM_TASKS.md +287 -0
  99. package/docs/planning/UX_IMPLEMENTATION_PLAN.md +691 -0
  100. package/docs/planning/archive/RELEASE_CHECKLIST_v1.3.0.md +332 -0
  101. package/docs/planning/archive/RELEASE_v1.3.0.md +428 -0
  102. package/docs/planning/archive/cakemail-cli-ux-improvements.md +438 -0
  103. package/docs/planning/cakemail-profile-system-plan.md +1121 -0
  104. package/docs/testing/AI_USER_SIMULATION_DESIGN.md +1342 -0
  105. package/docs/testing/KENOGAMI_BIDIRECTIONAL_FLOW.md +1517 -0
  106. package/docs/testing/KENOGAMI_TRUTH_RECONCILIATION_SYSTEM.md +1369 -0
  107. package/docs/user-manual/.obsidian/app.json +1 -0
  108. package/docs/user-manual/.obsidian/appearance.json +1 -0
  109. package/docs/user-manual/.obsidian/core-plugins.json +33 -0
  110. package/docs/user-manual/.obsidian/workspace.json +167 -0
  111. package/docs/user-manual/01-getting-started/01-installation.md +214 -0
  112. package/docs/user-manual/01-getting-started/02-quick-start.md +432 -0
  113. package/docs/user-manual/01-getting-started/03-authentication.md +448 -0
  114. package/docs/user-manual/01-getting-started/04-configuration.md +430 -0
  115. package/docs/user-manual/01-getting-started/05-output-formats.md +447 -0
  116. package/docs/user-manual/02-core-concepts/01-accounts.md +514 -0
  117. package/docs/user-manual/02-core-concepts/02-profile-system.md +771 -0
  118. package/docs/user-manual/02-core-concepts/03-smart-defaults.md +485 -0
  119. package/docs/user-manual/02-core-concepts/04-authentication-methods.md +435 -0
  120. package/docs/user-manual/02-core-concepts/05-pagination-filtering.md +600 -0
  121. package/docs/user-manual/02-core-concepts/06-error-handling.md +718 -0
  122. package/docs/user-manual/02-core-concepts/07-api-coverage.md +483 -0
  123. package/docs/user-manual/03-email-operations/01-senders.md +490 -0
  124. package/docs/user-manual/03-email-operations/02-templates.md +444 -0
  125. package/docs/user-manual/03-email-operations/03-transactional-emails.md +706 -0
  126. package/docs/user-manual/03-email-operations/04-email-tracking.md +407 -0
  127. package/docs/user-manual/04-campaign-management/01-campaigns-basics.md +394 -0
  128. package/docs/user-manual/04-campaign-management/02-campaign-scheduling.md +630 -0
  129. package/docs/user-manual/04-campaign-management/03-campaign-testing.md +997 -0
  130. package/docs/user-manual/04-campaign-management/04-campaign-lifecycle.md +709 -0
  131. package/docs/user-manual/04-campaign-management/05-campaign-links.md +934 -0
  132. package/docs/user-manual/05-contact-management/01-lists.md +836 -0
  133. package/docs/user-manual/05-contact-management/02-contacts.md +1035 -0
  134. package/docs/user-manual/05-contact-management/03-custom-attributes.md +788 -0
  135. package/docs/user-manual/05-contact-management/04-segments.md +1028 -0
  136. package/docs/user-manual/05-contact-management/05-contact-import-export.md +1031 -0
  137. package/docs/user-manual/06-analytics-reporting/01-campaign-analytics.md +867 -0
  138. package/docs/user-manual/06-analytics-reporting/02-account-reports.md +227 -0
  139. package/docs/user-manual/07-integrations/01-webhooks-integration.md +259 -0
  140. package/docs/user-manual/07-integrations/02-automation.md +326 -0
  141. package/docs/user-manual/08-advanced-usage/01-scripting-patterns.md +672 -0
  142. package/docs/user-manual/08-advanced-usage/02-bulk-operations.md +932 -0
  143. package/docs/user-manual/08-advanced-usage/03-ci-cd-integration.md +892 -0
  144. package/docs/user-manual/08-advanced-usage/04-performance-optimization.md +766 -0
  145. package/docs/user-manual/09-command-reference/01-config.md +776 -0
  146. package/docs/user-manual/09-command-reference/02-account.md +652 -0
  147. package/docs/user-manual/09-command-reference/03-lists.md +958 -0
  148. package/docs/user-manual/09-command-reference/04-contacts.md +1408 -0
  149. package/docs/user-manual/09-command-reference/05-attributes.md +617 -0
  150. package/docs/user-manual/09-command-reference/06-segments.md +894 -0
  151. package/docs/user-manual/09-command-reference/07-senders.md +803 -0
  152. package/docs/user-manual/09-command-reference/08-templates.md +818 -0
  153. package/docs/user-manual/09-command-reference/09-campaigns.md +1250 -0
  154. package/docs/user-manual/09-command-reference/10-emails.md +807 -0
  155. package/docs/user-manual/09-command-reference/11-reports.md +1135 -0
  156. package/docs/user-manual/09-command-reference/12-webhooks.md +773 -0
  157. package/docs/user-manual/09-command-reference/13-suppressed.md +797 -0
  158. package/docs/user-manual/09-command-reference/14-interests.md +630 -0
  159. package/docs/user-manual/09-command-reference/15-tags.md +584 -0
  160. package/docs/user-manual/09-command-reference/16-logs.md +656 -0
  161. package/docs/user-manual/09-command-reference/17-transactional-templates.md +850 -0
  162. package/docs/user-manual/10-troubleshooting/01-common-errors.md +457 -0
  163. package/docs/user-manual/10-troubleshooting/02-authentication-issues.md +558 -0
  164. package/docs/user-manual/10-troubleshooting/03-connection-problems.md +634 -0
  165. package/docs/user-manual/10-troubleshooting/04-debugging.md +725 -0
  166. package/docs/user-manual/11-appendix/04-faq.md +484 -0
  167. package/docs/user-manual/11-appendix/05-glossary.md +250 -0
  168. package/docs/user-manual/README.md +0 -0
  169. package/package.json +13 -47
  170. package/src/cli.ts +125 -0
  171. package/src/client.ts +16 -0
  172. package/src/commands/account.ts +267 -0
  173. package/src/commands/accounts.ts +78 -0
  174. package/src/commands/actions.ts +249 -0
  175. package/src/commands/attributes.ts +139 -0
  176. package/src/commands/campaign-blueprints.ts +106 -0
  177. package/src/commands/campaigns.ts +469 -0
  178. package/src/commands/config.ts +77 -0
  179. package/src/commands/contacts.ts +612 -0
  180. package/src/commands/custom-attributes.ts +127 -0
  181. package/src/commands/dkims.ts +117 -0
  182. package/src/commands/domains.ts +82 -0
  183. package/src/commands/email-apis.ts +569 -0
  184. package/src/commands/emails.ts +197 -0
  185. package/src/commands/forms.ts +283 -0
  186. package/src/commands/interests.ts +155 -0
  187. package/src/commands/links.ts +38 -0
  188. package/src/commands/lists.ts +406 -0
  189. package/src/commands/logos.ts +71 -0
  190. package/src/commands/logs.ts +386 -0
  191. package/src/commands/reports.ts +306 -0
  192. package/src/commands/segments.ts +158 -0
  193. package/src/commands/senders.ts +204 -0
  194. package/src/commands/sub-accounts.ts +271 -0
  195. package/src/commands/suppressed-emails.ts +234 -0
  196. package/src/commands/suppressed.ts +198 -0
  197. package/src/commands/system-emails.ts +85 -0
  198. package/src/commands/tags.ts +146 -0
  199. package/src/commands/tasks.ts +116 -0
  200. package/src/commands/templates.ts +189 -0
  201. package/src/commands/tokens.ts +83 -0
  202. package/src/commands/transactional-emails.ts +374 -0
  203. package/src/commands/transactional-templates.ts +385 -0
  204. package/src/commands/users.ts +506 -0
  205. package/src/commands/webhooks.ts +172 -0
  206. package/src/commands/workflow-blueprints.ts +123 -0
  207. package/src/commands/workflows.ts +265 -0
  208. package/src/types/profile.ts +93 -0
  209. package/src/utils/auth.ts +272 -0
  210. package/src/utils/config-file.ts +96 -0
  211. package/src/utils/config.ts +134 -0
  212. package/src/utils/confirm.ts +32 -0
  213. package/src/utils/defaults.ts +99 -0
  214. package/src/utils/errors.ts +116 -0
  215. package/src/utils/interactive.ts +91 -0
  216. package/src/utils/list-defaults.ts +74 -0
  217. package/src/utils/output.ts +190 -0
  218. package/src/utils/progress.ts +320 -0
  219. package/src/utils/spinner.ts +22 -0
  220. package/tests/IMPLEMENTATION_STATUS.md +258 -0
  221. package/tests/PTY_SETUP.md +118 -0
  222. package/tests/PTY_TESTING_GUIDE.md +507 -0
  223. package/tests/README.md +244 -0
  224. package/tests/fixtures/api-responses/campaigns.json +34 -0
  225. package/tests/fixtures/test-config.json +13 -0
  226. package/tests/helpers/cli-runner.ts +128 -0
  227. package/tests/helpers/mock-server.ts +301 -0
  228. package/tests/helpers/pty-runner.ts +181 -0
  229. package/tests/integration/campaigns-real-api.test.ts +196 -0
  230. package/tests/integration/setup-integration.ts +50 -0
  231. package/tests/pty/campaigns.test.ts +241 -0
  232. package/tests/setup.ts +34 -0
  233. package/tsconfig.json +15 -0
  234. package/vitest.config.ts +28 -0
@@ -0,0 +1,709 @@
1
+ # Campaign Lifecycle
2
+
3
+ Understand and manage campaigns through every stage from creation to completion.
4
+
5
+ ## Lifecycle Overview
6
+
7
+ Campaigns move through distinct states:
8
+
9
+ ```
10
+ draft → scheduled → sending → sent → archived
11
+ ↓ ↓ ↓
12
+ delete unschedule suspend/cancel
13
+ ```
14
+
15
+ ## Campaign States
16
+
17
+ ### Draft
18
+
19
+ **Description:** Newly created, not yet scheduled
20
+
21
+ **Available Actions:**
22
+ - Edit content, subject, list, sender
23
+ - Send test emails
24
+ - Schedule for delivery
25
+ - Delete
26
+
27
+ **Commands:**
28
+ ```bash
29
+ # Update draft
30
+ $ cakemail campaigns update 790 --subject "New Subject"
31
+
32
+ # Send test
33
+ $ cakemail campaigns test 790 -e test@example.com
34
+
35
+ # Schedule
36
+ $ cakemail campaigns schedule 790
37
+
38
+ # Delete if not needed
39
+ $ cakemail campaigns delete 790 --force
40
+ ```
41
+
42
+ ### Scheduled
43
+
44
+ **Description:** Queued for future delivery
45
+
46
+ **Available Actions:**
47
+ - Reschedule to different time
48
+ - Unschedule (return to draft)
49
+ - Send test emails
50
+ - Cancel
51
+
52
+ **Commands:**
53
+ ```bash
54
+ # Reschedule
55
+ $ cakemail campaigns reschedule 790 --when "2024-03-25 10:00:00"
56
+
57
+ # Unschedule (back to draft)
58
+ $ cakemail campaigns unschedule 790
59
+
60
+ # Cancel
61
+ $ cakemail campaigns cancel 790
62
+ ```
63
+
64
+ ### Sending
65
+
66
+ **Description:** Currently being sent to recipients
67
+
68
+ **Available Actions:**
69
+ - Suspend (pause sending)
70
+ - View progress
71
+ - Monitor statistics
72
+
73
+ **Commands:**
74
+ ```bash
75
+ # Suspend sending
76
+ $ cakemail campaigns suspend 790
77
+
78
+ # Check progress
79
+ $ cakemail campaigns get 790 -f json | jq '{status, sent_count, total_recipients}'
80
+
81
+ # View real-time stats
82
+ $ cakemail reports campaign 790
83
+ ```
84
+
85
+ ### Sent
86
+
87
+ **Description:** Completed successfully
88
+
89
+ **Available Actions:**
90
+ - View analytics
91
+ - Archive
92
+ - Delete (removes from list)
93
+
94
+ **Commands:**
95
+ ```bash
96
+ # View analytics
97
+ $ cakemail reports campaign 790
98
+
99
+ # View link clicks
100
+ $ cakemail reports campaign-links 790
101
+
102
+ # Archive
103
+ $ cakemail campaigns archive 790
104
+
105
+ # Delete
106
+ $ cakemail campaigns delete 790 --force
107
+ ```
108
+
109
+ ### Suspended
110
+
111
+ **Description:** Paused during sending
112
+
113
+ **Available Actions:**
114
+ - Resume sending
115
+ - Cancel (stops permanently)
116
+ - View partial statistics
117
+
118
+ **Commands:**
119
+ ```bash
120
+ # Resume
121
+ $ cakemail campaigns resume 790
122
+
123
+ # Cancel permanently
124
+ $ cakemail campaigns cancel 790
125
+
126
+ # Check stats
127
+ $ cakemail reports campaign 790
128
+ ```
129
+
130
+ ### Cancelled
131
+
132
+ **Description:** Cancelled before/during send
133
+
134
+ **Available Actions:**
135
+ - View partial analytics
136
+ - Archive
137
+ - Delete
138
+
139
+ **Commands:**
140
+ ```bash
141
+ # View what was sent
142
+ $ cakemail reports campaign 790
143
+
144
+ # Archive
145
+ $ cakemail campaigns archive 790
146
+ ```
147
+
148
+ ### Archived
149
+
150
+ **Description:** Hidden from default views
151
+
152
+ **Available Actions:**
153
+ - Unarchive (restore to view)
154
+ - View analytics
155
+ - Delete permanently
156
+
157
+ **Commands:**
158
+ ```bash
159
+ # Unarchive
160
+ $ cakemail campaigns unarchive 790
161
+
162
+ # View
163
+ $ cakemail campaigns get 790
164
+
165
+ # Delete
166
+ $ cakemail campaigns delete 790 --force
167
+ ```
168
+
169
+ ## Managing Active Campaigns
170
+
171
+ ### Suspending a Campaign
172
+
173
+ Pause campaign mid-send:
174
+
175
+ ```bash
176
+ $ cakemail campaigns suspend 790
177
+ ```
178
+
179
+ **Output:**
180
+ ```
181
+ ✓ Campaign 790 suspended
182
+ ```
183
+
184
+ **When to suspend:**
185
+ - Content error discovered
186
+ - Wrong list selected
187
+ - Need to make urgent changes
188
+ - Technical issue with website/links
189
+
190
+ **What happens:**
191
+ - Sending stops immediately
192
+ - Emails already sent remain sent
193
+ - Remaining recipients not contacted
194
+ - Can resume or cancel later
195
+
196
+ ### Resuming a Campaign
197
+
198
+ Continue suspended campaign:
199
+
200
+ ```bash
201
+ $ cakemail campaigns resume 790
202
+ ```
203
+
204
+ **Output:**
205
+ ```
206
+ ✓ Campaign 790 resumed
207
+ ```
208
+
209
+ **Considerations:**
210
+ - Resumes from where it stopped
211
+ - Already-sent contacts not re-contacted
212
+ - Check time delay impact on results
213
+
214
+ ### Cancelling a Campaign
215
+
216
+ Permanently stop campaign:
217
+
218
+ ```bash
219
+ $ cakemail campaigns cancel 790
220
+ ```
221
+
222
+ **Output:**
223
+ ```
224
+ ⚠ Cancel campaign 790?
225
+
226
+ The following will happen:
227
+ • Campaign will be permanently cancelled
228
+ • Remaining recipients will not receive email
229
+ • Partial analytics available
230
+
231
+ Type 'yes' to confirm: yes
232
+
233
+ ✓ Campaign 790 cancelled
234
+ ```
235
+
236
+ **When to cancel:**
237
+ - Major error in content
238
+ - Wrong audience targeted
239
+ - Business reason (product recall, etc.)
240
+ - Regulatory/legal requirement
241
+
242
+ ## Archiving Campaigns
243
+
244
+ ### Archive Completed Campaigns
245
+
246
+ Remove from active view:
247
+
248
+ ```bash
249
+ $ cakemail campaigns archive 790
250
+ ```
251
+
252
+ **Output:**
253
+ ```
254
+ ✓ Campaign 790 archived
255
+ ```
256
+
257
+ **Benefits:**
258
+ - Cleaner campaign list
259
+ - Organized historical data
260
+ - Still accessible for analytics
261
+ - Can be unarchived if needed
262
+
263
+ ### Bulk Archive
264
+
265
+ Archive multiple campaigns:
266
+
267
+ ```bash
268
+ #!/bin/bash
269
+ # archive-old-campaigns.sh
270
+
271
+ # Archive all campaigns from Q1 2024
272
+ CAMPAIGNS=$(cakemail campaigns list \
273
+ --filter "status==sent;delivered_at>=2024-01-01;delivered_at<2024-04-01" \
274
+ -f json | jq -r '.data[].id')
275
+
276
+ for ID in $CAMPAIGNS; do
277
+ echo "Archiving campaign $ID..."
278
+ cakemail campaigns archive $ID
279
+ done
280
+
281
+ echo "Archived $(echo "$CAMPAIGNS" | wc -l) campaigns"
282
+ ```
283
+
284
+ ### Archive by Age
285
+
286
+ ```bash
287
+ #!/bin/bash
288
+ # archive-by-age.sh
289
+
290
+ # Archive campaigns older than 90 days
291
+ CUTOFF_DATE=$(date -d "90 days ago" +%Y-%m-%d)
292
+
293
+ CAMPAIGNS=$(cakemail campaigns list \
294
+ --filter "status==sent;delivered_at<$CUTOFF_DATE" \
295
+ -f json | jq -r '.data[].id')
296
+
297
+ for ID in $CAMPAIGNS; do
298
+ NAME=$(cakemail campaigns get $ID -f json | jq -r '.name')
299
+ echo "Archiving: $NAME (ID: $ID)"
300
+ cakemail campaigns archive $ID
301
+ done
302
+ ```
303
+
304
+ ### Unarchive Campaigns
305
+
306
+ Restore archived campaign to active view:
307
+
308
+ ```bash
309
+ $ cakemail campaigns unarchive 790
310
+ ```
311
+
312
+ **Output:**
313
+ ```
314
+ ✓ Campaign 790 unarchived
315
+ ```
316
+
317
+ ## Monitoring Campaigns
318
+
319
+ ### Real-Time Status Check
320
+
321
+ ```bash
322
+ #!/bin/bash
323
+ # monitor-campaign.sh
324
+
325
+ CAMPAIGN_ID=$1
326
+ INTERVAL=5 # seconds
327
+
328
+ while true; do
329
+ clear
330
+ echo "=== Campaign $CAMPAIGN_ID Status ==="
331
+ echo ""
332
+
333
+ STATUS=$(cakemail campaigns get $CAMPAIGN_ID -f json)
334
+
335
+ echo "Status: $(echo "$STATUS" | jq -r '.status')"
336
+ echo "Name: $(echo "$STATUS" | jq -r '.name')"
337
+ echo ""
338
+
339
+ # If sending, show progress
340
+ if [ "$(echo "$STATUS" | jq -r '.status')" == "sending" ]; then
341
+ SENT=$(echo "$STATUS" | jq -r '.sent_count // 0')
342
+ TOTAL=$(echo "$STATUS" | jq -r '.total_recipients // 0')
343
+ PERCENT=$(echo "scale=1; $SENT * 100 / $TOTAL" | bc)
344
+
345
+ echo "Progress: $SENT / $TOTAL ($PERCENT%)"
346
+ echo ""
347
+
348
+ # Get stats
349
+ STATS=$(cakemail reports campaign $CAMPAIGN_ID -f json)
350
+ echo "Delivered: $(echo "$STATS" | jq -r '.delivered // 0')"
351
+ echo "Opened: $(echo "$STATS" | jq -r '.unique_opens // 0')"
352
+ echo "Clicked: $(echo "$STATS" | jq -r '.unique_clicks // 0')"
353
+ fi
354
+
355
+ echo ""
356
+ echo "Press Ctrl+C to stop monitoring"
357
+ sleep $INTERVAL
358
+ done
359
+ ```
360
+
361
+ ### Dashboard View
362
+
363
+ ```bash
364
+ #!/bin/bash
365
+ # campaign-dashboard.sh
366
+
367
+ echo "=== Campaign Dashboard ==="
368
+ echo ""
369
+
370
+ # Scheduled
371
+ SCHEDULED=$(cakemail campaigns list --filter "status==scheduled" -f json | jq '.count')
372
+ echo "Scheduled: $SCHEDULED"
373
+
374
+ # Sending
375
+ SENDING=$(cakemail campaigns list --filter "status==sending" -f json | jq '.count')
376
+ echo "Sending: $SENDING"
377
+
378
+ # Sent today
379
+ TODAY=$(date +%Y-%m-%d)
380
+ SENT_TODAY=$(cakemail campaigns list \
381
+ --filter "status==sent;delivered_at>=$TODAY" \
382
+ -f json | jq '.count')
383
+ echo "Sent Today: $SENT_TODAY"
384
+
385
+ # Drafts
386
+ DRAFTS=$(cakemail campaigns list --filter "status==draft" -f json | jq '.count')
387
+ echo "Drafts: $DRAFTS"
388
+
389
+ echo ""
390
+
391
+ # Show active campaigns
392
+ echo "=== Active Campaigns ==="
393
+ cakemail campaigns list --filter "status==sending" -f compact
394
+ ```
395
+
396
+ ## Lifecycle Workflows
397
+
398
+ ### Workflow 1: Emergency Stop
399
+
400
+ ```bash
401
+ #!/bin/bash
402
+ # emergency-stop.sh
403
+
404
+ CAMPAIGN_ID=$1
405
+
406
+ if [ -z "$CAMPAIGN_ID" ]; then
407
+ echo "Usage: $0 <campaign-id>"
408
+ exit 1
409
+ fi
410
+
411
+ echo "⚠️ EMERGENCY STOP for Campaign $CAMPAIGN_ID"
412
+ echo ""
413
+
414
+ # Check current status
415
+ STATUS=$(cakemail campaigns get $CAMPAIGN_ID -f json | jq -r '.status')
416
+ echo "Current status: $STATUS"
417
+
418
+ case $STATUS in
419
+ "scheduled")
420
+ echo "Unscheduling..."
421
+ cakemail campaigns unschedule $CAMPAIGN_ID
422
+ ;;
423
+ "sending")
424
+ echo "Suspending..."
425
+ cakemail campaigns suspend $CAMPAIGN_ID
426
+ ;;
427
+ *)
428
+ echo "Campaign is $STATUS - no action needed"
429
+ ;;
430
+ esac
431
+
432
+ echo ""
433
+ echo "✅ Emergency stop complete"
434
+ ```
435
+
436
+ ### Workflow 2: Scheduled Maintenance
437
+
438
+ ```bash
439
+ #!/bin/bash
440
+ # scheduled-maintenance.sh
441
+
442
+ echo "=== Pre-Maintenance: Suspend Active Campaigns ==="
443
+
444
+ # Get all sending campaigns
445
+ SENDING=$(cakemail campaigns list --filter "status==sending" -f json)
446
+ SENDING_IDS=$(echo "$SENDING" | jq -r '.data[].id')
447
+
448
+ # Suspend each
449
+ for ID in $SENDING_IDS; do
450
+ echo "Suspending campaign $ID..."
451
+ cakemail campaigns suspend $ID
452
+ done
453
+
454
+ echo ""
455
+ echo "Suspended $(echo "$SENDING_IDS" | wc -l) campaigns"
456
+ echo "IDs: $SENDING_IDS"
457
+ echo ""
458
+ echo "Save these IDs to resume after maintenance!"
459
+ ```
460
+
461
+ Resume after maintenance:
462
+
463
+ ```bash
464
+ #!/bin/bash
465
+ # resume-after-maintenance.sh
466
+
467
+ # IDs from previous script
468
+ CAMPAIGN_IDS="790 791 792"
469
+
470
+ echo "=== Post-Maintenance: Resume Campaigns ==="
471
+
472
+ for ID in $CAMPAIGN_IDS; do
473
+ echo "Resuming campaign $ID..."
474
+ cakemail campaigns resume $ID
475
+ done
476
+
477
+ echo ""
478
+ echo "✅ All campaigns resumed"
479
+ ```
480
+
481
+ ### Workflow 3: Quarterly Archival
482
+
483
+ ```bash
484
+ #!/bin/bash
485
+ # quarterly-archive.sh
486
+
487
+ YEAR=$1
488
+ QUARTER=$2
489
+
490
+ if [ -z "$YEAR" ] || [ -z "$QUARTER" ]; then
491
+ echo "Usage: $0 <year> <quarter>"
492
+ echo "Example: $0 2024 1"
493
+ exit 1
494
+ fi
495
+
496
+ # Calculate date range
497
+ case $QUARTER in
498
+ 1) START="$YEAR-01-01"; END="$YEAR-03-31" ;;
499
+ 2) START="$YEAR-04-01"; END="$YEAR-06-30" ;;
500
+ 3) START="$YEAR-07-01"; END="$YEAR-09-30" ;;
501
+ 4) START="$YEAR-10-01"; END="$YEAR-12-31" ;;
502
+ *) echo "Invalid quarter"; exit 1 ;;
503
+ esac
504
+
505
+ echo "Archiving Q$QUARTER $YEAR campaigns ($START to $END)..."
506
+
507
+ # Get campaigns
508
+ CAMPAIGNS=$(cakemail campaigns list \
509
+ --filter "status==sent;delivered_at>=$START;delivered_at<=$END" \
510
+ -f json | jq -r '.data[].id')
511
+
512
+ COUNT=0
513
+ for ID in $CAMPAIGNS; do
514
+ cakemail campaigns archive $ID
515
+ ((COUNT++))
516
+ done
517
+
518
+ echo ""
519
+ echo "✅ Archived $COUNT campaigns from Q$QUARTER $YEAR"
520
+ ```
521
+
522
+ ### Workflow 4: Campaign Health Check
523
+
524
+ ```bash
525
+ #!/bin/bash
526
+ # health-check.sh
527
+
528
+ echo "=== Campaign Health Check ==="
529
+ echo ""
530
+
531
+ # Check for stuck campaigns
532
+ echo "Checking for stuck campaigns..."
533
+ SENDING=$(cakemail campaigns list --filter "status==sending" -f json)
534
+ SENDING_COUNT=$(echo "$SENDING" | jq '.count')
535
+
536
+ if [ "$SENDING_COUNT" -gt 0 ]; then
537
+ echo "$SENDING" | jq -r '.data[] | " ID: \(.id) - Started: \(.sending_started_at // "unknown")"'
538
+
539
+ # Flag campaigns sending > 2 hours
540
+ CUTOFF=$(date -d "2 hours ago" --iso-8601=seconds)
541
+ STUCK=$(echo "$SENDING" | jq --arg cutoff "$CUTOFF" '
542
+ .data[] | select(.sending_started_at < $cutoff)
543
+ ')
544
+
545
+ if [ -n "$STUCK" ]; then
546
+ echo ""
547
+ echo "⚠️ Warning: Campaigns sending > 2 hours:"
548
+ echo "$STUCK" | jq -r '" ID: \(.id) - \(.name)"'
549
+ fi
550
+ else
551
+ echo " ✅ No campaigns currently sending"
552
+ fi
553
+
554
+ echo ""
555
+
556
+ # Check for scheduled campaigns in past
557
+ echo "Checking for past-due scheduled campaigns..."
558
+ NOW=$(date --iso-8601=seconds)
559
+ PAST_DUE=$(cakemail campaigns list --filter "status==scheduled" -f json | \
560
+ jq --arg now "$NOW" '.data[] | select(.scheduled_for < $now)')
561
+
562
+ if [ -n "$PAST_DUE" ]; then
563
+ echo "⚠️ Warning: Past-due scheduled campaigns:"
564
+ echo "$PAST_DUE" | jq -r '" ID: \(.id) - Scheduled: \(.scheduled_for)"'
565
+ else
566
+ echo " ✅ No past-due campaigns"
567
+ fi
568
+
569
+ echo ""
570
+
571
+ # Check for old drafts
572
+ echo "Checking for old drafts (> 30 days)..."
573
+ OLD_CUTOFF=$(date -d "30 days ago" +%Y-%m-%d)
574
+ OLD_DRAFTS=$(cakemail campaigns list \
575
+ --filter "status==draft;created_on<$OLD_CUTOFF" \
576
+ -f json | jq '.count')
577
+
578
+ echo " Old drafts: $OLD_DRAFTS"
579
+
580
+ if [ "$OLD_DRAFTS" -gt 0 ]; then
581
+ echo " Consider cleaning up old drafts"
582
+ fi
583
+
584
+ echo ""
585
+ echo "✅ Health check complete"
586
+ ```
587
+
588
+ ## Best Practices
589
+
590
+ ### 1. Monitor Active Campaigns
591
+
592
+ Set up automated monitoring:
593
+
594
+ ```bash
595
+ # Add to crontab: every 5 minutes
596
+ */5 * * * * /path/to/monitor-campaigns.sh >> /var/log/campaign-monitor.log 2>&1
597
+ ```
598
+
599
+ ### 2. Archive Regularly
600
+
601
+ Monthly archival routine:
602
+
603
+ ```bash
604
+ # First day of each month
605
+ 0 0 1 * * /path/to/monthly-archive.sh
606
+ ```
607
+
608
+ ### 3. Emergency Procedures
609
+
610
+ Document emergency contacts and procedures:
611
+
612
+ ```bash
613
+ #!/bin/bash
614
+ # EMERGENCY.sh
615
+
616
+ echo "=== EMERGENCY CAMPAIGN PROCEDURES ==="
617
+ echo ""
618
+ echo "1. Suspend all sending: ./emergency-stop-all.sh"
619
+ echo "2. Contact: support@cakemail.com"
620
+ echo "3. Escalation: +1-XXX-XXX-XXXX"
621
+ echo ""
622
+ echo "Campaign ID to stop:"
623
+ read CAMPAIGN_ID
624
+
625
+ ./emergency-stop.sh $CAMPAIGN_ID
626
+ ```
627
+
628
+ ### 4. Document State Changes
629
+
630
+ Log important actions:
631
+
632
+ ```bash
633
+ # Log state changes
634
+ log_action() {
635
+ echo "$(date --iso-8601=seconds) | $1 | $2" >> campaign-actions.log
636
+ }
637
+
638
+ # Usage
639
+ log_action "SUSPEND" "Campaign 790 suspended due to content error"
640
+ ```
641
+
642
+ ### 5. Review Before Archiving
643
+
644
+ Ensure analytics captured:
645
+
646
+ ```bash
647
+ #!/bin/bash
648
+ # safe-archive.sh
649
+
650
+ CAMPAIGN_ID=$1
651
+
652
+ # Get final stats
653
+ STATS=$(cakemail reports campaign $CAMPAIGN_ID -f json)
654
+
655
+ # Save to file
656
+ echo "$STATS" > "campaign-$CAMPAIGN_ID-stats.json"
657
+
658
+ # Now archive
659
+ cakemail campaigns archive $CAMPAIGN_ID
660
+
661
+ echo "Stats saved and campaign archived"
662
+ ```
663
+
664
+ ## Troubleshooting
665
+
666
+ ### Campaign Stuck in "Sending"
667
+
668
+ **Problem:** Campaign status "sending" for extended period
669
+
670
+ **Investigation:**
671
+ ```bash
672
+ # Check how long it's been sending
673
+ $ cakemail campaigns get 790 -f json | jq '{status, sending_started_at, sent_count, total_recipients}'
674
+ ```
675
+
676
+ **Solutions:**
677
+ - Large lists take time (normal for 10k+ contacts)
678
+ - Contact support if > 4 hours with no progress
679
+ - Check account status for issues
680
+
681
+ ### Cannot Suspend Campaign
682
+
683
+ **Error:** "Campaign cannot be suspended"
684
+
685
+ **Possible reasons:**
686
+ - Campaign already completed
687
+ - Campaign not in "sending" status
688
+ - Too close to completion
689
+
690
+ **Check status:**
691
+ ```bash
692
+ $ cakemail campaigns get 790 -f json | jq '.status'
693
+ ```
694
+
695
+ ### Suspended Campaign Won't Resume
696
+
697
+ **Problem:** Resume command fails
698
+
699
+ **Solutions:**
700
+ ```bash
701
+ # Check if campaign cancelled
702
+ $ cakemail campaigns get 790 -f json | jq '.status'
703
+
704
+ # If cancelled, cannot resume (create new campaign)
705
+
706
+ # If suspended, try again
707
+ $ cakemail campaigns resume 790
708
+ ```
709
+