@growthub/cli 0.3.54 → 0.3.56
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/README.md +56 -156
- package/assets/worker-kits/growthub-ai-website-cloner-v1/.env.example +7 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/QUICKSTART.md +116 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/brands/NEW-CLIENT.md +22 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/brands/_template/brand-kit.md +27 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/brands/growthub/brand-kit.md +26 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/bundles/growthub-ai-website-cloner-v1.json +53 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/docs/ai-website-cloner-fork-integration.md +118 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/docs/design-token-system.md +135 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/docs/multi-phase-pipeline.md +129 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/docs/parallel-builder-dispatch.md +103 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/examples/clone-brief-sample.md +54 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/examples/component-spec-sample.md +123 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/examples/platform-handoff-sample.md +102 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/examples/visual-qa-sample.md +119 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/growthub-meta/README.md +71 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/growthub-meta/kit-standard.md +47 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/kit.json +105 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/output/README.md +26 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/output-standards.md +75 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/runtime-assumptions.md +70 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/setup/check-deps.sh +50 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/setup/clone-fork.sh +66 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/setup/verify-env.mjs +78 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/skills.md +186 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/asset-manifest.md +57 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/builder-dispatch-plan.md +92 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/clone-brief.md +59 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/component-spec.md +124 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/design-token-extraction.md +89 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/platform-handoff.md +114 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/reconnaissance-report.md +77 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/visual-qa-checklist.md +107 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/validation-checklist.md +76 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/workers/ai-website-cloner-operator/CLAUDE.md +256 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/.env.example +40 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/QUICKSTART.md +114 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/brands/NEW-CLIENT.md +42 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/brands/_template/brand-kit.md +49 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/brands/growthub/brand-kit.md +50 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/bundles/growthub-open-montage-studio-v1.json +55 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/docs/cms-node-bridge.md +152 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/docs/open-montage-fork-integration.md +120 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/docs/pipeline-reference.md +147 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/docs/provider-adapter-layer.md +105 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/examples/cms-node-video-gen-sample.md +109 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/examples/pipeline-selection-sample.md +67 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/examples/platform-ready-handoff-sample.md +101 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/examples/video-production-brief-sample.md +68 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/growthub-meta/README.md +7 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/growthub-meta/kit-standard.md +45 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/kit.json +107 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/output/README.md +34 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/output-standards.md +79 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/runtime-assumptions.md +86 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/setup/check-deps.sh +43 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/setup/clone-fork.sh +53 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/setup/verify-env.mjs +102 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/skills.md +254 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/asset-tracking.md +46 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/cms-node-pipeline-mapping.md +64 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/generation-batch-plan.md +70 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/pipeline-selection-brief.md +67 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/platform-ready-execution-handoff.md +103 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/prompt-matrix.md +48 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/provider-selection-brief.md +86 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/review-qa-checklist.md +59 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/scene-plan.md +65 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/video-production-brief.md +58 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/validation-checklist.md +46 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/workers/open-montage-studio-operator/CLAUDE.md +304 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/.env.example +15 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/QUICKSTART.md +90 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/brands/NEW-CLIENT.md +57 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/brands/_template/brand-kit.md +88 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/brands/growthub/brand-kit.md +92 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/bundles/growthub-twenty-crm-v1.json +56 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/docs/api-and-webhooks.md +296 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/docs/data-model-layer.md +172 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/docs/twenty-fork-integration.md +213 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/examples/crm-playbook-sample.md +172 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/examples/crm-setup-sample.md +100 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/examples/lead-enrichment-sample.md +117 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/examples/pipeline-automation-sample.md +132 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/growthub-meta/README.md +114 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/growthub-meta/kit-standard.md +61 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/kit.json +108 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/output/README.md +46 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/output-standards.md +175 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/runtime-assumptions.md +150 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/setup/check-deps.sh +56 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/setup/clone-fork.sh +77 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/setup/verify-env.mjs +105 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/skills.md +401 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/api-query-plan.md +179 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/crm-playbook.md +155 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/crm-setup-brief.md +94 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/custom-object-design.md +115 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/data-model-design.md +112 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/enrichment-field-map.md +100 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/import-mapping.md +139 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/integration-handoff.md +190 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/lead-enrichment-pipeline.md +128 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/pipeline-automation-brief.md +88 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/webhook-integration-spec.md +129 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/workspace-config-checklist.md +129 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/validation-checklist.md +115 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/workers/twenty-crm-operator/CLAUDE.md +310 -0
- package/package.json +1 -1
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Import Mapping — [CLIENT NAME]
|
|
2
|
+
|
|
3
|
+
**Date:** YYYY-MM-DD
|
|
4
|
+
**Source CRM / tool:** [e.g. Salesforce / HubSpot / Apollo CSV / Airtable]
|
|
5
|
+
**Kit:** `growthub-twenty-crm-v1`
|
|
6
|
+
**Mode:** `[cloud / self-hosted / local-fork / agent-only]`
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 1. SOURCE EXPORT FORMAT
|
|
11
|
+
|
|
12
|
+
**Format:** `[CSV / JSON / API response]`
|
|
13
|
+
**Export method:** [e.g. "Apollo: Settings > Exports > All Contacts as CSV"]
|
|
14
|
+
**Encoding:** `UTF-8`
|
|
15
|
+
**Record count (estimated):** [N]
|
|
16
|
+
**Date of export:** YYYY-MM-DD
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 2. PERSON RECORD MAPPING
|
|
21
|
+
|
|
22
|
+
**Dedup key:** `emails.primaryEmail`
|
|
23
|
+
**Import mode:** `[insert-only / merge]`
|
|
24
|
+
|
|
25
|
+
| Source column | Source type | → | Twenty object | Twenty field | Transformation |
|
|
26
|
+
|---|---|---|---|---|---|
|
|
27
|
+
| `First Name` | string | → | `Person` | `name.firstName` | none |
|
|
28
|
+
| `Last Name` | string | → | `Person` | `name.lastName` | none |
|
|
29
|
+
| `Email` | string | → | `Person` | `emails.primaryEmail` | lowercase, trim |
|
|
30
|
+
| `Phone` | string | → | `Person` | `phones.primaryPhoneNumber` | none |
|
|
31
|
+
| `Title` | string | → | `Person` | `position` | none |
|
|
32
|
+
| `LinkedIn URL` | string | → | `Person` | `linkedInLink.url` | none |
|
|
33
|
+
| `Company Name` | string | → | `Company` | `name` | create or link |
|
|
34
|
+
| `[Source column]` | [type] | → | `[Object]` | `[field]` | [transformation] |
|
|
35
|
+
|
|
36
|
+
**Columns to skip (no mapping):**
|
|
37
|
+
|
|
38
|
+
| Source column | Reason |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `[column]` | [reason — e.g. "internal ID not needed in Twenty"] |
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 3. COMPANY RECORD MAPPING
|
|
45
|
+
|
|
46
|
+
**Dedup key:** `domain`
|
|
47
|
+
**Import mode:** `[insert-only / merge]`
|
|
48
|
+
|
|
49
|
+
| Source column | Source type | → | Twenty object | Twenty field | Transformation |
|
|
50
|
+
|---|---|---|---|---|---|
|
|
51
|
+
| `Company Name` | string | → | `Company` | `name` | none |
|
|
52
|
+
| `Website` | string | → | `Company` | `domain` | strip `https://` prefix, strip trailing `/` |
|
|
53
|
+
| `Employee Count` | integer | → | `Company` | `employees` | integer cast |
|
|
54
|
+
| `Industry` | string | → | `Company` | `[custom field]` | none |
|
|
55
|
+
| `[Source column]` | [type] | → | `Company` | `[field]` | [transformation] |
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 4. OPPORTUNITY RECORD MAPPING (if applicable)
|
|
60
|
+
|
|
61
|
+
**Dedup key:** [opportunity name + company combination — no direct dedup key]
|
|
62
|
+
**Import mode:** `[insert-only]`
|
|
63
|
+
|
|
64
|
+
| Source column | Source type | → | Twenty object | Twenty field | Transformation |
|
|
65
|
+
|---|---|---|---|---|---|
|
|
66
|
+
| `Deal Name` | string | → | `Opportunity` | `name` | none |
|
|
67
|
+
| `Stage` | string | → | `Opportunity` | `stage` | see stage map below |
|
|
68
|
+
| `Amount` | number | → | `Opportunity` | `amount.amountMicros` | multiply by 1,000,000 |
|
|
69
|
+
| `Currency` | string | → | `Opportunity` | `amount.currencyCode` | uppercase (e.g. USD) |
|
|
70
|
+
| `Close Date` | date | → | `Opportunity` | `closeDate` | ISO 8601 (YYYY-MM-DD) |
|
|
71
|
+
|
|
72
|
+
**Stage mapping:**
|
|
73
|
+
|
|
74
|
+
| Source stage value | → | Twenty stage value |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| `[New]` | → | `LEAD` |
|
|
77
|
+
| `[Qualified]` | → | `QUALIFIED` |
|
|
78
|
+
| `[Discovery Call]` | → | `DEMO` |
|
|
79
|
+
| `[Proposal Sent]` | → | `PROPOSAL` |
|
|
80
|
+
| `[Won]` | → | `CLOSED_WON` |
|
|
81
|
+
| `[Lost]` | → | `CLOSED_LOST` |
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 5. TRANSFORMATION RULES
|
|
86
|
+
|
|
87
|
+
| Rule | Field | Input pattern | Output pattern |
|
|
88
|
+
|---|---|---|---|
|
|
89
|
+
| Domain normalization | `Company.domain` | `https://acme.com/` | `acme.com` |
|
|
90
|
+
| Email lowercase | `Person.emails.primaryEmail` | `Jane@ACME.COM` | `jane@acme.com` |
|
|
91
|
+
| Amount to micros | `Opportunity.amount.amountMicros` | `10000` | `10000000000` |
|
|
92
|
+
| Date to ISO 8601 | `Opportunity.closeDate` | `04/15/2026` | `2026-04-15` |
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 6. IMPORT SEQUENCE
|
|
97
|
+
|
|
98
|
+
1. **Pre-import clean:**
|
|
99
|
+
- Remove records with blank email (Person) or blank domain (Company)
|
|
100
|
+
- Deduplicate within the CSV itself (keep most recent by modification date)
|
|
101
|
+
- Normalize email addresses to lowercase
|
|
102
|
+
|
|
103
|
+
2. **Company import first:**
|
|
104
|
+
- Import Company CSV before Person CSV so that Person-Company links can be resolved
|
|
105
|
+
|
|
106
|
+
3. **Person import:**
|
|
107
|
+
- Run Person import with company linking enabled
|
|
108
|
+
- Review linked count vs. unlinked count in import summary
|
|
109
|
+
|
|
110
|
+
4. **Opportunity import (if applicable):**
|
|
111
|
+
- Run after Person and Company imports
|
|
112
|
+
- Confirm `pointOfContact` and company relations are set
|
|
113
|
+
|
|
114
|
+
5. **Post-import audit:** see section 7
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 7. POST-IMPORT VALIDATION
|
|
119
|
+
|
|
120
|
+
| Check | Expected result | Action if failed |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| Total record count | Within ±2% of source count | Check error log |
|
|
123
|
+
| Duplicate email check | 0 duplicates | Merge or remove duplicates |
|
|
124
|
+
| Company linkage | ≥ 90% of Persons linked to a Company | Review unlinked persons |
|
|
125
|
+
| Required fields | 0 blank required fields | Enrich manually |
|
|
126
|
+
| Stage mapping | All stages are valid Twenty values | Fix mapping and re-import affected rows |
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 8. ROLLBACK PLAN
|
|
131
|
+
|
|
132
|
+
If the import produces significant data quality issues:
|
|
133
|
+
|
|
134
|
+
1. Note the import timestamp
|
|
135
|
+
2. Use the Twenty audit log to identify all records created after that timestamp
|
|
136
|
+
3. Bulk delete the affected records via the GraphQL API using a `deleteMany` mutation
|
|
137
|
+
4. Fix the source CSV and re-import
|
|
138
|
+
|
|
139
|
+
**Contact the developer** if bulk delete is needed — do not manually delete records one by one.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Integration Handoff — [CLIENT NAME]
|
|
2
|
+
|
|
3
|
+
**Date:** YYYY-MM-DD
|
|
4
|
+
**Kit:** `growthub-twenty-crm-v1`
|
|
5
|
+
**Handoff from:** [CRM Operator / Consultant]
|
|
6
|
+
**Handoff to:** [Developer / DevOps]
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## PURPOSE
|
|
11
|
+
|
|
12
|
+
This document gives the implementing developer everything needed to connect [CLIENT NAME]'s external tools to their Twenty CRM workspace without needing to ask follow-up questions.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 1. SYSTEM INTEGRATION DIAGRAM
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
[Apollo / Clay]
|
|
20
|
+
|
|
|
21
|
+
| CSV export or API
|
|
22
|
+
▼
|
|
23
|
+
[Import Script / Enrichment Job]
|
|
24
|
+
|
|
|
25
|
+
| GraphQL mutation batch
|
|
26
|
+
▼
|
|
27
|
+
[Twenty CRM API] ─────── workspace: [workspace-id]
|
|
28
|
+
▲
|
|
29
|
+
|
|
|
30
|
+
| Outbound webhooks
|
|
31
|
+
▼
|
|
32
|
+
[Slack / Notification endpoint]
|
|
33
|
+
|
|
34
|
+
[Stripe]
|
|
35
|
+
|
|
|
36
|
+
| webhook: customer.created
|
|
37
|
+
▼
|
|
38
|
+
[Webhook handler endpoint]
|
|
39
|
+
|
|
|
40
|
+
| GraphQL mutation
|
|
41
|
+
▼
|
|
42
|
+
[Twenty CRM API]
|
|
43
|
+
|
|
44
|
+
[Intercom]
|
|
45
|
+
|
|
|
46
|
+
| webhook: conversation.created
|
|
47
|
+
▼
|
|
48
|
+
[Webhook handler endpoint]
|
|
49
|
+
|
|
|
50
|
+
| GraphQL mutation (create Note)
|
|
51
|
+
▼
|
|
52
|
+
[Twenty CRM API]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 2. CREDENTIALS REQUIRED
|
|
58
|
+
|
|
59
|
+
**Types only — do not store values in this document.**
|
|
60
|
+
|
|
61
|
+
| Secret | Type | Where to get it | Where to store it |
|
|
62
|
+
|---|---|---|---|
|
|
63
|
+
| `TWENTY_API_TOKEN` | Bearer token | Twenty: Settings > API > Tokens | `.env` / secrets manager |
|
|
64
|
+
| `TWENTY_API_URL` | URL string | Twenty workspace URL | `.env` |
|
|
65
|
+
| `STRIPE_WEBHOOK_SECRET` | Webhook signing secret | Stripe: Developers > Webhooks | `.env` / secrets manager |
|
|
66
|
+
| `INTERCOM_WEBHOOK_SECRET` | Webhook signing secret | Intercom: Settings > Developers | `.env` / secrets manager |
|
|
67
|
+
| `APOLLO_API_KEY` | API key | Apollo: Settings > API | `.env` / secrets manager |
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 3. ENDPOINT CONTRACTS
|
|
72
|
+
|
|
73
|
+
### Twenty GraphQL API
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
URL: <TWENTY_API_URL>/graphql
|
|
77
|
+
Method: POST
|
|
78
|
+
Auth: Authorization: Bearer <TWENTY_API_TOKEN>
|
|
79
|
+
Type: application/json
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Twenty REST API
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
URL: <TWENTY_API_URL>/api/objects/<object-name>
|
|
86
|
+
Method: GET / POST / PATCH / DELETE
|
|
87
|
+
Auth: Authorization: Bearer <TWENTY_API_TOKEN>
|
|
88
|
+
Type: application/json
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Inbound webhook receiver (to be built by developer)
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
URL: https://[your-domain]/webhooks/stripe (example)
|
|
95
|
+
Method: POST
|
|
96
|
+
Auth: Validate STRIPE_WEBHOOK_SECRET signature header
|
|
97
|
+
Handles: customer.created, customer.subscription.updated
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 4. DATA FLOW — ENRICHMENT PIPELINE
|
|
103
|
+
|
|
104
|
+
**Sequence:**
|
|
105
|
+
|
|
106
|
+
1. Enrichment job reads Apollo export (CSV or API)
|
|
107
|
+
2. For each record:
|
|
108
|
+
a. Check if `email` already exists in Twenty (GraphQL query)
|
|
109
|
+
b. If match found: update Person record (GraphQL mutation: `updatePerson`)
|
|
110
|
+
c. If no match: create Person record (GraphQL mutation: `createPerson`)
|
|
111
|
+
d. Check if company domain already exists in Twenty
|
|
112
|
+
e. If no match: create Company record (`createCompany`) and link to Person
|
|
113
|
+
3. Log all results (created, updated, skipped, error) to output file
|
|
114
|
+
4. Report: total processed, errors, duplicates merged
|
|
115
|
+
|
|
116
|
+
**Key GraphQL operations:**
|
|
117
|
+
|
|
118
|
+
- `people` query — check for existing Person by email
|
|
119
|
+
- `createPerson` mutation — insert new Person
|
|
120
|
+
- `updatePerson` mutation — merge enrichment fields
|
|
121
|
+
- `createCompany` mutation — insert new Company
|
|
122
|
+
- `companies` query — check for existing Company by domain
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 5. DATA FLOW — STRIPE WEBHOOK
|
|
127
|
+
|
|
128
|
+
**Sequence:**
|
|
129
|
+
|
|
130
|
+
1. Stripe fires `customer.created` event to webhook receiver
|
|
131
|
+
2. Receiver validates `Stripe-Signature` header using `STRIPE_WEBHOOK_SECRET`
|
|
132
|
+
3. Receiver extracts: `email`, `name`, `metadata.company_name`
|
|
133
|
+
4. Receiver queries Twenty for existing Person by email
|
|
134
|
+
5. If not found: creates Person record with `createPerson` mutation
|
|
135
|
+
6. Creates a Note on the Person: "Stripe customer created — ID: [stripe-id]"
|
|
136
|
+
7. Returns HTTP 200 to Stripe
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 6. DATA FLOW — INTERCOM WEBHOOK
|
|
141
|
+
|
|
142
|
+
**Sequence:**
|
|
143
|
+
|
|
144
|
+
1. Intercom fires `conversation.created` event
|
|
145
|
+
2. Receiver validates signature
|
|
146
|
+
3. Receiver extracts: `contact.email`, `conversation.id`, `conversation.subject`
|
|
147
|
+
4. Receiver queries Twenty for Person by email
|
|
148
|
+
5. If found: creates Note on Person with conversation summary
|
|
149
|
+
6. Returns HTTP 200 to Intercom
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 7. ENVIRONMENT CHECKLIST
|
|
154
|
+
|
|
155
|
+
| Environment | Status | Twenty workspace | API token |
|
|
156
|
+
|---|---|---|---|
|
|
157
|
+
| Development | [ready / pending] | [dev workspace ID] | [dev token] |
|
|
158
|
+
| Staging | [ready / pending] | [staging workspace ID] | [staging token] |
|
|
159
|
+
| Production | [ready / pending] | [prod workspace ID] | [prod token] |
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 8. ROLLBACK PLAN
|
|
164
|
+
|
|
165
|
+
If a bad data push occurs:
|
|
166
|
+
|
|
167
|
+
1. Stop the enrichment job or webhook receiver
|
|
168
|
+
2. Note the exact timestamp of the bad push
|
|
169
|
+
3. Query Twenty for all records created/updated after that timestamp:
|
|
170
|
+
```graphql
|
|
171
|
+
query {
|
|
172
|
+
people(filter: { createdAt: { gte: "YYYY-MM-DDTHH:MM:SSZ" } }) {
|
|
173
|
+
edges { node { id createdAt } }
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
4. Use `deleteManyPeople` mutation to remove the affected records
|
|
178
|
+
5. Fix the source data and re-run the pipeline
|
|
179
|
+
|
|
180
|
+
**Contact for rollback approvals:** [CRM Admin name and email]
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 9. OPEN ITEMS FOR DEVELOPER
|
|
185
|
+
|
|
186
|
+
| Item | Owner | Due date | Notes |
|
|
187
|
+
|---|---|---|---|
|
|
188
|
+
| [Webhook receiver for Stripe] | [developer] | YYYY-MM-DD | |
|
|
189
|
+
| [Enrichment job script] | [developer] | YYYY-MM-DD | |
|
|
190
|
+
| [Secrets stored in CI] | [devops] | YYYY-MM-DD | |
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Lead Enrichment Pipeline — [CLIENT NAME]
|
|
2
|
+
|
|
3
|
+
**Date:** YYYY-MM-DD
|
|
4
|
+
**Kit:** `growthub-twenty-crm-v1`
|
|
5
|
+
**Mode:** `[cloud / self-hosted / local-fork / agent-only]`
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. ENRICHMENT PROVIDER(S)
|
|
10
|
+
|
|
11
|
+
| Provider | Auth mechanism | Data tier | Primary use |
|
|
12
|
+
|---|---|---|---|
|
|
13
|
+
| [Apollo] | Bearer token | Person + Company | Outbound lead source |
|
|
14
|
+
| [Clearbit] | Bearer token | Company | Company enrichment |
|
|
15
|
+
| [Clay] | API key | Person + Company | Enrichment waterfall |
|
|
16
|
+
| [Hunter] | API key | Person | Email verification |
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 2. SOURCE FIELDS PROVIDED
|
|
21
|
+
|
|
22
|
+
### [Provider name] — Person fields
|
|
23
|
+
|
|
24
|
+
| Provider field | Data type | Example value |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| `first_name` | string | `Jane` |
|
|
27
|
+
| `last_name` | string | `Doe` |
|
|
28
|
+
| `email` | string | `jane@example.com` |
|
|
29
|
+
| `title` | string | `Head of Growth` |
|
|
30
|
+
| `linkedin_url` | string | `https://linkedin.com/in/janedoe` |
|
|
31
|
+
| `organization.name` | string | `Acme Corp` |
|
|
32
|
+
| `organization.website_url` | string | `acme.com` |
|
|
33
|
+
|
|
34
|
+
### [Provider name] — Company fields
|
|
35
|
+
|
|
36
|
+
| Provider field | Data type | Example value |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `name` | string | `Acme Corp` |
|
|
39
|
+
| `website_url` | string | `acme.com` |
|
|
40
|
+
| `employee_count` | integer | `250` |
|
|
41
|
+
| `industry` | string | `Software` |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 3. DEDUPLICATION STRATEGY
|
|
46
|
+
|
|
47
|
+
**Person dedup key:** `emails.primaryEmail`
|
|
48
|
+
**Company dedup key:** `domain`
|
|
49
|
+
**Secondary person key (when email unavailable):** `linkedInLink.url`
|
|
50
|
+
|
|
51
|
+
**Dedup behavior:**
|
|
52
|
+
- Match found → **merge** (update existing record with enriched fields)
|
|
53
|
+
- No match found → **insert** (create new record)
|
|
54
|
+
- If both email and LinkedIn are absent → **skip and log** the record for manual review
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 4. IMPORT MODE
|
|
59
|
+
|
|
60
|
+
**Selected mode:** `[insert-only / merge / merge-with-insert-fallback]`
|
|
61
|
+
|
|
62
|
+
**Rationale:** [Why this mode was chosen for this client's data state]
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 5. IMPORT METHOD
|
|
67
|
+
|
|
68
|
+
**Method:** `[CSV import via Twenty UI / GraphQL mutation batch / REST API batch / webhook ingest]`
|
|
69
|
+
|
|
70
|
+
**Import sequence:**
|
|
71
|
+
1. Export [source] as CSV
|
|
72
|
+
2. Clean CSV: remove duplicates, normalize email format (lowercase), strip leading/trailing spaces
|
|
73
|
+
3. Run field mapping (see section 6)
|
|
74
|
+
4. Upload via Twenty UI (Settings > Import) or batch via API
|
|
75
|
+
5. Run post-import audit (section 7)
|
|
76
|
+
|
|
77
|
+
**Batch size recommendation:** [N] records per batch (to avoid rate limits)
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 6. FIELD MAPPING
|
|
82
|
+
|
|
83
|
+
See `EnrichmentFieldMap` artifact for full field-by-field alignment table.
|
|
84
|
+
|
|
85
|
+
Summary of key mappings:
|
|
86
|
+
|
|
87
|
+
| Source field | → | Twenty object | Twenty field | Transformation |
|
|
88
|
+
|---|---|---|---|---|
|
|
89
|
+
| `email` | → | `Person` | `emails.primaryEmail` | none |
|
|
90
|
+
| `first_name` | → | `Person` | `name.firstName` | none |
|
|
91
|
+
| `last_name` | → | `Person` | `name.lastName` | none |
|
|
92
|
+
| `title` | → | `Person` | `position` | none |
|
|
93
|
+
| `linkedin_url` | → | `Person` | `linkedInLink.url` | none |
|
|
94
|
+
| `organization.name` | → | `Company` | `name` | none |
|
|
95
|
+
| `organization.website_url` | → | `Company` | `domain` | strip protocol prefix |
|
|
96
|
+
| `employee_count` | → | `Company` | `employees` | integer cast |
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 7. POST-IMPORT VALIDATION
|
|
101
|
+
|
|
102
|
+
After import completes:
|
|
103
|
+
|
|
104
|
+
- [ ] Record count matches expected import total (within ±2%)
|
|
105
|
+
- [ ] Duplicate check: no duplicate email addresses in Person
|
|
106
|
+
- [ ] Relation integrity: all Person records with a company are linked to a Company record
|
|
107
|
+
- [ ] Sample review: spot-check 10 records for correct field mapping
|
|
108
|
+
- [ ] Error log reviewed: all skipped records documented with reason
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## 8. ERROR AND FAILURE HANDLING
|
|
113
|
+
|
|
114
|
+
| Error type | Behavior | Resolution |
|
|
115
|
+
|---|---|---|
|
|
116
|
+
| Invalid email format | Skip record, log to error file | Manual review |
|
|
117
|
+
| Duplicate email (on insert-only) | Skip record, log | Merge manually or switch to merge mode |
|
|
118
|
+
| Missing required field | Skip record, log | Enrich from secondary provider |
|
|
119
|
+
| API rate limit hit | Pause [N] seconds, retry | Reduce batch size |
|
|
120
|
+
| Company not found | Create new Company record | Review after import |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 9. UPDATE FREQUENCY
|
|
125
|
+
|
|
126
|
+
**Enrichment cadence:** [one-time import / weekly / monthly / on-trigger]
|
|
127
|
+
|
|
128
|
+
**Trigger for re-enrichment (if event-driven):** [e.g. "when Opportunity stage changes to QUALIFIED"]
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Pipeline Automation Brief — [CLIENT NAME]
|
|
2
|
+
|
|
3
|
+
**Date:** YYYY-MM-DD
|
|
4
|
+
**Kit:** `growthub-twenty-crm-v1`
|
|
5
|
+
**Mode:** `[cloud / self-hosted / local-fork / agent-only]`
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## AUTOMATION INVENTORY
|
|
10
|
+
|
|
11
|
+
| # | Automation name | Trigger | Action | Status |
|
|
12
|
+
|---|---|---|---|---|
|
|
13
|
+
| 1 | [Name] | [trigger type] | [action type] | [planned / active] |
|
|
14
|
+
| 2 | [Name] | [trigger type] | [action type] | [planned / active] |
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## AUTOMATION 1 — [NAME]
|
|
19
|
+
|
|
20
|
+
**Purpose:** [What problem this automation solves]
|
|
21
|
+
|
|
22
|
+
### Trigger
|
|
23
|
+
|
|
24
|
+
| Property | Value |
|
|
25
|
+
|---|---|
|
|
26
|
+
| Trigger type | `[on_create / on_update / on_field_change / on_schedule / on_webhook]` |
|
|
27
|
+
| Target object | `[Person / Company / Opportunity / Note / Task / <custom>]` |
|
|
28
|
+
| Condition | `[field] [operator] [value]` (e.g. `stage == "QUALIFIED"`) |
|
|
29
|
+
| Previous value (if field change) | `[previous value]` |
|
|
30
|
+
| New value (if field change) | `[new value]` |
|
|
31
|
+
|
|
32
|
+
### Action sequence
|
|
33
|
+
|
|
34
|
+
| Step | Action type | Target | Parameters |
|
|
35
|
+
|---|---|---|---|
|
|
36
|
+
| 1 | `[update_field]` | `[Opportunity]` | `[field: assignee, value: <sales-rep-id>]` |
|
|
37
|
+
| 2 | `[create_task]` | `[Person]` | `[title: "Follow up", dueAt: +2 days, assignee: <sales-rep-id>]` |
|
|
38
|
+
| 3 | `[send_webhook]` | external | See webhook spec |
|
|
39
|
+
|
|
40
|
+
### Failure behavior
|
|
41
|
+
|
|
42
|
+
**If step 1 fails:** [retry / skip / halt]
|
|
43
|
+
**If step 2 fails:** [retry / skip / halt]
|
|
44
|
+
**If webhook fails:** retry 3× with exponential backoff (5s, 15s, 45s), then log and alert
|
|
45
|
+
|
|
46
|
+
### Monitoring
|
|
47
|
+
|
|
48
|
+
**How to verify this automation is running:** [e.g. "Check Task creation count in Twenty dashboard daily"]
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## AUTOMATION 2 — [NAME]
|
|
53
|
+
|
|
54
|
+
**Purpose:** [What problem this automation solves]
|
|
55
|
+
|
|
56
|
+
### Trigger
|
|
57
|
+
|
|
58
|
+
| Property | Value |
|
|
59
|
+
|---|---|
|
|
60
|
+
| Trigger type | `[trigger type]` |
|
|
61
|
+
| Target object | `[object]` |
|
|
62
|
+
| Condition | `[condition]` |
|
|
63
|
+
|
|
64
|
+
### Action sequence
|
|
65
|
+
|
|
66
|
+
| Step | Action type | Target | Parameters |
|
|
67
|
+
|---|---|---|---|
|
|
68
|
+
| 1 | `[action type]` | `[target]` | `[parameters]` |
|
|
69
|
+
|
|
70
|
+
### Failure behavior
|
|
71
|
+
|
|
72
|
+
**If any action fails:** [behavior]
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## AUTOMATION DESIGN DECISIONS
|
|
77
|
+
|
|
78
|
+
| Decision | Choice | Rationale |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| [Decision 1] | [Choice] | [Rationale] |
|
|
81
|
+
| [Decision 2] | [Choice] | [Rationale] |
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## OPEN QUESTIONS
|
|
86
|
+
|
|
87
|
+
- [ ] [Open question 1 — e.g. "Should the assignment automation use round-robin or territory-based routing?"]
|
|
88
|
+
- [ ] [Open question 2]
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Webhook Integration Spec — [CLIENT NAME]
|
|
2
|
+
|
|
3
|
+
**Date:** YYYY-MM-DD
|
|
4
|
+
**Kit:** `growthub-twenty-crm-v1`
|
|
5
|
+
**Mode:** `[cloud / self-hosted / local-fork / agent-only]`
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## WEBHOOK INVENTORY
|
|
10
|
+
|
|
11
|
+
| # | Name | Direction | Event | Status |
|
|
12
|
+
|---|---|---|---|---|
|
|
13
|
+
| 1 | [Name] | [inbound / outbound] | [event] | [planned / active] |
|
|
14
|
+
| 2 | [Name] | [inbound / outbound] | [event] | [planned / active] |
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## WEBHOOK 1 — [NAME]
|
|
19
|
+
|
|
20
|
+
**Direction:** `[inbound / outbound]`
|
|
21
|
+
**Purpose:** [What this webhook enables — e.g. "When a Stripe customer is created, create a Company record in Twenty"]
|
|
22
|
+
|
|
23
|
+
### Event Definition
|
|
24
|
+
|
|
25
|
+
| Property | Value |
|
|
26
|
+
|---|---|
|
|
27
|
+
| Event source | `[Stripe / Intercom / Segment / Twenty / other]` |
|
|
28
|
+
| Event name | `[e.g. customer.created / opportunity.created]` |
|
|
29
|
+
| Trigger object | `[Twenty object or external object]` |
|
|
30
|
+
| Trigger condition | `[e.g. "all events" / "stage = CLOSED_WON"]` |
|
|
31
|
+
|
|
32
|
+
### Payload Schema
|
|
33
|
+
|
|
34
|
+
**Source payload (what the sender sends):**
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"event": "[event-name]",
|
|
39
|
+
"created": 1713000000,
|
|
40
|
+
"data": {
|
|
41
|
+
"object": {
|
|
42
|
+
"id": "[source-id]",
|
|
43
|
+
"email": "[email]",
|
|
44
|
+
"name": "[name]",
|
|
45
|
+
"[field]": "[value]"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Target payload (what Twenty or the receiver expects):**
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"name": "[value]",
|
|
56
|
+
"emails": { "primaryEmail": "[email]" },
|
|
57
|
+
"[field]": "[value]"
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Endpoint
|
|
62
|
+
|
|
63
|
+
| Property | Value |
|
|
64
|
+
|---|---|
|
|
65
|
+
| URL | `[https://api.twenty.com/graphql or external endpoint]` |
|
|
66
|
+
| Method | `[POST]` |
|
|
67
|
+
| Auth header | `Authorization: Bearer <TWENTY_API_TOKEN>` |
|
|
68
|
+
| Content-Type | `application/json` |
|
|
69
|
+
|
|
70
|
+
### Field Mapping (inbound to Twenty)
|
|
71
|
+
|
|
72
|
+
| Source field | → | Twenty object | Twenty field | Transformation |
|
|
73
|
+
|---|---|---|---|---|
|
|
74
|
+
| `data.object.email` | → | `Person` | `emails.primaryEmail` | none |
|
|
75
|
+
| `data.object.name` | → | `Company` | `name` | none |
|
|
76
|
+
|
|
77
|
+
### Retry Policy
|
|
78
|
+
|
|
79
|
+
| Property | Value |
|
|
80
|
+
|---|---|
|
|
81
|
+
| Max retries | 3 |
|
|
82
|
+
| Backoff | 5s, 15s, 45s |
|
|
83
|
+
| On max retry failure | log to error queue and alert CRM admin |
|
|
84
|
+
|
|
85
|
+
### Test Procedure
|
|
86
|
+
|
|
87
|
+
1. Use [Stripe CLI / webhook testing tool] to send a test event
|
|
88
|
+
2. Verify the payload arrives at the endpoint
|
|
89
|
+
3. Verify the Twenty record is created or updated correctly
|
|
90
|
+
4. Check for any field mapping errors in the response
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## WEBHOOK 2 — [NAME]
|
|
95
|
+
|
|
96
|
+
**Direction:** `[inbound / outbound]`
|
|
97
|
+
**Purpose:** [Purpose]
|
|
98
|
+
|
|
99
|
+
### Event Definition
|
|
100
|
+
|
|
101
|
+
| Property | Value |
|
|
102
|
+
|---|---|
|
|
103
|
+
| Event source | `[source]` |
|
|
104
|
+
| Event name | `[event]` |
|
|
105
|
+
|
|
106
|
+
### Payload Schema
|
|
107
|
+
|
|
108
|
+
[See payload schema above pattern]
|
|
109
|
+
|
|
110
|
+
### Endpoint
|
|
111
|
+
|
|
112
|
+
| Property | Value |
|
|
113
|
+
|---|---|
|
|
114
|
+
| URL | `[URL]` |
|
|
115
|
+
| Auth | `[auth mechanism]` |
|
|
116
|
+
|
|
117
|
+
### Retry Policy
|
|
118
|
+
|
|
119
|
+
| Property | Value |
|
|
120
|
+
|---|---|
|
|
121
|
+
| Max retries | 3 |
|
|
122
|
+
| On failure | [behavior] |
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## OPEN QUESTIONS
|
|
127
|
+
|
|
128
|
+
- [ ] [Open question 1 — e.g. "Does Intercom's webhook payload include the contact email consistently?"]
|
|
129
|
+
- [ ] [Open question 2]
|