@cakemail-org/cakemail-cli 1.7.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.
- package/.claude/settings.local.json +12 -0
- package/.env.example +40 -0
- package/.env.test.example +45 -0
- package/CHANGELOG.md +1031 -0
- package/README.md +41 -37
- package/audit-formats.js +128 -0
- package/cakemail.rb +20 -0
- package/dist/client.js +1 -1
- package/dist/client.js.map +1 -1
- package/dist/commands/account.js +1 -1
- package/dist/commands/account.js.map +1 -1
- package/dist/commands/attributes.js +1 -1
- package/dist/commands/attributes.js.map +1 -1
- package/dist/commands/campaigns.js +1 -1
- package/dist/commands/campaigns.js.map +1 -1
- package/dist/commands/contacts.js +1 -1
- package/dist/commands/contacts.js.map +1 -1
- package/dist/commands/emails.js +1 -1
- package/dist/commands/emails.js.map +1 -1
- package/dist/commands/interests.js +1 -1
- package/dist/commands/interests.js.map +1 -1
- package/dist/commands/lists.js +1 -1
- package/dist/commands/lists.js.map +1 -1
- package/dist/commands/logs.js +1 -1
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/reports.js +1 -1
- package/dist/commands/reports.js.map +1 -1
- package/dist/commands/segments.js +1 -1
- package/dist/commands/segments.js.map +1 -1
- package/dist/commands/senders.js +1 -1
- package/dist/commands/senders.js.map +1 -1
- package/dist/commands/suppressed.js +1 -1
- package/dist/commands/suppressed.js.map +1 -1
- package/dist/commands/tags.js +1 -1
- package/dist/commands/tags.js.map +1 -1
- package/dist/commands/templates.js +1 -1
- package/dist/commands/templates.js.map +1 -1
- package/dist/commands/transactional-templates.js +1 -1
- package/dist/commands/transactional-templates.js.map +1 -1
- package/dist/commands/webhooks.js +1 -1
- package/dist/commands/webhooks.js.map +1 -1
- package/dist/utils/config.js +2 -2
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/errors.js +1 -1
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/progress.d.ts.map +1 -1
- package/dist/utils/progress.js +32 -4
- package/dist/utils/progress.js.map +1 -1
- package/dist/utils/spinner.d.ts +17 -0
- package/dist/utils/spinner.d.ts.map +1 -0
- package/dist/utils/spinner.js +43 -0
- package/dist/utils/spinner.js.map +1 -0
- package/docs/DOCUMENTATION-STANDARD.md +1068 -0
- package/docs/README.md +161 -0
- package/docs/developer/ARCHITECTURE.md +516 -0
- package/docs/developer/AUTH.md +204 -0
- package/docs/developer/CONTRIBUTING.md +227 -0
- package/docs/developer/DOCUMENTATION_SUMMARY.md +346 -0
- package/docs/developer/PROJECT_INDEX.md +365 -0
- package/docs/planning/API_COVERAGE.md +1045 -0
- package/docs/planning/BACKLOG.md +1159 -0
- package/docs/planning/PROFILE_SYSTEM_TASKS.md +287 -0
- package/docs/planning/UX_IMPLEMENTATION_PLAN.md +691 -0
- package/docs/planning/archive/RELEASE_CHECKLIST_v1.3.0.md +332 -0
- package/docs/planning/archive/RELEASE_v1.3.0.md +428 -0
- package/docs/planning/archive/cakemail-cli-ux-improvements.md +438 -0
- package/docs/planning/cakemail-profile-system-plan.md +1121 -0
- package/docs/testing/AI_USER_SIMULATION_DESIGN.md +1342 -0
- package/docs/testing/KENOGAMI_BIDIRECTIONAL_FLOW.md +1517 -0
- package/docs/testing/KENOGAMI_TRUTH_RECONCILIATION_SYSTEM.md +1369 -0
- package/docs/user-manual/.obsidian/app.json +1 -0
- package/docs/user-manual/.obsidian/appearance.json +1 -0
- package/docs/user-manual/.obsidian/core-plugins.json +33 -0
- package/docs/user-manual/.obsidian/workspace.json +167 -0
- package/docs/user-manual/01-getting-started/01-installation.md +214 -0
- package/docs/user-manual/01-getting-started/02-quick-start.md +432 -0
- package/docs/user-manual/01-getting-started/03-authentication.md +448 -0
- package/docs/user-manual/01-getting-started/04-configuration.md +430 -0
- package/docs/user-manual/01-getting-started/05-output-formats.md +447 -0
- package/docs/user-manual/02-core-concepts/01-accounts.md +514 -0
- package/docs/user-manual/02-core-concepts/02-profile-system.md +771 -0
- package/docs/user-manual/02-core-concepts/03-smart-defaults.md +485 -0
- package/docs/user-manual/02-core-concepts/04-authentication-methods.md +435 -0
- package/docs/user-manual/02-core-concepts/05-pagination-filtering.md +600 -0
- package/docs/user-manual/02-core-concepts/06-error-handling.md +718 -0
- package/docs/user-manual/02-core-concepts/07-api-coverage.md +483 -0
- package/docs/user-manual/03-email-operations/01-senders.md +490 -0
- package/docs/user-manual/03-email-operations/02-templates.md +444 -0
- package/docs/user-manual/03-email-operations/03-transactional-emails.md +706 -0
- package/docs/user-manual/03-email-operations/04-email-tracking.md +407 -0
- package/docs/user-manual/04-campaign-management/01-campaigns-basics.md +394 -0
- package/docs/user-manual/04-campaign-management/02-campaign-scheduling.md +630 -0
- package/docs/user-manual/04-campaign-management/03-campaign-testing.md +997 -0
- package/docs/user-manual/04-campaign-management/04-campaign-lifecycle.md +709 -0
- package/docs/user-manual/04-campaign-management/05-campaign-links.md +934 -0
- package/docs/user-manual/05-contact-management/01-lists.md +836 -0
- package/docs/user-manual/05-contact-management/02-contacts.md +1035 -0
- package/docs/user-manual/05-contact-management/03-custom-attributes.md +788 -0
- package/docs/user-manual/05-contact-management/04-segments.md +1028 -0
- package/docs/user-manual/05-contact-management/05-contact-import-export.md +1031 -0
- package/docs/user-manual/06-analytics-reporting/01-campaign-analytics.md +867 -0
- package/docs/user-manual/06-analytics-reporting/02-account-reports.md +227 -0
- package/docs/user-manual/07-integrations/01-webhooks-integration.md +259 -0
- package/docs/user-manual/07-integrations/02-automation.md +326 -0
- package/docs/user-manual/08-advanced-usage/01-scripting-patterns.md +672 -0
- package/docs/user-manual/08-advanced-usage/02-bulk-operations.md +932 -0
- package/docs/user-manual/08-advanced-usage/03-ci-cd-integration.md +892 -0
- package/docs/user-manual/08-advanced-usage/04-performance-optimization.md +766 -0
- package/docs/user-manual/09-command-reference/01-config.md +776 -0
- package/docs/user-manual/09-command-reference/02-account.md +652 -0
- package/docs/user-manual/09-command-reference/03-lists.md +958 -0
- package/docs/user-manual/09-command-reference/04-contacts.md +1408 -0
- package/docs/user-manual/09-command-reference/05-attributes.md +617 -0
- package/docs/user-manual/09-command-reference/06-segments.md +894 -0
- package/docs/user-manual/09-command-reference/07-senders.md +803 -0
- package/docs/user-manual/09-command-reference/08-templates.md +818 -0
- package/docs/user-manual/09-command-reference/09-campaigns.md +1250 -0
- package/docs/user-manual/09-command-reference/10-emails.md +807 -0
- package/docs/user-manual/09-command-reference/11-reports.md +1135 -0
- package/docs/user-manual/09-command-reference/12-webhooks.md +773 -0
- package/docs/user-manual/09-command-reference/13-suppressed.md +797 -0
- package/docs/user-manual/09-command-reference/14-interests.md +630 -0
- package/docs/user-manual/09-command-reference/15-tags.md +584 -0
- package/docs/user-manual/09-command-reference/16-logs.md +656 -0
- package/docs/user-manual/09-command-reference/17-transactional-templates.md +850 -0
- package/docs/user-manual/10-troubleshooting/01-common-errors.md +457 -0
- package/docs/user-manual/10-troubleshooting/02-authentication-issues.md +558 -0
- package/docs/user-manual/10-troubleshooting/03-connection-problems.md +634 -0
- package/docs/user-manual/10-troubleshooting/04-debugging.md +725 -0
- package/docs/user-manual/11-appendix/04-faq.md +484 -0
- package/docs/user-manual/11-appendix/05-glossary.md +250 -0
- package/docs/user-manual/README.md +0 -0
- package/package.json +13 -61
- package/src/cli.ts +125 -0
- package/src/client.ts +16 -0
- package/src/commands/account.ts +267 -0
- package/src/commands/accounts.ts +78 -0
- package/src/commands/actions.ts +249 -0
- package/src/commands/attributes.ts +139 -0
- package/src/commands/campaign-blueprints.ts +106 -0
- package/src/commands/campaigns.ts +469 -0
- package/src/commands/config.ts +77 -0
- package/src/commands/contacts.ts +612 -0
- package/src/commands/custom-attributes.ts +127 -0
- package/src/commands/dkims.ts +117 -0
- package/src/commands/domains.ts +82 -0
- package/src/commands/email-apis.ts +569 -0
- package/src/commands/emails.ts +197 -0
- package/src/commands/forms.ts +283 -0
- package/src/commands/interests.ts +155 -0
- package/src/commands/links.ts +38 -0
- package/src/commands/lists.ts +406 -0
- package/src/commands/logos.ts +71 -0
- package/src/commands/logs.ts +386 -0
- package/src/commands/reports.ts +306 -0
- package/src/commands/segments.ts +158 -0
- package/src/commands/senders.ts +204 -0
- package/src/commands/sub-accounts.ts +271 -0
- package/src/commands/suppressed-emails.ts +234 -0
- package/src/commands/suppressed.ts +198 -0
- package/src/commands/system-emails.ts +85 -0
- package/src/commands/tags.ts +146 -0
- package/src/commands/tasks.ts +116 -0
- package/src/commands/templates.ts +189 -0
- package/src/commands/tokens.ts +83 -0
- package/src/commands/transactional-emails.ts +374 -0
- package/src/commands/transactional-templates.ts +385 -0
- package/src/commands/users.ts +506 -0
- package/src/commands/webhooks.ts +172 -0
- package/src/commands/workflow-blueprints.ts +123 -0
- package/src/commands/workflows.ts +265 -0
- package/src/types/profile.ts +93 -0
- package/src/utils/auth.ts +272 -0
- package/src/utils/config-file.ts +96 -0
- package/src/utils/config.ts +134 -0
- package/src/utils/confirm.ts +32 -0
- package/src/utils/defaults.ts +99 -0
- package/src/utils/errors.ts +116 -0
- package/src/utils/interactive.ts +91 -0
- package/src/utils/list-defaults.ts +74 -0
- package/src/utils/output.ts +190 -0
- package/src/utils/progress.ts +320 -0
- package/src/utils/spinner.ts +22 -0
- package/tests/IMPLEMENTATION_STATUS.md +258 -0
- package/tests/PTY_SETUP.md +118 -0
- package/tests/PTY_TESTING_GUIDE.md +507 -0
- package/tests/README.md +244 -0
- package/tests/fixtures/api-responses/campaigns.json +34 -0
- package/tests/fixtures/test-config.json +13 -0
- package/tests/helpers/cli-runner.ts +128 -0
- package/tests/helpers/mock-server.ts +301 -0
- package/tests/helpers/pty-runner.ts +181 -0
- package/tests/integration/campaigns-real-api.test.ts +196 -0
- package/tests/integration/setup-integration.ts +50 -0
- package/tests/pty/campaigns.test.ts +241 -0
- package/tests/setup.ts +34 -0
- package/tsconfig.json +15 -0
- package/vitest.config.ts +28 -0
|
@@ -0,0 +1,788 @@
|
|
|
1
|
+
# Custom Attributes
|
|
2
|
+
|
|
3
|
+
Extend contact records with custom fields to store business-specific data beyond standard email and name fields.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Custom attributes allow you to:
|
|
8
|
+
- Store unlimited additional contact data
|
|
9
|
+
- Track customer preferences and behavior
|
|
10
|
+
- Enable advanced segmentation
|
|
11
|
+
- Personalize campaigns with custom data
|
|
12
|
+
- Integrate with your business systems
|
|
13
|
+
- Build comprehensive customer profiles
|
|
14
|
+
|
|
15
|
+
Custom attributes are the key to making Cakemail work for your specific business needs.
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
### Create Your First Attribute
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
$ cakemail attributes create 123 -n "plan_type" -t "text"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Output:**
|
|
26
|
+
```
|
|
27
|
+
✓ Custom attribute created: plan_type
|
|
28
|
+
|
|
29
|
+
Name: plan_type
|
|
30
|
+
Type: text
|
|
31
|
+
List: 123
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Add Contact with Custom Data
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
$ cakemail contacts add 123 \
|
|
38
|
+
-e "customer@example.com" \
|
|
39
|
+
-f "Jane" \
|
|
40
|
+
-l "Doe" \
|
|
41
|
+
-d '{"plan_type":"premium"}'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### View Attributes
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
$ cakemail attributes list 123
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Output:**
|
|
51
|
+
```
|
|
52
|
+
┌──────────────────┬──────────┬─────────────────────┐
|
|
53
|
+
│ Name │ Type │ Created │
|
|
54
|
+
├──────────────────┼──────────┼─────────────────────┤
|
|
55
|
+
│ plan_type │ text │ 2024-01-15 10:30:00 │
|
|
56
|
+
│ signup_date │ date │ 2024-02-01 14:20:00 │
|
|
57
|
+
│ lifetime_value │ number │ 2024-02-15 09:00:00 │
|
|
58
|
+
│ is_vip │ boolean │ 2024-03-01 11:45:00 │
|
|
59
|
+
└──────────────────┴──────────┴─────────────────────┘
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Attribute Types
|
|
63
|
+
|
|
64
|
+
### Text Attributes
|
|
65
|
+
|
|
66
|
+
Store string values like names, categories, or IDs.
|
|
67
|
+
|
|
68
|
+
**Create:**
|
|
69
|
+
```bash
|
|
70
|
+
$ cakemail attributes create 123 -n "plan_type" -t "text"
|
|
71
|
+
$ cakemail attributes create 123 -n "customer_id" -t "text"
|
|
72
|
+
$ cakemail attributes create 123 -n "company_name" -t "text"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Use cases:**
|
|
76
|
+
- Plan tiers (free, basic, premium, enterprise)
|
|
77
|
+
- Customer segments (new, active, lapsed)
|
|
78
|
+
- Industry categories (technology, retail, finance)
|
|
79
|
+
- Product preferences (red, blue, green)
|
|
80
|
+
- External system IDs
|
|
81
|
+
|
|
82
|
+
**Example values:**
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"plan_type": "premium",
|
|
86
|
+
"customer_id": "CUST-12345",
|
|
87
|
+
"company_name": "Acme Corporation",
|
|
88
|
+
"industry": "Technology",
|
|
89
|
+
"preferred_color": "blue"
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Number Attributes
|
|
94
|
+
|
|
95
|
+
Store numeric values like counts, amounts, or scores.
|
|
96
|
+
|
|
97
|
+
**Create:**
|
|
98
|
+
```bash
|
|
99
|
+
$ cakemail attributes create 123 -n "purchase_count" -t "number"
|
|
100
|
+
$ cakemail attributes create 123 -n "lifetime_value" -t "number"
|
|
101
|
+
$ cakemail attributes create 123 -n "engagement_score" -t "number"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Use cases:**
|
|
105
|
+
- Purchase counts
|
|
106
|
+
- Lifetime value (dollars)
|
|
107
|
+
- Engagement scores
|
|
108
|
+
- Account age (days)
|
|
109
|
+
- Product quantities
|
|
110
|
+
|
|
111
|
+
**Example values:**
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"purchase_count": 15,
|
|
115
|
+
"lifetime_value": 2499.99,
|
|
116
|
+
"engagement_score": 87,
|
|
117
|
+
"account_age_days": 365,
|
|
118
|
+
"cart_items": 3
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Date Attributes
|
|
123
|
+
|
|
124
|
+
Store dates in ISO format (YYYY-MM-DD).
|
|
125
|
+
|
|
126
|
+
**Create:**
|
|
127
|
+
```bash
|
|
128
|
+
$ cakemail attributes create 123 -n "signup_date" -t "date"
|
|
129
|
+
$ cakemail attributes create 123 -n "last_purchase" -t "date"
|
|
130
|
+
$ cakemail attributes create 123 -n "trial_ends" -t "date"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Use cases:**
|
|
134
|
+
- Signup/registration dates
|
|
135
|
+
- Last purchase dates
|
|
136
|
+
- Trial expiration dates
|
|
137
|
+
- Birthday/anniversary dates
|
|
138
|
+
- Renewal dates
|
|
139
|
+
|
|
140
|
+
**Example values:**
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"signup_date": "2024-01-15",
|
|
144
|
+
"last_purchase": "2024-03-10",
|
|
145
|
+
"trial_ends": "2024-04-15",
|
|
146
|
+
"birthday": "1990-06-15",
|
|
147
|
+
"renewal_date": "2024-12-31"
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Boolean Attributes
|
|
152
|
+
|
|
153
|
+
Store true/false flags.
|
|
154
|
+
|
|
155
|
+
**Create:**
|
|
156
|
+
```bash
|
|
157
|
+
$ cakemail attributes create 123 -n "is_vip" -t "boolean"
|
|
158
|
+
$ cakemail attributes create 123 -n "opted_in_sms" -t "boolean"
|
|
159
|
+
$ cakemail attributes create 123 -n "email_verified" -t "boolean"
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Use cases:**
|
|
163
|
+
- VIP status
|
|
164
|
+
- Feature flags
|
|
165
|
+
- Opt-in preferences
|
|
166
|
+
- Verification status
|
|
167
|
+
- Active/inactive indicators
|
|
168
|
+
|
|
169
|
+
**Example values:**
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"is_vip": true,
|
|
173
|
+
"opted_in_sms": false,
|
|
174
|
+
"email_verified": true,
|
|
175
|
+
"marketing_consent": true,
|
|
176
|
+
"account_locked": false
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Attribute Naming
|
|
181
|
+
|
|
182
|
+
### Best Naming Practices
|
|
183
|
+
|
|
184
|
+
**Good names:**
|
|
185
|
+
```bash
|
|
186
|
+
$ cakemail attributes create 123 -n "plan_type" -t "text" # Clear purpose
|
|
187
|
+
$ cakemail attributes create 123 -n "last_login_date" -t "date" # Descriptive
|
|
188
|
+
$ cakemail attributes create 123 -n "is_premium" -t "boolean" # Clear boolean
|
|
189
|
+
$ cakemail attributes create 123 -n "total_spent" -t "number" # Clear metric
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**Avoid:**
|
|
193
|
+
```bash
|
|
194
|
+
$ cakemail attributes create 123 -n "pt" -t "text" # Too short
|
|
195
|
+
$ cakemail attributes create 123 -n "Plan Type" -t "text" # Spaces
|
|
196
|
+
$ cakemail attributes create 123 -n "PLAN" -t "text" # All caps
|
|
197
|
+
$ cakemail attributes create 123 -n "thePlanTypeForCustomer" -t "text" # Too verbose
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Naming Conventions
|
|
201
|
+
|
|
202
|
+
**Use snake_case:**
|
|
203
|
+
```bash
|
|
204
|
+
plan_type # ✓
|
|
205
|
+
lifetime_value # ✓
|
|
206
|
+
last_purchase_date # ✓
|
|
207
|
+
is_vip # ✓
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Not camelCase or spaces:**
|
|
211
|
+
```bash
|
|
212
|
+
planType # ✗
|
|
213
|
+
lifetimeValue # ✗
|
|
214
|
+
"last purchase" # ✗
|
|
215
|
+
"Is VIP" # ✗
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**Boolean prefix:**
|
|
219
|
+
```bash
|
|
220
|
+
is_vip # ✓ Clear it's boolean
|
|
221
|
+
has_subscription # ✓ Clear it's boolean
|
|
222
|
+
email_verified # ✓ Clear it's boolean
|
|
223
|
+
|
|
224
|
+
vip # ✗ Not obvious it's boolean
|
|
225
|
+
subscription # ✗ Not obvious it's boolean
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Attribute Workflows
|
|
229
|
+
|
|
230
|
+
### Workflow 1: Customer Data Setup
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
#!/bin/bash
|
|
234
|
+
# setup-customer-attributes.sh
|
|
235
|
+
|
|
236
|
+
LIST_ID=123
|
|
237
|
+
|
|
238
|
+
echo "=== Setting Up Customer Attributes ==="
|
|
239
|
+
echo ""
|
|
240
|
+
|
|
241
|
+
# Basic info
|
|
242
|
+
echo "Creating basic customer attributes..."
|
|
243
|
+
cakemail attributes create $LIST_ID -n "customer_id" -t "text"
|
|
244
|
+
cakemail attributes create $LIST_ID -n "company_name" -t "text"
|
|
245
|
+
cakemail attributes create $LIST_ID -n "industry" -t "text"
|
|
246
|
+
cakemail attributes create $LIST_ID -n "company_size" -t "text"
|
|
247
|
+
|
|
248
|
+
# Subscription
|
|
249
|
+
echo "Creating subscription attributes..."
|
|
250
|
+
cakemail attributes create $LIST_ID -n "plan_type" -t "text"
|
|
251
|
+
cakemail attributes create $LIST_ID -n "signup_date" -t "date"
|
|
252
|
+
cakemail attributes create $LIST_ID -n "trial_ends" -t "date"
|
|
253
|
+
cakemail attributes create $LIST_ID -n "is_paying" -t "boolean"
|
|
254
|
+
|
|
255
|
+
# Engagement
|
|
256
|
+
echo "Creating engagement attributes..."
|
|
257
|
+
cakemail attributes create $LIST_ID -n "last_login_date" -t "date"
|
|
258
|
+
cakemail attributes create $LIST_ID -n "login_count" -t "number"
|
|
259
|
+
cakemail attributes create $LIST_ID -n "feature_usage_score" -t "number"
|
|
260
|
+
|
|
261
|
+
# Financial
|
|
262
|
+
echo "Creating financial attributes..."
|
|
263
|
+
cakemail attributes create $LIST_ID -n "lifetime_value" -t "number"
|
|
264
|
+
cakemail attributes create $LIST_ID -n "purchase_count" -t "number"
|
|
265
|
+
cakemail attributes create $LIST_ID -n "last_purchase_date" -t "date"
|
|
266
|
+
cakemail attributes create $LIST_ID -n "average_order_value" -t "number"
|
|
267
|
+
|
|
268
|
+
echo ""
|
|
269
|
+
echo "✓ Attribute setup complete"
|
|
270
|
+
echo ""
|
|
271
|
+
|
|
272
|
+
# Show all attributes
|
|
273
|
+
cakemail attributes list $LIST_ID
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Workflow 2: E-commerce Attributes
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
#!/bin/bash
|
|
280
|
+
# setup-ecommerce-attributes.sh
|
|
281
|
+
|
|
282
|
+
LIST_ID=123
|
|
283
|
+
|
|
284
|
+
echo "=== E-commerce Attribute Setup ==="
|
|
285
|
+
echo ""
|
|
286
|
+
|
|
287
|
+
# Purchase behavior
|
|
288
|
+
cakemail attributes create $LIST_ID -n "total_orders" -t "number"
|
|
289
|
+
cakemail attributes create $LIST_ID -n "total_spent" -t "number"
|
|
290
|
+
cakemail attributes create $LIST_ID -n "average_order_value" -t "number"
|
|
291
|
+
cakemail attributes create $LIST_ID -n "last_order_date" -t "date"
|
|
292
|
+
cakemail attributes create $LIST_ID -n "first_order_date" -t "date"
|
|
293
|
+
|
|
294
|
+
# Preferences
|
|
295
|
+
cakemail attributes create $LIST_ID -n "favorite_category" -t "text"
|
|
296
|
+
cakemail attributes create $LIST_ID -n "preferred_brand" -t "text"
|
|
297
|
+
cakemail attributes create $LIST_ID -n "size_preference" -t "text"
|
|
298
|
+
|
|
299
|
+
# Loyalty
|
|
300
|
+
cakemail attributes create $LIST_ID -n "loyalty_points" -t "number"
|
|
301
|
+
cakemail attributes create $LIST_ID -n "loyalty_tier" -t "text"
|
|
302
|
+
cakemail attributes create $LIST_ID -n "is_vip" -t "boolean"
|
|
303
|
+
|
|
304
|
+
# Cart behavior
|
|
305
|
+
cakemail attributes create $LIST_ID -n "cart_abandoned_date" -t "date"
|
|
306
|
+
cakemail attributes create $LIST_ID -n "cart_value" -t "number"
|
|
307
|
+
cakemail attributes create $LIST_ID -n "has_active_cart" -t "boolean"
|
|
308
|
+
|
|
309
|
+
echo "✓ E-commerce attributes created"
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Workflow 3: SaaS Attributes
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
#!/bin/bash
|
|
316
|
+
# setup-saas-attributes.sh
|
|
317
|
+
|
|
318
|
+
LIST_ID=123
|
|
319
|
+
|
|
320
|
+
echo "=== SaaS Attribute Setup ==="
|
|
321
|
+
echo ""
|
|
322
|
+
|
|
323
|
+
# Account
|
|
324
|
+
cakemail attributes create $LIST_ID -n "account_id" -t "text"
|
|
325
|
+
cakemail attributes create $LIST_ID -n "plan_name" -t "text"
|
|
326
|
+
cakemail attributes create $LIST_ID -n "mrr" -t "number"
|
|
327
|
+
cakemail attributes create $LIST_ID -n "arr" -t "number"
|
|
328
|
+
|
|
329
|
+
# Subscription lifecycle
|
|
330
|
+
cakemail attributes create $LIST_ID -n "trial_start_date" -t "date"
|
|
331
|
+
cakemail attributes create $LIST_ID -n "trial_end_date" -t "date"
|
|
332
|
+
cakemail attributes create $LIST_ID -n "subscription_start" -t "date"
|
|
333
|
+
cakemail attributes create $LIST_ID -n "next_billing_date" -t "date"
|
|
334
|
+
cakemail attributes create $LIST_ID -n "is_trial" -t "boolean"
|
|
335
|
+
cakemail attributes create $LIST_ID -n "is_paying" -t "boolean"
|
|
336
|
+
|
|
337
|
+
# Usage
|
|
338
|
+
cakemail attributes create $LIST_ID -n "last_login" -t "date"
|
|
339
|
+
cakemail attributes create $LIST_ID -n "login_count_30d" -t "number"
|
|
340
|
+
cakemail attributes create $LIST_ID -n "feature_adoption_score" -t "number"
|
|
341
|
+
cakemail attributes create $LIST_ID -n "active_users" -t "number"
|
|
342
|
+
|
|
343
|
+
# Health
|
|
344
|
+
cakemail attributes create $LIST_ID -n "health_score" -t "number"
|
|
345
|
+
cakemail attributes create $LIST_ID -n "churn_risk" -t "text"
|
|
346
|
+
cakemail attributes create $LIST_ID -n "support_tickets_30d" -t "number"
|
|
347
|
+
|
|
348
|
+
echo "✓ SaaS attributes created"
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### Workflow 4: Attribute Audit
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
#!/bin/bash
|
|
355
|
+
# audit-attributes.sh
|
|
356
|
+
|
|
357
|
+
LIST_ID=123
|
|
358
|
+
|
|
359
|
+
echo "=== Attribute Audit ==="
|
|
360
|
+
echo ""
|
|
361
|
+
|
|
362
|
+
# Get all attributes
|
|
363
|
+
ATTRIBUTES=$(cakemail attributes list $LIST_ID -f json | jq -r '.data[] | "\(.name):\(.type)"')
|
|
364
|
+
|
|
365
|
+
echo "Attribute | Type | Usage (%)"
|
|
366
|
+
echo "----------|------|----------"
|
|
367
|
+
|
|
368
|
+
# Check usage for each attribute
|
|
369
|
+
for ATTR in $ATTRIBUTES; do
|
|
370
|
+
NAME=$(echo "$ATTR" | cut -d: -f1)
|
|
371
|
+
TYPE=$(echo "$ATTR" | cut -d: -f2)
|
|
372
|
+
|
|
373
|
+
# Get contacts with this attribute set
|
|
374
|
+
TOTAL=$(cakemail contacts list $LIST_ID -f json | jq '.count')
|
|
375
|
+
|
|
376
|
+
# Note: This is simplified - actual implementation would need to check each contact
|
|
377
|
+
# For demonstration purposes
|
|
378
|
+
USAGE="~%"
|
|
379
|
+
|
|
380
|
+
printf "%-20s | %-8s | %s\n" "$NAME" "$TYPE" "$USAGE"
|
|
381
|
+
done
|
|
382
|
+
|
|
383
|
+
echo ""
|
|
384
|
+
echo "Review attributes with low usage for potential removal"
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Workflow 5: Attribute Migration
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
#!/bin/bash
|
|
391
|
+
# migrate-attributes.sh
|
|
392
|
+
|
|
393
|
+
SOURCE_LIST=123
|
|
394
|
+
TARGET_LIST=124
|
|
395
|
+
|
|
396
|
+
echo "=== Migrating Attributes ==="
|
|
397
|
+
echo "From: List $SOURCE_LIST"
|
|
398
|
+
echo "To: List $TARGET_LIST"
|
|
399
|
+
echo ""
|
|
400
|
+
|
|
401
|
+
# Get source attributes
|
|
402
|
+
ATTRIBUTES=$(cakemail attributes list $SOURCE_LIST -f json)
|
|
403
|
+
|
|
404
|
+
echo "$ATTRIBUTES" | jq -r '.data[] | "\(.name):\(.type)"' | while IFS=: read NAME TYPE; do
|
|
405
|
+
echo "Creating: $NAME ($TYPE)"
|
|
406
|
+
|
|
407
|
+
# Create in target list
|
|
408
|
+
cakemail attributes create $TARGET_LIST -n "$NAME" -t "$TYPE" 2>/dev/null
|
|
409
|
+
|
|
410
|
+
if [ $? -eq 0 ]; then
|
|
411
|
+
echo " ✓ Created"
|
|
412
|
+
else
|
|
413
|
+
echo " ⚠️ Already exists or error"
|
|
414
|
+
fi
|
|
415
|
+
done
|
|
416
|
+
|
|
417
|
+
echo ""
|
|
418
|
+
echo "✓ Attribute migration complete"
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
## Using Attributes with Contacts
|
|
422
|
+
|
|
423
|
+
### Add Contact with Attributes
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
$ cakemail contacts add 123 \
|
|
427
|
+
-e "customer@example.com" \
|
|
428
|
+
-f "Jane" \
|
|
429
|
+
-l "Doe" \
|
|
430
|
+
-d '{
|
|
431
|
+
"plan_type": "premium",
|
|
432
|
+
"signup_date": "2024-03-15",
|
|
433
|
+
"is_vip": true,
|
|
434
|
+
"lifetime_value": 599.99,
|
|
435
|
+
"purchase_count": 8
|
|
436
|
+
}'
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### Update Contact Attributes
|
|
440
|
+
|
|
441
|
+
```bash
|
|
442
|
+
# Update single attribute
|
|
443
|
+
$ cakemail contacts update 123 501 -d '{"plan_type":"enterprise"}'
|
|
444
|
+
|
|
445
|
+
# Update multiple attributes
|
|
446
|
+
$ cakemail contacts update 123 501 -d '{
|
|
447
|
+
"plan_type": "enterprise",
|
|
448
|
+
"is_vip": true,
|
|
449
|
+
"lifetime_value": 1299.99
|
|
450
|
+
}'
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Query by Attributes
|
|
454
|
+
|
|
455
|
+
```bash
|
|
456
|
+
# Find premium users
|
|
457
|
+
$ cakemail contacts list 123 --filter "custom_attributes.plan_type==premium"
|
|
458
|
+
|
|
459
|
+
# Find VIP customers
|
|
460
|
+
$ cakemail contacts list 123 --filter "custom_attributes.is_vip==true"
|
|
461
|
+
|
|
462
|
+
# Find high-value customers
|
|
463
|
+
$ cakemail contacts list 123 --filter "custom_attributes.lifetime_value>=1000"
|
|
464
|
+
|
|
465
|
+
# Find recent signups
|
|
466
|
+
$ cakemail contacts list 123 --filter "custom_attributes.signup_date>=2024-03-01"
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
## Segmentation with Attributes
|
|
470
|
+
|
|
471
|
+
### Create Segments Based on Attributes
|
|
472
|
+
|
|
473
|
+
```bash
|
|
474
|
+
# Premium plan segment
|
|
475
|
+
$ cakemail segments create 123 -n "Premium Users" -c '{
|
|
476
|
+
"match": "all",
|
|
477
|
+
"rules": [
|
|
478
|
+
{"field": "custom_attributes.plan_type", "operator": "equals", "value": "premium"}
|
|
479
|
+
]
|
|
480
|
+
}'
|
|
481
|
+
|
|
482
|
+
# High-value customers
|
|
483
|
+
$ cakemail segments create 123 -n "High Value" -c '{
|
|
484
|
+
"match": "all",
|
|
485
|
+
"rules": [
|
|
486
|
+
{"field": "custom_attributes.lifetime_value", "operator": "greater_than", "value": "1000"}
|
|
487
|
+
]
|
|
488
|
+
}'
|
|
489
|
+
|
|
490
|
+
# At-risk trial users
|
|
491
|
+
$ cakemail segments create 123 -n "Trial Ending Soon" -c '{
|
|
492
|
+
"match": "all",
|
|
493
|
+
"rules": [
|
|
494
|
+
{"field": "custom_attributes.is_trial", "operator": "equals", "value": "true"},
|
|
495
|
+
{"field": "custom_attributes.trial_ends", "operator": "less_than", "value": "2024-04-01"}
|
|
496
|
+
]
|
|
497
|
+
}'
|
|
498
|
+
|
|
499
|
+
# Engaged VIPs
|
|
500
|
+
$ cakemail segments create 123 -n "Engaged VIPs" -c '{
|
|
501
|
+
"match": "all",
|
|
502
|
+
"rules": [
|
|
503
|
+
{"field": "custom_attributes.is_vip", "operator": "equals", "value": "true"},
|
|
504
|
+
{"field": "last_open_date", "operator": "greater_than", "value": "2024-03-01"}
|
|
505
|
+
]
|
|
506
|
+
}'
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
## Campaign Personalization
|
|
510
|
+
|
|
511
|
+
### Use Attributes in Campaigns
|
|
512
|
+
|
|
513
|
+
Campaign HTML with merge tags:
|
|
514
|
+
|
|
515
|
+
```html
|
|
516
|
+
<p>Hi {{first_name}},</p>
|
|
517
|
+
|
|
518
|
+
<p>As a {{custom_attributes.plan_type}} member, you have access to:</p>
|
|
519
|
+
|
|
520
|
+
{{#if custom_attributes.is_vip}}
|
|
521
|
+
<p><strong>VIP Benefits:</strong></p>
|
|
522
|
+
<ul>
|
|
523
|
+
<li>Priority Support</li>
|
|
524
|
+
<li>Exclusive Features</li>
|
|
525
|
+
<li>Early Access</li>
|
|
526
|
+
</ul>
|
|
527
|
+
{{/if}}
|
|
528
|
+
|
|
529
|
+
<p>You've been with us since {{custom_attributes.signup_date}}.</p>
|
|
530
|
+
|
|
531
|
+
<p>Your lifetime savings: ${{custom_attributes.lifetime_value}}</p>
|
|
532
|
+
|
|
533
|
+
<p>Thanks for {{custom_attributes.purchase_count}} purchases!</p>
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### Conditional Content
|
|
537
|
+
|
|
538
|
+
```html
|
|
539
|
+
{{#if custom_attributes.plan_type == "free"}}
|
|
540
|
+
<div class="upgrade-prompt">
|
|
541
|
+
<h2>Upgrade to Premium</h2>
|
|
542
|
+
<p>Get more features for just $9.99/month</p>
|
|
543
|
+
<a href="https://example.com/upgrade">Upgrade Now</a>
|
|
544
|
+
</div>
|
|
545
|
+
{{/if}}
|
|
546
|
+
|
|
547
|
+
{{#if custom_attributes.cart_abandoned_date}}
|
|
548
|
+
<div class="cart-reminder">
|
|
549
|
+
<h2>You Left Items in Your Cart</h2>
|
|
550
|
+
<p>Complete your purchase and save {{custom_attributes.cart_value}}!</p>
|
|
551
|
+
<a href="https://example.com/cart">Return to Cart</a>
|
|
552
|
+
</div>
|
|
553
|
+
{{/if}}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
## Attribute Best Practices
|
|
557
|
+
|
|
558
|
+
### 1. Plan Schema First
|
|
559
|
+
|
|
560
|
+
```bash
|
|
561
|
+
# Document your attribute schema
|
|
562
|
+
cat > attribute-schema.md << 'EOF'
|
|
563
|
+
# Customer Attributes Schema
|
|
564
|
+
|
|
565
|
+
## Account
|
|
566
|
+
- customer_id (text): External CRM ID
|
|
567
|
+
- account_type (text): individual | business
|
|
568
|
+
- signup_date (date): Registration date
|
|
569
|
+
|
|
570
|
+
## Subscription
|
|
571
|
+
- plan_type (text): free | basic | premium | enterprise
|
|
572
|
+
- is_paying (boolean): Active paid subscription
|
|
573
|
+
- mrr (number): Monthly recurring revenue
|
|
574
|
+
|
|
575
|
+
## Engagement
|
|
576
|
+
- last_login (date): Last login date
|
|
577
|
+
- login_count_30d (number): Logins in last 30 days
|
|
578
|
+
- health_score (number): 0-100 engagement score
|
|
579
|
+
|
|
580
|
+
## Financial
|
|
581
|
+
- lifetime_value (number): Total revenue
|
|
582
|
+
- purchase_count (number): Total orders
|
|
583
|
+
- average_order_value (number): AOV
|
|
584
|
+
EOF
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
### 2. Use Consistent Types
|
|
588
|
+
|
|
589
|
+
```bash
|
|
590
|
+
# All dates as date type
|
|
591
|
+
$ cakemail attributes create 123 -n "signup_date" -t "date"
|
|
592
|
+
$ cakemail attributes create 123 -n "last_purchase" -t "date"
|
|
593
|
+
$ cakemail attributes create 123 -n "trial_ends" -t "date"
|
|
594
|
+
|
|
595
|
+
# All monetary values as number
|
|
596
|
+
$ cakemail attributes create 123 -n "lifetime_value" -t "number"
|
|
597
|
+
$ cakemail attributes create 123 -n "monthly_spend" -t "number"
|
|
598
|
+
$ cakemail attributes create 123 -n "cart_value" -t "number"
|
|
599
|
+
|
|
600
|
+
# All flags as boolean
|
|
601
|
+
$ cakemail attributes create 123 -n "is_vip" -t "boolean"
|
|
602
|
+
$ cakemail attributes create 123 -n "email_verified" -t "boolean"
|
|
603
|
+
$ cakemail attributes create 123 -n "marketing_consent" -t "boolean"
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
### 3. Validate Data Before Setting
|
|
607
|
+
|
|
608
|
+
```bash
|
|
609
|
+
#!/bin/bash
|
|
610
|
+
# validate-and-set.sh
|
|
611
|
+
|
|
612
|
+
LIST_ID=123
|
|
613
|
+
CONTACT_ID=501
|
|
614
|
+
PLAN="$1"
|
|
615
|
+
|
|
616
|
+
# Validate plan type
|
|
617
|
+
VALID_PLANS=("free" "basic" "premium" "enterprise")
|
|
618
|
+
|
|
619
|
+
if [[ ! " ${VALID_PLANS[@]} " =~ " ${PLAN} " ]]; then
|
|
620
|
+
echo "❌ Invalid plan: $PLAN"
|
|
621
|
+
echo "Valid plans: ${VALID_PLANS[@]}"
|
|
622
|
+
exit 1
|
|
623
|
+
fi
|
|
624
|
+
|
|
625
|
+
# Set attribute
|
|
626
|
+
cakemail contacts update $LIST_ID $CONTACT_ID -d "{\"plan_type\":\"$PLAN\"}"
|
|
627
|
+
echo "✓ Plan set to: $PLAN"
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
### 4. Keep Attributes Synchronized
|
|
631
|
+
|
|
632
|
+
```bash
|
|
633
|
+
#!/bin/bash
|
|
634
|
+
# sync-from-crm.sh
|
|
635
|
+
|
|
636
|
+
LIST_ID=123
|
|
637
|
+
|
|
638
|
+
echo "=== Syncing from CRM ==="
|
|
639
|
+
echo ""
|
|
640
|
+
|
|
641
|
+
# Fetch from your CRM (example)
|
|
642
|
+
CUSTOMERS=$(curl -s "https://api.yourcrm.com/customers")
|
|
643
|
+
|
|
644
|
+
echo "$CUSTOMERS" | jq -c '.[]' | while read CUSTOMER; do
|
|
645
|
+
EMAIL=$(echo "$CUSTOMER" | jq -r '.email')
|
|
646
|
+
PLAN=$(echo "$CUSTOMER" | jq -r '.plan')
|
|
647
|
+
LTV=$(echo "$CUSTOMER" | jq -r '.lifetime_value')
|
|
648
|
+
LAST_PURCHASE=$(echo "$CUSTOMER" | jq -r '.last_purchase_date')
|
|
649
|
+
|
|
650
|
+
# Find contact
|
|
651
|
+
CONTACTS=$(cakemail contacts list $LIST_ID --filter "email==$EMAIL" -f json)
|
|
652
|
+
CONTACT_ID=$(echo "$CONTACTS" | jq -r '.data[0].id')
|
|
653
|
+
|
|
654
|
+
if [ "$CONTACT_ID" != "null" ]; then
|
|
655
|
+
# Update attributes
|
|
656
|
+
cakemail contacts update $LIST_ID $CONTACT_ID -d "{
|
|
657
|
+
\"plan_type\": \"$PLAN\",
|
|
658
|
+
\"lifetime_value\": $LTV,
|
|
659
|
+
\"last_purchase_date\": \"$LAST_PURCHASE\"
|
|
660
|
+
}"
|
|
661
|
+
echo " Synced: $EMAIL"
|
|
662
|
+
fi
|
|
663
|
+
done
|
|
664
|
+
|
|
665
|
+
echo ""
|
|
666
|
+
echo "✓ CRM sync complete"
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
### 5. Remove Unused Attributes
|
|
670
|
+
|
|
671
|
+
```bash
|
|
672
|
+
#!/bin/bash
|
|
673
|
+
# cleanup-unused.sh
|
|
674
|
+
|
|
675
|
+
LIST_ID=123
|
|
676
|
+
|
|
677
|
+
echo "=== Cleaning Up Unused Attributes ==="
|
|
678
|
+
echo ""
|
|
679
|
+
|
|
680
|
+
# List of deprecated attributes
|
|
681
|
+
DEPRECATED=(
|
|
682
|
+
"old_field"
|
|
683
|
+
"legacy_score"
|
|
684
|
+
"temp_attribute"
|
|
685
|
+
)
|
|
686
|
+
|
|
687
|
+
for ATTR in "${DEPRECATED[@]}"; do
|
|
688
|
+
echo "Removing: $ATTR"
|
|
689
|
+
cakemail attributes delete $LIST_ID $ATTR --force
|
|
690
|
+
done
|
|
691
|
+
|
|
692
|
+
echo ""
|
|
693
|
+
echo "✓ Cleanup complete"
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
## Troubleshooting
|
|
697
|
+
|
|
698
|
+
### Attribute Not Appearing
|
|
699
|
+
|
|
700
|
+
**Problem:** Created attribute but it's not showing
|
|
701
|
+
|
|
702
|
+
**Solution:**
|
|
703
|
+
```bash
|
|
704
|
+
# Verify attribute was created
|
|
705
|
+
$ cakemail attributes list 123
|
|
706
|
+
|
|
707
|
+
# Check specific attribute
|
|
708
|
+
$ cakemail attributes get 123 plan_type
|
|
709
|
+
|
|
710
|
+
# If not found, recreate
|
|
711
|
+
$ cakemail attributes create 123 -n "plan_type" -t "text"
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
### Cannot Set Attribute Value
|
|
715
|
+
|
|
716
|
+
**Problem:** Attribute value not saving on contact
|
|
717
|
+
|
|
718
|
+
**Solutions:**
|
|
719
|
+
```bash
|
|
720
|
+
# 1. Ensure attribute exists
|
|
721
|
+
$ cakemail attributes list 123
|
|
722
|
+
|
|
723
|
+
# 2. Check data type matches
|
|
724
|
+
$ cakemail attributes get 123 lifetime_value
|
|
725
|
+
# If type is "number", use number not string:
|
|
726
|
+
$ cakemail contacts update 123 501 -d '{"lifetime_value":599.99}' # ✓
|
|
727
|
+
$ cakemail contacts update 123 501 -d '{"lifetime_value":"599.99"}' # ✗
|
|
728
|
+
|
|
729
|
+
# 3. Check JSON format
|
|
730
|
+
$ cakemail contacts update 123 501 -d '{"plan":"premium"}' # ✓ Valid JSON
|
|
731
|
+
$ cakemail contacts update 123 501 -d '{plan:premium}' # ✗ Invalid JSON
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
### Wrong Data Type
|
|
735
|
+
|
|
736
|
+
**Problem:** Created attribute with wrong type
|
|
737
|
+
|
|
738
|
+
**Solution:**
|
|
739
|
+
```bash
|
|
740
|
+
# Type cannot be changed
|
|
741
|
+
# Must delete and recreate
|
|
742
|
+
|
|
743
|
+
# 1. Export contacts with old attribute
|
|
744
|
+
$ cakemail contacts export 123
|
|
745
|
+
|
|
746
|
+
# 2. Delete old attribute
|
|
747
|
+
$ cakemail attributes delete 123 old_name --force
|
|
748
|
+
|
|
749
|
+
# 3. Create with correct type
|
|
750
|
+
$ cakemail attributes create 123 -n "new_name" -t "number"
|
|
751
|
+
|
|
752
|
+
# 4. Re-import contacts with new attribute
|
|
753
|
+
# (Update CSV with new column)
|
|
754
|
+
$ cakemail contacts import 123 --file updated.csv
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
### Date Format Issues
|
|
758
|
+
|
|
759
|
+
**Problem:** Dates not saving correctly
|
|
760
|
+
|
|
761
|
+
**Solution:**
|
|
762
|
+
```bash
|
|
763
|
+
# Use ISO format: YYYY-MM-DD
|
|
764
|
+
$ cakemail contacts update 123 501 -d '{"signup_date":"2024-03-15"}' # ✓
|
|
765
|
+
|
|
766
|
+
# Wrong formats:
|
|
767
|
+
# "03/15/2024" # ✗ US format
|
|
768
|
+
# "15/03/2024" # ✗ European format
|
|
769
|
+
# "March 15, 2024" # ✗ Text format
|
|
770
|
+
|
|
771
|
+
# Convert if needed
|
|
772
|
+
DATE="03/15/2024"
|
|
773
|
+
ISO_DATE=$(date -d "$DATE" +%Y-%m-%d) # Converts to 2024-03-15
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
## Best Practices Summary
|
|
777
|
+
|
|
778
|
+
1. **Plan schema first** - Design attributes before creating
|
|
779
|
+
2. **Use descriptive names** - Clear, self-explanatory names
|
|
780
|
+
3. **Choose correct types** - Match data type to usage
|
|
781
|
+
4. **Validate input** - Check values before setting
|
|
782
|
+
5. **Document attributes** - Keep schema documentation
|
|
783
|
+
6. **Consistent naming** - Use snake_case
|
|
784
|
+
7. **Sync regularly** - Keep attributes updated from source systems
|
|
785
|
+
8. **Remove unused** - Delete deprecated attributes
|
|
786
|
+
9. **Test thoroughly** - Verify attributes work in campaigns
|
|
787
|
+
10. **Monitor usage** - Track which attributes are actually used
|
|
788
|
+
|