decoupled-cli 2.0.3 → 2.1.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/README.md +38 -11
- package/dist/commands/auth.js +16 -6
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/content.js +3 -3
- package/dist/commands/content.js.map +1 -1
- package/dist/commands/download.js +3 -3
- package/dist/commands/spaces.d.ts.map +1 -1
- package/dist/commands/spaces.js +20 -23
- package/dist/commands/spaces.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +8 -3
- package/dist/lib/config.js.map +1 -1
- package/examples/.cursorrules +31 -31
- package/examples/CLAUDE.md +44 -44
- package/examples/GEMINI.md +42 -42
- package/examples/content-import-sample.json +237 -62
- package/package.json +3 -3
package/examples/GEMINI.md
CHANGED
|
@@ -5,7 +5,7 @@ This document provides Gemini with comprehensive instructions for building compl
|
|
|
5
5
|
## Project Overview
|
|
6
6
|
|
|
7
7
|
**Architecture**: Headless Drupal backend with Next.js frontend
|
|
8
|
-
**Backend**: Drupal 11 with GraphQL Compose and
|
|
8
|
+
**Backend**: Drupal 11 with GraphQL Compose and DC Import API
|
|
9
9
|
**Frontend**: Next.js 15 with TypeScript, Tailwind CSS, and Apollo GraphQL
|
|
10
10
|
**Environment**: DDEV local development
|
|
11
11
|
|
|
@@ -18,7 +18,7 @@ This document provides Gemini with comprehensive instructions for building compl
|
|
|
18
18
|
- `DRUPAL_REVALIDATE_SECRET` - Secret for on-demand revalidation
|
|
19
19
|
- `NODE_TLS_REJECT_UNAUTHORIZED=0` - Allow self-signed certificates (development)
|
|
20
20
|
|
|
21
|
-
##
|
|
21
|
+
## DC CLI Setup
|
|
22
22
|
|
|
23
23
|
**First-time CLI setup:**
|
|
24
24
|
```bash
|
|
@@ -40,7 +40,7 @@ npx decoupled-cli spaces use <space_id>
|
|
|
40
40
|
npx decoupled-cli spaces current
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
**OAuth Prerequisites (for `
|
|
43
|
+
**OAuth Prerequisites (for `decoupled-cli auth oauth`):**
|
|
44
44
|
Your `.env.local` must contain:
|
|
45
45
|
- `NEXT_PUBLIC_DRUPAL_BASE_URL=https://your-space.decoupled.io`
|
|
46
46
|
- `DRUPAL_CLIENT_ID=your_oauth_client_id`
|
|
@@ -48,11 +48,11 @@ Your `.env.local` must contain:
|
|
|
48
48
|
|
|
49
49
|
**Authentication Method Differences:**
|
|
50
50
|
- **OAuth** → Works with your Drupal site API (content import, Drupal operations)
|
|
51
|
-
- **Personal Access Token** → Works with
|
|
51
|
+
- **Personal Access Token** → Works with Decoupled Drupal platform API (spaces, users, organizations)
|
|
52
52
|
|
|
53
53
|
**If CLI is not available locally:**
|
|
54
54
|
- For projects with decoupled-cli in package.json: Run `npm install` then use `npx decoupled-cli`
|
|
55
|
-
- For development: `cd cli && npm install && npm run build && npm link` then use `
|
|
55
|
+
- For development: `cd cli && npm install && npm run build && npm link` then use `decoupled-cli`
|
|
56
56
|
- Always prefer using `npx decoupled-cli` for consistency and local package management
|
|
57
57
|
|
|
58
58
|
## End-to-End Development Workflow
|
|
@@ -73,8 +73,8 @@ Use OAuth authentication for direct Drupal content import, then frontend develop
|
|
|
73
73
|
|
|
74
74
|
**Create a todo list for tracking progress:**
|
|
75
75
|
```markdown
|
|
76
|
-
1. Verify
|
|
77
|
-
2. Create
|
|
76
|
+
1. Verify DC CLI authentication (npx decoupled-cli auth status)
|
|
77
|
+
2. Create DC Import JSON for [content_type]
|
|
78
78
|
3. Import content type and sample content to Drupal (npx decoupled-cli content import)
|
|
79
79
|
4. **CRITICAL**: Run schema generation (`npm run generate-schema`) to update GraphQL schema
|
|
80
80
|
5. Create TypeScript types and GraphQL queries
|
|
@@ -84,11 +84,11 @@ Use OAuth authentication for direct Drupal content import, then frontend develop
|
|
|
84
84
|
9. Validate end-to-end functionality
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
**Legacy Platform Workflow (PAT +
|
|
87
|
+
**Legacy Platform Workflow (PAT + Decoupled Drupal Platform):**
|
|
88
88
|
```markdown
|
|
89
|
-
1. Verify
|
|
89
|
+
1. Verify DC CLI authentication (npx decoupled-cli auth status)
|
|
90
90
|
2. Set default space if needed (npx decoupled-cli spaces use <id>)
|
|
91
|
-
3. Create
|
|
91
|
+
3. Create DC Import JSON for [content_type]
|
|
92
92
|
4. Import content type and sample content via platform (npx decoupled-cli spaces content-import)
|
|
93
93
|
5. **CRITICAL**: Run schema generation (`npm run generate-schema`) to update GraphQL schema
|
|
94
94
|
6. Create TypeScript types and GraphQL queries
|
|
@@ -119,7 +119,7 @@ npx decoupled-cli spaces use <space_id>
|
|
|
119
119
|
|
|
120
120
|
**If CLI authentication fails:**
|
|
121
121
|
- For OAuth: Verify `.env.local` contains `NEXT_PUBLIC_DRUPAL_BASE_URL`, `DRUPAL_CLIENT_ID`, `DRUPAL_CLIENT_SECRET`
|
|
122
|
-
- For personal tokens: Check that
|
|
122
|
+
- For personal tokens: Check that DC platform is accessible
|
|
123
123
|
- Ensure user has proper permissions for the operations you're trying to perform
|
|
124
124
|
|
|
125
125
|
**Important: Command Availability by Authentication Method**
|
|
@@ -127,7 +127,7 @@ npx decoupled-cli spaces use <space_id>
|
|
|
127
127
|
- **PAT-only commands**: `spaces list`, `spaces use`, `usage`, `org info`
|
|
128
128
|
- **Universal commands**: `auth login`, `auth oauth`, `auth test`
|
|
129
129
|
|
|
130
|
-
### 2.
|
|
130
|
+
### 2. DC Import JSON Creation
|
|
131
131
|
|
|
132
132
|
**Get example format with CLI:**
|
|
133
133
|
```bash
|
|
@@ -186,14 +186,14 @@ npx decoupled-cli spaces content-import --example > my-content-type.json
|
|
|
186
186
|
- **For image fields**: Use full URLs with the Drupal domain from `.env.local`, not relative paths:
|
|
187
187
|
```json
|
|
188
188
|
"featured_image": {
|
|
189
|
-
"uri": "${DRUPAL_BASE_URL}/modules/custom/
|
|
189
|
+
"uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
|
|
190
190
|
"alt": "Description of the image",
|
|
191
191
|
"title": "Image title"
|
|
192
192
|
}
|
|
193
193
|
```
|
|
194
194
|
Always read the `NEXT_PUBLIC_DRUPAL_BASE_URL` from `.env.local` and use that as the base for image URIs to ensure images load correctly from the Drupal backend.
|
|
195
195
|
|
|
196
|
-
### 3. Import via
|
|
196
|
+
### 3. Import via DC CLI
|
|
197
197
|
|
|
198
198
|
**Import Content Type:**
|
|
199
199
|
```bash
|
|
@@ -203,7 +203,7 @@ npx decoupled-cli content import --file content-type-import.json
|
|
|
203
203
|
# Or preview first to see what will be imported
|
|
204
204
|
npx decoupled-cli content import --file content-type-import.json --preview
|
|
205
205
|
|
|
206
|
-
# LEGACY: Import via
|
|
206
|
+
# LEGACY: Import via Decoupled Drupal platform (requires PAT authentication and space setup)
|
|
207
207
|
npx decoupled-cli spaces content-import --file content-type-import.json
|
|
208
208
|
npx decoupled-cli spaces content-import <space_id> --file content-type-import.json
|
|
209
209
|
```
|
|
@@ -220,7 +220,7 @@ npx decoupled-cli content import --example > content-type-import.json
|
|
|
220
220
|
- Field machine names (auto-generated)
|
|
221
221
|
- Node IDs created
|
|
222
222
|
- GraphQL schema updates
|
|
223
|
-
- **Important**: GraphQL field names may differ from
|
|
223
|
+
- **Important**: GraphQL field names may differ from DC field IDs (check actual schema)
|
|
224
224
|
|
|
225
225
|
**CRITICAL: Immediately Update GraphQL Schema After Import:**
|
|
226
226
|
```bash
|
|
@@ -500,7 +500,7 @@ npm run dev
|
|
|
500
500
|
### 6. Testing Checklist
|
|
501
501
|
|
|
502
502
|
**Verify each step:**
|
|
503
|
-
- [ ]
|
|
503
|
+
- [ ] DC import successful with no errors
|
|
504
504
|
- [ ] GraphQL schema includes new content type
|
|
505
505
|
- [ ] TypeScript types are properly defined
|
|
506
506
|
- [ ] Build process completes without errors
|
|
@@ -540,7 +540,7 @@ npm run dev
|
|
|
540
540
|
```json
|
|
541
541
|
"product_images": [
|
|
542
542
|
{
|
|
543
|
-
"uri": "${DRUPAL_BASE_URL}/modules/custom/
|
|
543
|
+
"uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
|
|
544
544
|
"alt": "Product showcase image",
|
|
545
545
|
"title": "Product Image"
|
|
546
546
|
}
|
|
@@ -588,7 +588,7 @@ npm run dev
|
|
|
588
588
|
**Sample content with image URI:**
|
|
589
589
|
```json
|
|
590
590
|
"profile_image": {
|
|
591
|
-
"uri": "${DRUPAL_BASE_URL}/modules/custom/
|
|
591
|
+
"uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
|
|
592
592
|
"alt": "Team member headshot",
|
|
593
593
|
"title": "Profile Photo"
|
|
594
594
|
}
|
|
@@ -617,7 +617,7 @@ npm run dev
|
|
|
617
617
|
```json
|
|
618
618
|
"project_images": [
|
|
619
619
|
{
|
|
620
|
-
"uri": "${DRUPAL_BASE_URL}/modules/custom/
|
|
620
|
+
"uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
|
|
621
621
|
"alt": "Project screenshot showing main interface",
|
|
622
622
|
"title": "Project Interface"
|
|
623
623
|
}
|
|
@@ -628,7 +628,7 @@ npm run dev
|
|
|
628
628
|
|
|
629
629
|
### Common Issues
|
|
630
630
|
|
|
631
|
-
**1.
|
|
631
|
+
**1. DC Import Fails**
|
|
632
632
|
- Check OAuth token expiration
|
|
633
633
|
- Verify JSON structure matches `schema/sample.json` format
|
|
634
634
|
- Ensure field IDs don't start with `field_`
|
|
@@ -645,15 +645,15 @@ npm run dev
|
|
|
645
645
|
- Verify GraphQL query syntax
|
|
646
646
|
|
|
647
647
|
**4. Content Not Displaying**
|
|
648
|
-
- Check GraphQL query field names match Drupal fields (may not match
|
|
648
|
+
- Check GraphQL query field names match Drupal fields (may not match DC field IDs)
|
|
649
649
|
- Verify content was created and published
|
|
650
650
|
- Check query variables and pagination
|
|
651
651
|
- For HTML content showing raw tags, use `dangerouslySetInnerHTML={{ __html: field.processed }}`
|
|
652
652
|
|
|
653
|
-
**5. GraphQL Schema Not Updated After
|
|
654
|
-
- **Critical Issue**:
|
|
653
|
+
**5. GraphQL Schema Not Updated After DC Import**
|
|
654
|
+
- **Critical Issue**: DC imports create content types successfully but GraphQL schema may not update immediately
|
|
655
655
|
- Content exists in Drupal but `nodeProducts` query returns "field not found" errors
|
|
656
|
-
- This is the most common issue with
|
|
656
|
+
- This is the most common issue with DC imports
|
|
657
657
|
|
|
658
658
|
**Solution Process**:
|
|
659
659
|
1. Clear Drupal caches (if you have admin access)
|
|
@@ -663,7 +663,7 @@ npm run dev
|
|
|
663
663
|
|
|
664
664
|
### Essential Schema Generation Workflow
|
|
665
665
|
|
|
666
|
-
**CRITICAL**: Always run schema generation after
|
|
666
|
+
**CRITICAL**: Always run schema generation after DC imports to ensure GraphQL integration works properly.
|
|
667
667
|
|
|
668
668
|
```bash
|
|
669
669
|
# Generate updated GraphQL schema after content type imports
|
|
@@ -677,7 +677,7 @@ This command:
|
|
|
677
677
|
- Validates that new content types are available in GraphQL
|
|
678
678
|
|
|
679
679
|
**Add this to your workflow**:
|
|
680
|
-
1. Import content type via
|
|
680
|
+
1. Import content type via DC API
|
|
681
681
|
2. **Immediately run**: `npm run generate-schema`
|
|
682
682
|
3. Check generated schema includes your new content type
|
|
683
683
|
4. Test GraphQL queries
|
|
@@ -713,7 +713,7 @@ npx decoupled-cli spaces list
|
|
|
713
713
|
# Check current default space
|
|
714
714
|
npx decoupled-cli spaces current
|
|
715
715
|
|
|
716
|
-
# Get health status of
|
|
716
|
+
# Get health status of DC platform
|
|
717
717
|
npx decoupled-cli health check
|
|
718
718
|
|
|
719
719
|
# Check organization info
|
|
@@ -778,7 +778,7 @@ npx decoupled-cli content import --file your-content.json
|
|
|
778
778
|
7. **Include proper TypeScript types** for all data structures
|
|
779
779
|
8. **Test the full user journey** from listing to detail pages
|
|
780
780
|
9. **Use `dangerouslySetInnerHTML`** for processed HTML content from Drupal to avoid raw tag display
|
|
781
|
-
10. **Verify GraphQL field names** match actual schema, not
|
|
781
|
+
10. **Verify GraphQL field names** match actual schema, not DC field IDs
|
|
782
782
|
|
|
783
783
|
## Success Criteria
|
|
784
784
|
|
|
@@ -796,7 +796,7 @@ A successful end-to-end implementation should:
|
|
|
796
796
|
|
|
797
797
|
Based on successful product catalog implementation, here are critical learnings to avoid common pitfalls:
|
|
798
798
|
|
|
799
|
-
###
|
|
799
|
+
### DC Import Format Issues
|
|
800
800
|
|
|
801
801
|
**Problem**: Field values incorrectly formatted with "field_" prefix
|
|
802
802
|
```json
|
|
@@ -817,14 +817,14 @@ Based on successful product catalog implementation, here are critical learnings
|
|
|
817
817
|
|
|
818
818
|
### GraphQL Field Name Mapping
|
|
819
819
|
|
|
820
|
-
**Problem**: Assuming GraphQL field names match
|
|
820
|
+
**Problem**: Assuming GraphQL field names match DC field IDs
|
|
821
821
|
```typescript
|
|
822
822
|
// WRONG - Field names may be transformed
|
|
823
|
-
price: string //
|
|
823
|
+
price: string // DC field ID
|
|
824
824
|
fieldPrice: string // What you might expect in GraphQL
|
|
825
825
|
|
|
826
826
|
// CORRECT - Check actual schema
|
|
827
|
-
price: string // Actual GraphQL field name (can match
|
|
827
|
+
price: string // Actual GraphQL field name (can match DC ID)
|
|
828
828
|
inStock: boolean // camelCase transformation
|
|
829
829
|
productImages: object // snake_case to camelCase
|
|
830
830
|
```
|
|
@@ -833,7 +833,7 @@ productImages: object // snake_case to camelCase
|
|
|
833
833
|
|
|
834
834
|
### GraphQL Field Value Structure Discovery
|
|
835
835
|
|
|
836
|
-
**Critical Learning**: GraphQL field values from
|
|
836
|
+
**Critical Learning**: GraphQL field values from DC imports return as simple types, not objects:
|
|
837
837
|
|
|
838
838
|
```typescript
|
|
839
839
|
// WRONG - Assuming field values are objects with .processed
|
|
@@ -844,7 +844,7 @@ fieldFeatures?: Array<{
|
|
|
844
844
|
processed: string
|
|
845
845
|
}>
|
|
846
846
|
|
|
847
|
-
// CORRECT -
|
|
847
|
+
// CORRECT - DC imports create simple value fields
|
|
848
848
|
price?: string
|
|
849
849
|
features?: string[]
|
|
850
850
|
```
|
|
@@ -957,29 +957,29 @@ npm run dev # Test in development mode
|
|
|
957
957
|
|
|
958
958
|
The most important learning from the product catalog implementation is the **mandatory schema generation step**:
|
|
959
959
|
|
|
960
|
-
**Problem**:
|
|
960
|
+
**Problem**: DC imports successfully create content types and content, but GraphQL schema doesn't update automatically.
|
|
961
961
|
**Symptoms**:
|
|
962
962
|
- `nodeProducts` query returns "field not found" errors
|
|
963
963
|
- Content exists in Drupal but not accessible via GraphQL
|
|
964
964
|
- Route queries work but content type queries fail
|
|
965
965
|
|
|
966
|
-
**Solution**: **ALWAYS run schema generation immediately after
|
|
966
|
+
**Solution**: **ALWAYS run schema generation immediately after DC imports**:
|
|
967
967
|
|
|
968
968
|
```bash
|
|
969
|
-
# After any
|
|
969
|
+
# After any DC import, immediately run:
|
|
970
970
|
npm run generate-schema
|
|
971
971
|
|
|
972
972
|
# This step is MANDATORY for GraphQL integration to work
|
|
973
973
|
```
|
|
974
974
|
|
|
975
975
|
**Why this is critical**:
|
|
976
|
-
-
|
|
976
|
+
- DC API creates Drupal content types but doesn't trigger GraphQL schema rebuilds
|
|
977
977
|
- The `generate-schema` script performs fresh introspection and updates local schema files
|
|
978
978
|
- Without this step, frontend development will fail with "type not found" errors
|
|
979
979
|
- This step bridges the gap between Drupal content type creation and Next.js GraphQL integration
|
|
980
980
|
|
|
981
981
|
**Workflow Integration**:
|
|
982
|
-
1. Import via
|
|
982
|
+
1. Import via DC API ✅
|
|
983
983
|
2. **Run `npm run generate-schema`** ✅ ← CRITICAL STEP
|
|
984
984
|
3. Verify schema includes new content type ✅
|
|
985
985
|
4. Proceed with frontend development ✅
|
|
@@ -989,7 +989,7 @@ This learning transforms the development workflow from "sometimes works" to "rel
|
|
|
989
989
|
### Additional Key Learnings
|
|
990
990
|
|
|
991
991
|
#### GraphQL Field Name Discovery (CRITICAL)
|
|
992
|
-
**Always verify actual GraphQL field names after
|
|
992
|
+
**Always verify actual GraphQL field names after DC import** - they may differ from field IDs used in import JSON.
|
|
993
993
|
|
|
994
994
|
**Field Name Transformations**:
|
|
995
995
|
- `in_stock` becomes `inStock` (camelCase)
|
|
@@ -1039,7 +1039,7 @@ const getActiveTab = () => {
|
|
|
1039
1039
|
#### Build Process Integration
|
|
1040
1040
|
**Essential Commands Sequence**:
|
|
1041
1041
|
```bash
|
|
1042
|
-
# After
|
|
1042
|
+
# After DC import, always run:
|
|
1043
1043
|
npm run generate-schema # Updates GraphQL schema
|
|
1044
1044
|
npm run build # Validates TypeScript and builds
|
|
1045
1045
|
npm run dev # Test in development
|
|
@@ -1,114 +1,289 @@
|
|
|
1
1
|
{
|
|
2
2
|
"model": [
|
|
3
3
|
{
|
|
4
|
-
"bundle": "
|
|
5
|
-
"description": "
|
|
6
|
-
"label": "
|
|
4
|
+
"bundle": "article",
|
|
5
|
+
"description": "Blog articles and news posts with rich media and categorization",
|
|
6
|
+
"label": "Article",
|
|
7
7
|
"body": true,
|
|
8
8
|
"fields": [
|
|
9
9
|
{
|
|
10
|
-
"id": "
|
|
11
|
-
"label": "
|
|
12
|
-
"type": "
|
|
13
|
-
|
|
14
|
-
{
|
|
15
|
-
"id": "location",
|
|
16
|
-
"label": "Location",
|
|
17
|
-
"type": "string"
|
|
10
|
+
"id": "summary",
|
|
11
|
+
"label": "Summary",
|
|
12
|
+
"type": "string",
|
|
13
|
+
"description": "Short text field (max 255 chars) for article preview"
|
|
18
14
|
},
|
|
19
15
|
{
|
|
20
16
|
"id": "featured_image",
|
|
21
17
|
"label": "Featured Image",
|
|
22
|
-
"type": "image"
|
|
18
|
+
"type": "image",
|
|
19
|
+
"description": "Single image upload for article hero"
|
|
23
20
|
},
|
|
24
21
|
{
|
|
25
|
-
"id": "
|
|
26
|
-
"label": "
|
|
27
|
-
"type": "
|
|
22
|
+
"id": "published_date",
|
|
23
|
+
"label": "Published Date",
|
|
24
|
+
"type": "datetime",
|
|
25
|
+
"description": "Date and time field for publication scheduling"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "author",
|
|
29
|
+
"label": "Author Name",
|
|
30
|
+
"type": "string"
|
|
28
31
|
},
|
|
29
32
|
{
|
|
30
33
|
"id": "tags",
|
|
31
34
|
"label": "Tags",
|
|
32
|
-
"type": "term(tags)[]"
|
|
35
|
+
"type": "term(tags)[]",
|
|
36
|
+
"description": "Multiple taxonomy term references"
|
|
33
37
|
},
|
|
34
38
|
{
|
|
35
39
|
"id": "featured",
|
|
36
|
-
"label": "Featured",
|
|
37
|
-
"type": "bool"
|
|
40
|
+
"label": "Featured Article",
|
|
41
|
+
"type": "bool",
|
|
42
|
+
"description": "Boolean flag for promoting articles"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"id": "key_points",
|
|
46
|
+
"label": "Key Points",
|
|
47
|
+
"type": "string[]",
|
|
48
|
+
"description": "Multiple string values - best for simple lists without HTML"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"id": "gallery",
|
|
52
|
+
"label": "Image Gallery",
|
|
53
|
+
"type": "image[]",
|
|
54
|
+
"description": "Multiple image uploads"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"id": "content_blocks",
|
|
58
|
+
"label": "Content Blocks",
|
|
59
|
+
"type": "paragraph(content_block)[]",
|
|
60
|
+
"description": "Multiple paragraph entity references for structured content"
|
|
38
61
|
}
|
|
39
62
|
]
|
|
40
63
|
},
|
|
41
64
|
{
|
|
42
65
|
"entity": "paragraph",
|
|
43
|
-
"bundle": "
|
|
44
|
-
"description": "Reusable content blocks
|
|
45
|
-
"label": "
|
|
66
|
+
"bundle": "content_block",
|
|
67
|
+
"description": "Reusable content blocks with images and formatted text",
|
|
68
|
+
"label": "Content Block",
|
|
46
69
|
"fields": [
|
|
47
70
|
{
|
|
48
|
-
"id": "
|
|
49
|
-
"label": "
|
|
50
|
-
"type": "string!"
|
|
71
|
+
"id": "block_title",
|
|
72
|
+
"label": "Block Title",
|
|
73
|
+
"type": "string!",
|
|
74
|
+
"description": "Required field (note the ! suffix)"
|
|
51
75
|
},
|
|
52
76
|
{
|
|
53
|
-
"id": "
|
|
54
|
-
"label": "
|
|
55
|
-
"type": "text"
|
|
77
|
+
"id": "block_content",
|
|
78
|
+
"label": "Block Content",
|
|
79
|
+
"type": "text",
|
|
80
|
+
"description": "Long text with HTML formatting"
|
|
56
81
|
},
|
|
57
82
|
{
|
|
58
|
-
"id": "
|
|
59
|
-
"label": "
|
|
83
|
+
"id": "block_image",
|
|
84
|
+
"label": "Block Image",
|
|
60
85
|
"type": "image"
|
|
61
86
|
}
|
|
62
87
|
]
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"bundle": "product",
|
|
91
|
+
"description": "E-commerce products with pricing, inventory, and specifications",
|
|
92
|
+
"label": "Product",
|
|
93
|
+
"body": true,
|
|
94
|
+
"fields": [
|
|
95
|
+
{
|
|
96
|
+
"id": "price",
|
|
97
|
+
"label": "Price",
|
|
98
|
+
"type": "string",
|
|
99
|
+
"description": "Product price as formatted string (e.g. '$299.99')"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"id": "sku",
|
|
103
|
+
"label": "SKU",
|
|
104
|
+
"type": "string",
|
|
105
|
+
"description": "Product identifier"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"id": "in_stock",
|
|
109
|
+
"label": "In Stock",
|
|
110
|
+
"type": "bool"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"id": "product_images",
|
|
114
|
+
"label": "Product Images",
|
|
115
|
+
"type": "image[]",
|
|
116
|
+
"description": "Multiple product photos"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"id": "features",
|
|
120
|
+
"label": "Key Features",
|
|
121
|
+
"type": "string[]",
|
|
122
|
+
"description": "List of product features (plain text, no HTML)"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"id": "specifications",
|
|
126
|
+
"label": "Specifications",
|
|
127
|
+
"type": "string[]",
|
|
128
|
+
"description": "Technical specifications"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"id": "category",
|
|
132
|
+
"label": "Product Category",
|
|
133
|
+
"type": "term(product_category)[]"
|
|
134
|
+
}
|
|
135
|
+
]
|
|
63
136
|
}
|
|
64
137
|
],
|
|
65
138
|
"content": [
|
|
66
139
|
{
|
|
67
|
-
"id": "
|
|
68
|
-
"type": "paragraph.
|
|
140
|
+
"id": "block1",
|
|
141
|
+
"type": "paragraph.content_block",
|
|
69
142
|
"values": {
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"uri": "/modules/custom/
|
|
74
|
-
"alt": "
|
|
75
|
-
"title": "
|
|
143
|
+
"block_title": "Introduction",
|
|
144
|
+
"block_content": "<p>This is an <strong>example content block</strong> with formatted text.</p>",
|
|
145
|
+
"block_image": {
|
|
146
|
+
"uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
|
|
147
|
+
"alt": "Content block illustration",
|
|
148
|
+
"title": "Block Image"
|
|
76
149
|
}
|
|
77
150
|
}
|
|
78
151
|
},
|
|
79
152
|
{
|
|
80
|
-
"id": "
|
|
81
|
-
"type": "
|
|
153
|
+
"id": "article1",
|
|
154
|
+
"type": "node.article",
|
|
155
|
+
"path": "/articles/getting-started-with-drupal",
|
|
82
156
|
"values": {
|
|
83
|
-
"
|
|
84
|
-
"
|
|
157
|
+
"title": "Getting Started with Decoupled Drupal",
|
|
158
|
+
"summary": "Learn how to build modern web applications with Drupal as a headless CMS",
|
|
159
|
+
"body": "<p>Decoupled Drupal enables you to use Drupal as a powerful content management backend while building your frontend with modern JavaScript frameworks.</p><p>This architecture provides flexibility, performance, and an excellent developer experience.</p>",
|
|
160
|
+
"published_date": "2024-03-15T09:00:00",
|
|
161
|
+
"author": "Jane Smith",
|
|
162
|
+
"featured": true,
|
|
163
|
+
"key_points": [
|
|
164
|
+
"Use Drupal for content management",
|
|
165
|
+
"Build frontend with Next.js, React, or Vue",
|
|
166
|
+
"Connect via GraphQL or REST API",
|
|
167
|
+
"Deploy frontend and backend independently"
|
|
168
|
+
],
|
|
169
|
+
"featured_image": {
|
|
170
|
+
"uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
|
|
171
|
+
"alt": "Decoupled Drupal architecture diagram",
|
|
172
|
+
"title": "Architecture Overview"
|
|
173
|
+
},
|
|
174
|
+
"gallery": [
|
|
175
|
+
{
|
|
176
|
+
"uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
|
|
177
|
+
"alt": "Screenshot of content management interface",
|
|
178
|
+
"title": "CMS Interface"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
|
|
182
|
+
"alt": "Frontend application example",
|
|
183
|
+
"title": "Frontend App"
|
|
184
|
+
}
|
|
185
|
+
],
|
|
186
|
+
"tags": [
|
|
187
|
+
"drupal",
|
|
188
|
+
"headless-cms",
|
|
189
|
+
"web-development"
|
|
190
|
+
],
|
|
191
|
+
"content_blocks": [
|
|
192
|
+
"@block1"
|
|
193
|
+
]
|
|
85
194
|
}
|
|
86
195
|
},
|
|
87
196
|
{
|
|
88
|
-
"id": "
|
|
89
|
-
"type": "node.
|
|
90
|
-
"path": "/
|
|
197
|
+
"id": "product1",
|
|
198
|
+
"type": "node.product",
|
|
199
|
+
"path": "/products/wireless-charger-pro",
|
|
91
200
|
"values": {
|
|
92
|
-
"title": "
|
|
93
|
-
"body": "<p>
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
"
|
|
103
|
-
"conference",
|
|
104
|
-
"technology"
|
|
201
|
+
"title": "Wireless Charger Pro",
|
|
202
|
+
"body": "<p>Experience the future of charging with our premium wireless charging pad. Sleek design meets powerful performance.</p>",
|
|
203
|
+
"price": "$79.99",
|
|
204
|
+
"sku": "WCP-2024-BLK",
|
|
205
|
+
"in_stock": true,
|
|
206
|
+
"features": [
|
|
207
|
+
"Fast 15W wireless charging",
|
|
208
|
+
"Qi-compatible with all devices",
|
|
209
|
+
"Non-slip rubberized surface",
|
|
210
|
+
"LED charging indicator",
|
|
211
|
+
"Overheat protection"
|
|
105
212
|
],
|
|
106
|
-
"
|
|
107
|
-
|
|
108
|
-
"
|
|
109
|
-
"
|
|
213
|
+
"specifications": [
|
|
214
|
+
"Input: USB-C 5V/3A",
|
|
215
|
+
"Output: 15W max",
|
|
216
|
+
"Size: 4 x 4 x 0.5 inches",
|
|
217
|
+
"Weight: 3.2 oz",
|
|
218
|
+
"Color: Matte Black"
|
|
219
|
+
],
|
|
220
|
+
"product_images": [
|
|
221
|
+
{
|
|
222
|
+
"uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
|
|
223
|
+
"alt": "Wireless Charger Pro front view",
|
|
224
|
+
"title": "Product Front"
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
|
|
228
|
+
"alt": "Wireless Charger Pro with phone charging",
|
|
229
|
+
"title": "In Use"
|
|
230
|
+
}
|
|
231
|
+
],
|
|
232
|
+
"category": [
|
|
233
|
+
"electronics",
|
|
234
|
+
"accessories"
|
|
110
235
|
]
|
|
111
236
|
}
|
|
112
237
|
}
|
|
113
|
-
]
|
|
238
|
+
],
|
|
239
|
+
"_comments": {
|
|
240
|
+
"field_types": {
|
|
241
|
+
"string": "Short text (max 255 chars), plain text only",
|
|
242
|
+
"text": "Long text with HTML formatting support",
|
|
243
|
+
"string[]": "Multiple string values - best for simple lists like features, tags, specifications",
|
|
244
|
+
"text[]": "Multiple text values with HTML - use sparingly, prefer string[] for lists",
|
|
245
|
+
"image": "Single image upload with uri, alt, title properties",
|
|
246
|
+
"image[]": "Multiple image uploads",
|
|
247
|
+
"datetime": "Date and time in ISO 8601 format (YYYY-MM-DDTHH:mm:ss)",
|
|
248
|
+
"bool": "Boolean true/false value",
|
|
249
|
+
"term(vocabulary)[]": "Taxonomy term references, creates/assigns terms automatically",
|
|
250
|
+
"paragraph(bundle)[]": "References to paragraph entities for structured content",
|
|
251
|
+
"string!": "Required field (note the ! suffix)"
|
|
252
|
+
},
|
|
253
|
+
"image_format": {
|
|
254
|
+
"description": "Images require full URLs with Drupal domain, not relative paths",
|
|
255
|
+
"example": {
|
|
256
|
+
"uri": "${DRUPAL_BASE_URL}/modules/custom/dc_import/resources/placeholder.png",
|
|
257
|
+
"alt": "Descriptive alt text for accessibility",
|
|
258
|
+
"title": "Image title"
|
|
259
|
+
},
|
|
260
|
+
"note": "Replace ${DRUPAL_BASE_URL} with actual Drupal URL from .env.local"
|
|
261
|
+
},
|
|
262
|
+
"content_references": {
|
|
263
|
+
"description": "Reference other content items using @id syntax",
|
|
264
|
+
"example": "\"content_blocks\": [\"@block1\", \"@block2\"]",
|
|
265
|
+
"note": "Referenced content must be defined earlier in the content array"
|
|
266
|
+
},
|
|
267
|
+
"field_naming": {
|
|
268
|
+
"important": "In DC import JSON, use field 'id' directly (e.g., 'price'), NOT 'field_price'",
|
|
269
|
+
"note": "Drupal automatically prefixes with 'field_' internally",
|
|
270
|
+
"graphql": "GraphQL field names may transform to camelCase (e.g., in_stock → inStock)"
|
|
271
|
+
},
|
|
272
|
+
"best_practices": [
|
|
273
|
+
"Use string[] for simple lists (features, specifications) - avoids HTML rendering complexity",
|
|
274
|
+
"Use text[] only when you need rich HTML formatting within each list item",
|
|
275
|
+
"Always include sample content for immediate testing",
|
|
276
|
+
"Use descriptive field IDs that are clear and consistent",
|
|
277
|
+
"Include alt text for all images for accessibility",
|
|
278
|
+
"Set body: true to include standard body field",
|
|
279
|
+
"Use path aliases following /content-type/slug pattern"
|
|
280
|
+
],
|
|
281
|
+
"common_patterns": {
|
|
282
|
+
"e-commerce": "price (string), sku (string), in_stock (bool), product_images (image[]), features (string[])",
|
|
283
|
+
"blog": "summary (string), author (string), published_date (datetime), tags (term[]), featured (bool)",
|
|
284
|
+
"events": "event_date (datetime), location (string), registration_url (string), speakers (string[])",
|
|
285
|
+
"team": "position (string), profile_image (image), bio (text), social_links (string[])",
|
|
286
|
+
"portfolio": "project_url (string), technologies (string[]), project_images (image[]), client (string)"
|
|
287
|
+
}
|
|
288
|
+
}
|
|
114
289
|
}
|