create-content-sdk-app 2.0.0-canary.9 → 2.0.2-canary.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/dist/templates/nextjs/CLAUDE.md +6 -170
- package/dist/templates/nextjs/Skills.md +1 -1
- package/dist/templates/nextjs/package.json +2 -2
- package/dist/templates/nextjs/src/Bootstrap.tsx +20 -13
- package/dist/templates/nextjs/src/byoc/index.tsx +1 -1
- package/dist/templates/nextjs/src/components/content-sdk/CdpPageView.tsx +1 -1
- package/dist/templates/nextjs-app-router/.agents/skills/content-sdk-route-configuration/SKILL.md +2 -2
- package/dist/templates/nextjs-app-router/.sitecore/import-map.server.ts +2 -2
- package/dist/templates/nextjs-app-router/AGENTS.md +5 -6
- package/dist/templates/nextjs-app-router/CLAUDE.md +6 -271
- package/dist/templates/nextjs-app-router/README.md +0 -36
- package/dist/templates/nextjs-app-router/Skills.md +1 -1
- package/dist/templates/nextjs-app-router/package.json +3 -2
- package/dist/templates/nextjs-app-router/src/Bootstrap.tsx +20 -12
- package/dist/templates/nextjs-app-router/src/app/[site]/[locale]/[[...path]]/layout.tsx +19 -0
- package/dist/templates/nextjs-app-router/src/app/[site]/[locale]/[[...path]]/not-found.tsx +3 -28
- package/dist/templates/nextjs-app-router/src/app/[site]/[locale]/[[...path]]/page.tsx +6 -21
- package/dist/templates/nextjs-app-router/src/app/[site]/layout.tsx +5 -21
- package/dist/templates/nextjs-app-router/src/app/not-found.tsx +1 -23
- package/dist/templates/nextjs-app-router/src/byoc/index.tsx +1 -1
- package/dist/templates/nextjs-app-router/src/components/content-sdk/CdpPageView.tsx +1 -1
- package/package.json +2 -2
- package/dist/templates/nextjs/LLMs.txt +0 -179
- package/dist/templates/nextjs-app-router/LLMs.txt +0 -236
|
@@ -1,173 +1,9 @@
|
|
|
1
|
-
# Claude Code
|
|
1
|
+
# Claude Code — Sitecore Content SDK Next.js (Pages Router) App
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
At the start of every session, read these files for full project guidance:
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
1. **`AGENTS.md`** — Canonical source of truth for this app: overview, commands, application structure, middleware, SitecoreClient, catch-all route, i18n, DO/DON'T, guardrails, boundaries
|
|
6
|
+
2. **`.cursor/rules/`** — Coding rules for this template: general, javascript, sitecore, project-setup
|
|
7
|
+
3. **`Skills.md`** and **`.agents/skills/`** — Capability-specific guidance (component registration, data fetching, editing, i18n, etc.) for tools that support the [Agent Skills](https://agentskills.io) standard.
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
- **Next.js** - React framework with SSR/SSG capabilities
|
|
9
|
-
- **Sitecore Content SDK** - Official SDK for Sitecore XM Cloud integration
|
|
10
|
-
- **TypeScript** - Type-safe JavaScript development
|
|
11
|
-
- **Sitecore XM Cloud** - Headless CMS platform
|
|
12
|
-
- **React** - Component-based UI library
|
|
13
|
-
|
|
14
|
-
## Coding Standards
|
|
15
|
-
|
|
16
|
-
### TypeScript Standards
|
|
17
|
-
- Use **strict mode** in tsconfig.json
|
|
18
|
-
- Prefer type assertions over `any`: `value as ContentItem`
|
|
19
|
-
- Use discriminated unions for complex state management
|
|
20
|
-
- Enable strict null checks and strict function types
|
|
21
|
-
|
|
22
|
-
### Naming Conventions
|
|
23
|
-
- **Variables/Functions**: camelCase (`getUserData()`, `isLoading`, `currentUser`)
|
|
24
|
-
- **Components**: PascalCase (`SitecoreComponent`, `PageLayout`, `ContentBlock`)
|
|
25
|
-
- **Constants**: UPPER_SNAKE_CASE (`API_ENDPOINT`, `DEFAULT_TIMEOUT`)
|
|
26
|
-
- **Directories**: kebab-case (`src/components`, `src/api-clients`)
|
|
27
|
-
- **Types/Interfaces**: PascalCase (`ContentItem`, `LayoutProps`, `SitecoreConfig`)
|
|
28
|
-
|
|
29
|
-
### Modular Layout
|
|
30
|
-
```
|
|
31
|
-
src/
|
|
32
|
-
components/ # UI components (React)
|
|
33
|
-
lib/ # Configuration and utilities
|
|
34
|
-
pages/ # Next.js pages
|
|
35
|
-
assets/ # Static assets and styles
|
|
36
|
-
types/ # TypeScript type definitions
|
|
37
|
-
hooks/ # Custom React hooks
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
## Library Usage
|
|
41
|
-
|
|
42
|
-
### @sitecore-content-sdk
|
|
43
|
-
- Use `SitecoreClient` for content fetching
|
|
44
|
-
- Implement proper error handling with try/catch blocks
|
|
45
|
-
- Cache API responses using React Query or SWR
|
|
46
|
-
- Handle content preview vs. published content scenarios
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
import { SitecoreClient } from '@sitecore-content-sdk/nextjs/client';
|
|
50
|
-
import scConfig from 'sitecore.config';
|
|
51
|
-
|
|
52
|
-
const client = new SitecoreClient({
|
|
53
|
-
...scConfig,
|
|
54
|
-
});
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### React Patterns
|
|
58
|
-
- Use **Server Components** for data fetching and static content
|
|
59
|
-
- Use **Client Components** for interactivity (use 'use client')
|
|
60
|
-
- Implement proper error boundaries
|
|
61
|
-
- Use React.memo for expensive components
|
|
62
|
-
- Leverage useCallback and useMemo for performance optimization
|
|
63
|
-
|
|
64
|
-
### Sitecore Field Components
|
|
65
|
-
- Always use Sitecore field components: `<Text>`, `<RichText>`, `<Image>`
|
|
66
|
-
- Validate field existence before rendering
|
|
67
|
-
- Handle empty/null fields gracefully
|
|
68
|
-
- Prefer Sitecore field components over manual rendering
|
|
69
|
-
|
|
70
|
-
```typescript
|
|
71
|
-
// Good: Using Sitecore field components
|
|
72
|
-
<Text field={fields?.title} tag="h1" />
|
|
73
|
-
<RichText field={fields?.content} />
|
|
74
|
-
<Image field={fields?.backgroundImage} />
|
|
75
|
-
|
|
76
|
-
// Avoid: Manual field value extraction unless necessary
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Example Patterns and Prompts
|
|
80
|
-
|
|
81
|
-
### Component Development
|
|
82
|
-
```typescript
|
|
83
|
-
// Component props interface
|
|
84
|
-
interface HeroProps {
|
|
85
|
-
fields: {
|
|
86
|
-
title: Field;
|
|
87
|
-
subtitle: Field;
|
|
88
|
-
backgroundImage: Field;
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export default function Hero({ fields }: HeroProps) {
|
|
93
|
-
return (
|
|
94
|
-
<div>
|
|
95
|
-
<Text field={fields?.title} tag="h1" />
|
|
96
|
-
<Text field={fields?.subtitle} tag="p" />
|
|
97
|
-
<Image field={fields?.backgroundImage} />
|
|
98
|
-
</div>
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### Error Handling
|
|
104
|
-
```typescript
|
|
105
|
-
async function fetchPageData(path: string): Promise<Page | null> {
|
|
106
|
-
if (!path) {
|
|
107
|
-
throw new Error('Page path is required');
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
try {
|
|
111
|
-
const pageData = await client.getPage(path);
|
|
112
|
-
return pageData;
|
|
113
|
-
} catch (error) {
|
|
114
|
-
throw new SitecoreFetchError(`Failed to fetch page data for ${path}`, error);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
### Configuration
|
|
120
|
-
```typescript
|
|
121
|
-
// sitecore.config.ts
|
|
122
|
-
import { defineConfig } from '@sitecore-content-sdk/nextjs/config';
|
|
123
|
-
|
|
124
|
-
export default defineConfig({
|
|
125
|
-
api: {
|
|
126
|
-
edge: {
|
|
127
|
-
contextId: process.env.SITECORE_EDGE_CONTEXT_ID || '',
|
|
128
|
-
clientContextId: process.env.NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID,
|
|
129
|
-
edgeUrl:
|
|
130
|
-
process.env.NEXT_PUBLIC_SITECORE_EDGE_PLATFORM_HOSTNAME ||
|
|
131
|
-
process.env.SITECORE_EDGE_PLATFORM_HOSTNAME ||
|
|
132
|
-
'https://edge-platform.sitecorecloud.io',
|
|
133
|
-
},
|
|
134
|
-
local: {
|
|
135
|
-
apiKey: process.env.SITECORE_API_KEY || '',
|
|
136
|
-
apiHost: process.env.SITECORE_API_HOST || '',
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
defaultSite: process.env.NEXT_PUBLIC_DEFAULT_SITE_NAME || 'default',
|
|
140
|
-
defaultLanguage: process.env.NEXT_PUBLIC_DEFAULT_LANGUAGE || 'en',
|
|
141
|
-
editingSecret: process.env.SITECORE_EDITING_SECRET,
|
|
142
|
-
});
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
## Development Workflow
|
|
146
|
-
|
|
147
|
-
1. **Install dependencies**: `npm install`
|
|
148
|
-
2. **Configure environment**: Copy `.env.example` to `.env.local`
|
|
149
|
-
3. **Start development**: `npm run dev`
|
|
150
|
-
4. **Build for production**: `npm run build`
|
|
151
|
-
|
|
152
|
-
## Best Practices
|
|
153
|
-
|
|
154
|
-
### Performance
|
|
155
|
-
- Optimize images using Next.js Image component
|
|
156
|
-
- Implement proper loading states
|
|
157
|
-
- Cache expensive operations appropriately
|
|
158
|
-
- Consider server-side rendering implications
|
|
159
|
-
- Lazy-load non-critical modules
|
|
160
|
-
|
|
161
|
-
### Security
|
|
162
|
-
- Sanitize user inputs before processing
|
|
163
|
-
- Validate data at application boundaries
|
|
164
|
-
- Use HTTPS for all Sitecore connections
|
|
165
|
-
- Never expose sensitive configuration in client-side code
|
|
166
|
-
- Escape content when rendering to prevent XSS
|
|
167
|
-
|
|
168
|
-
### Code Quality
|
|
169
|
-
- Follow DRY principle - extract common functionality
|
|
170
|
-
- Use SOLID principles for maintainable code
|
|
171
|
-
- Write self-documenting code with clear intent
|
|
172
|
-
- Implement proper error boundaries
|
|
173
|
-
- Test behavior, not implementation details
|
|
9
|
+
This file applies to **this scaffolded head application only**. For the Content SDK monorepo (packages, CLI, templates source), use that repo's root `AGENTS.md` and `.cursor/rules/`.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
This file describes **this application** in terms of **capability-style groupings**: high-level areas that help AI tools and developers map tasks to the right part of the app. This is a Pages Router app with `pages/[[...path]].tsx`, Next.js i18n, and a single component map. For concrete steps and patterns, see [AGENTS.md](AGENTS.md) and the [official Content SDK documentation](https://doc.sitecore.com/xmc/en/developers/content-sdk/sitecore-content-sdk-for-xm-cloud.html).
|
|
4
4
|
|
|
5
|
-
**Agent Skills:** Each grouping is also available as a skill in [.agents/skills/](.agents/skills/) in the standard [Agent Skills](https://agentskills.io) format (`SKILL.md` per capability). Tools that support this standard
|
|
5
|
+
**Agent Skills:** Each grouping is also available as a skill in [.agents/skills/](.agents/skills/) in the standard [Agent Skills](https://agentskills.io) format (`SKILL.md` per capability). Tools that support this standard load skills from `.agents/skills/`; Cursor's built-in skills use `.cursor/skills/` unless it also supports the Agent Skills standard. The skills here are tailored for **Pages Router** (e.g. extractPath, context.locale, getComponentData, single component-map.ts).
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
},
|
|
23
23
|
"license": "Apache-2.0",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@sitecore-cloudsdk/core": "^0.5.1",
|
|
26
|
-
"@sitecore-cloudsdk/events": "^0.5.1",
|
|
27
25
|
"@sitecore-content-sdk/nextjs": "<%- version %>",
|
|
26
|
+
"@sitecore-content-sdk/analytics-core": "<%- version %>",
|
|
27
|
+
"@sitecore-content-sdk/events": "<%- version %>",
|
|
28
28
|
"@sitecore-feaas/clientside": "^0.6.0",
|
|
29
29
|
"@sitecore/components": "~2.1.0",
|
|
30
30
|
"next": "^16.1.1",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useEffect, JSX } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { SitecorePageProps } from '@sitecore-content-sdk/nextjs';
|
|
4
|
-
import '@sitecore-cloudsdk/events/browser';
|
|
2
|
+
import { SitecorePageProps, initContentSdk } from '@sitecore-content-sdk/nextjs';
|
|
5
3
|
import config from 'sitecore.config';
|
|
4
|
+
import { eventsPlugin } from '@sitecore-content-sdk/events';
|
|
5
|
+
import { analyticsBrowserAdapter, analyticsPlugin } from '@sitecore-content-sdk/analytics-core';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* The Bootstrap component is the entry point for performing any initialization logic
|
|
@@ -26,16 +26,23 @@ const Bootstrap = (props: SitecorePageProps): JSX.Element | null => {
|
|
|
26
26
|
console.debug('Browser Events SDK is not initialized in edit and preview modes');
|
|
27
27
|
} else {
|
|
28
28
|
if (config.api.edge?.clientContextId) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
29
|
+
initContentSdk({
|
|
30
|
+
config: {
|
|
31
|
+
contextId: config.api.edge.clientContextId,
|
|
32
|
+
edgeUrl: config.api.edge.edgeUrl,
|
|
33
|
+
siteName: page.siteName || config.defaultSite,
|
|
34
|
+
},
|
|
35
|
+
plugins: [
|
|
36
|
+
analyticsPlugin({
|
|
37
|
+
options: {
|
|
38
|
+
enableCookie: true,
|
|
39
|
+
cookieDomain: window.location.hostname.replace(/^www\./, ''),
|
|
40
|
+
},
|
|
41
|
+
adapter: analyticsBrowserAdapter(),
|
|
42
|
+
}),
|
|
43
|
+
eventsPlugin(),
|
|
44
|
+
],
|
|
45
|
+
});
|
|
39
46
|
} else {
|
|
40
47
|
console.error('Client Edge API settings missing from configuration');
|
|
41
48
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { JSX } from 'react';
|
|
2
2
|
import * as FEAAS from '@sitecore-feaas/clientside/react';
|
|
3
|
-
import * as Events from '@sitecore-
|
|
3
|
+
import * as Events from '@sitecore-content-sdk/events';
|
|
4
4
|
import { LayoutServicePageState, SitecoreProviderReactContext } from '@sitecore-content-sdk/nextjs';
|
|
5
5
|
import '@sitecore/components/context';
|
|
6
6
|
import dynamic from 'next/dynamic';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CdpHelper, useSitecore } from '@sitecore-content-sdk/nextjs';
|
|
2
2
|
import { useEffect, JSX } from 'react';
|
|
3
|
-
import { pageView } from '@sitecore-
|
|
3
|
+
import { pageView } from '@sitecore-content-sdk/events';
|
|
4
4
|
import config from 'sitecore.config';
|
|
5
5
|
|
|
6
6
|
/**
|
package/dist/templates/nextjs-app-router/.agents/skills/content-sdk-route-configuration/SKILL.md
CHANGED
|
@@ -15,7 +15,7 @@ Single catch-all route and layout hierarchy. Site and locale are **in the path**
|
|
|
15
15
|
|
|
16
16
|
## How to perform
|
|
17
17
|
|
|
18
|
-
- Single Sitecore page: `src/app/[site]/[locale]/[[...path]]/page.tsx`. Use `await params` for `{ site, locale, path? }`; pass to getPage and call `setRequestLocale(\`${site}_${locale}\`)` at the top. Layout: app/layout.tsx → app/[site]/layout.tsx (Bootstrap, draftMode) → page. Not-found: use
|
|
18
|
+
- Single Sitecore page: `src/app/[site]/[locale]/[[...path]]/page.tsx`. Use `await params` for `{ site, locale, path? }`; pass to getPage and call `setRequestLocale(\`${site}_${locale}\`)` at the top. Layout: app/layout.tsx → app/[site]/layout.tsx (Bootstrap, draftMode) → page. Not-found: use getCachedPageParams and getErrorPage in the route's not-found.tsx.
|
|
19
19
|
|
|
20
20
|
## Hard Rules
|
|
21
21
|
|
|
@@ -24,7 +24,7 @@ Single catch-all route and layout hierarchy. Site and locale are **in the path**
|
|
|
24
24
|
- **Locale for next-intl:** Call `setRequestLocale(\`${site}_${locale}\`)` at the **top** of the page so next-intl and `src/i18n/request.ts` see the correct locale. Do not omit when adding new page branches.
|
|
25
25
|
- **Layout hierarchy:** `app/layout.tsx` → `app/[site]/layout.tsx` (Bootstrap with `siteName={site}` and `draftMode()`) → page. Do not put site/locale-specific data fetching in the root layout.
|
|
26
26
|
- Placeholders are rendered by the layout (e.g. Placeholder component); do not change placeholder names or structure without aligning with Sitecore layout definition.
|
|
27
|
-
- **Not-found:** `src/app/[site]/[locale]/[[...path]]/not-found.tsx`. For Sitecore-driven 404 use `
|
|
27
|
+
- **Not-found:** `src/app/[site]/[locale]/[[...path]]/not-found.tsx`. For Sitecore-driven 404 use `getCachedPageParams()` from `@sitecore-content-sdk/nextjs` for site/locale, then `client.getErrorPage(ErrorPage.NotFound, { site, locale })`.
|
|
28
28
|
|
|
29
29
|
## Stop Conditions
|
|
30
30
|
|
|
@@ -16,7 +16,7 @@ import { Suspense } from 'react';
|
|
|
16
16
|
import React from 'react';
|
|
17
17
|
import { componentMap } from '.sitecore/component-map';
|
|
18
18
|
import client from 'src/lib/sitecore-client';
|
|
19
|
-
import { pageView } from '@sitecore-
|
|
19
|
+
import { pageView } from '@sitecore-content-sdk/events';
|
|
20
20
|
import config from 'sitecore.config';
|
|
21
21
|
|
|
22
22
|
const importMapServer = [
|
|
@@ -48,7 +48,7 @@ const importMapServer = [
|
|
|
48
48
|
exports: [{ name: 'default', value: client }],
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
|
-
module: '@sitecore-
|
|
51
|
+
module: '@sitecore-content-sdk/events',
|
|
52
52
|
exports: [{ name: 'pageView', value: pageView }],
|
|
53
53
|
},
|
|
54
54
|
{
|
|
@@ -120,15 +120,14 @@ These are the main head-app–specific concepts. Details are in the sections bel
|
|
|
120
120
|
- **SSG:** `generateStaticParams` — use `client.getAppRouterStaticParams(sites, routing.locales)` (sites from `.sitecore/sites.json`). Return at least one default param when not generating full paths (e.g. dev or when `generateStaticPaths` is off).
|
|
121
121
|
- **Metadata:** `generateMetadata` in the same segment can call `client.getPage(path ?? [], { site, locale })` and derive `title` (e.g. from route fields). Next.js will cache as appropriate.
|
|
122
122
|
|
|
123
|
-
### Server vs Client components
|
|
123
|
+
### Server vs Client components
|
|
124
124
|
|
|
125
125
|
- **Default:** Components are Server Components. Use `'use client'` only for interactivity (e.g. hooks, event handlers).
|
|
126
|
-
- **PPR (Partial Prerendering):** Dynamic work (e.g. `draftMode()`, data fetching) is wrapped in `<Suspense>` (e.g. `DynamicPageContent`, `DynamicLayoutContent`, `DynamicNotFoundContent`). Keep the same pattern when adding new dynamic branches so PPR and caching behave correctly.
|
|
127
126
|
- **draftMode:** Used in layout and page; call `await draftMode()` in Server Components that need to know preview state.
|
|
128
127
|
|
|
129
128
|
### Not-found and error page
|
|
130
129
|
|
|
131
|
-
- **Segment not-found:** `src/app/[site]/[locale]/[[...path]]/not-found.tsx`.
|
|
130
|
+
- **Segment not-found:** `src/app/[site]/[locale]/[[...path]]/not-found.tsx`. Uses `getCachedPageParams()` from `@sitecore-content-sdk/nextjs` for site/locale, then `client.getErrorPage(ErrorPage.NotFound, { site, locale })` and renders layout if a page is returned.
|
|
132
131
|
- **Root not-found:** `src/app/not-found.tsx` — minimal fallback when no segment handles the route.
|
|
133
132
|
|
|
134
133
|
### API route handlers
|
|
@@ -154,7 +153,7 @@ These are the main head-app–specific concepts. Details are in the sections bel
|
|
|
154
153
|
|
|
155
154
|
- **Quick checks:** If locale or dictionary is wrong, ensure `setRequestLocale(\`${site}_${locale}\`)` is called at the top of the page and `src/i18n/request.ts` parses `requestLocale` and calls `client.getDictionary`. If not-found doesn't show Sitecore content, use `parseRewriteHeader(headers())` for site/locale. Always `await params` (Next.js 15+).
|
|
156
155
|
- **Security:** Use only environment variables in `sitecore.config.ts`; never hardcode API keys, editing secret, or host URLs. Do not expose secrets in client-side code or in logs. Validate and sanitize user input at boundaries.
|
|
157
|
-
- **Performance:** Keep middleware lightweight; use the proxy `matcher` so it does not run on API routes, `_next`, sitemap, robots, or static assets. Use Server Components
|
|
156
|
+
- **Performance:** Keep middleware lightweight; use the proxy `matcher` so it does not run on API routes, `_next`, sitemap, robots, or static assets. Use Server Components for data fetching; add `'use client'` only where interactivity is needed. Use `generateStaticParams` and caching as in the existing page.
|
|
158
157
|
- **Sitecore patterns:** Use SDK field components (`<Text>`, `<RichText>`, `<Image>`) and validate field existence before render. Register new components in `.sitecore/component-map.ts` and `.sitecore/component-map.client.ts` as appropriate. Use the single Sitecore client in `lib/sitecore-client.ts` for all data fetching.
|
|
159
158
|
- **Consistency:** Follow the existing patterns in `[site]/[locale]/[[...path]]/page.tsx`, layout hierarchy, `i18n/request.ts` (site_locale), and API route handlers. When adding routes or rewrites, keep the middleware matcher and next-intl config in sync.
|
|
160
159
|
|
|
@@ -168,7 +167,7 @@ These are the main head-app–specific concepts. Details are in the sections bel
|
|
|
168
167
|
| Pass `{ site, locale }` to `client.getPage` and `getDictionary` | Assume site/locale from headers inside page without using params |
|
|
169
168
|
| Run LocaleProxy before AppRouterMultisiteProxy in middleware | Change proxy order (locale must run first for i18n) |
|
|
170
169
|
| Call `setRequestLocale(\`${site}_${locale}\`)` in the page for next-intl | Omit setRequestLocale when adding new page branches |
|
|
171
|
-
| Use
|
|
170
|
+
| Use Server Components for async data fetching | Put async data fetching in client components when SSR is intended |
|
|
172
171
|
| Use `parseRewriteHeader(headers())` in not-found for site/locale | Hardcode site/locale in not-found or error pages |
|
|
173
172
|
| Use createXRouteHandler and `.sitecore/sites.json` for sitemap/robots | Hardcode site list or commit `.env` |
|
|
174
173
|
| Use Sitecore field components and validate fields | Expose API keys or editing secret in client code |
|
|
@@ -179,7 +178,7 @@ These are the main head-app–specific concepts. Details are in the sections bel
|
|
|
179
178
|
|
|
180
179
|
## Guardrails for agentic AI
|
|
181
180
|
|
|
182
|
-
- **Preserve behavior:** Do not change the proxy order (LocaleProxy → AppRouterMultisiteProxy → …), the `[site]/[locale]/[[...path]]` route shape, or the way `setRequestLocale` and `i18n/request.ts` use `{site}_{locale}`. Preserve
|
|
181
|
+
- **Preserve behavior:** Do not change the proxy order (LocaleProxy → AppRouterMultisiteProxy → …), the `[site]/[locale]/[[...path]]` route shape, or the way `setRequestLocale` and `i18n/request.ts` use `{site}_{locale}`. Preserve draftMode handling in layout and page.
|
|
183
182
|
- **Do not expand scope:** Limit edits to the app (app router, components, API routes, i18n, config). Do not modify SDK packages or monorepo tooling unless explicitly asked. Do not change CI, lockfiles, or root config.
|
|
184
183
|
- **Follow existing patterns:** When adding routes, layouts, or components, mirror the existing structure. Use the same Sitecore client, component maps, and env-based config. Do not introduce a different way to resolve site/locale or a second client without clear need.
|
|
185
184
|
- **Verify and stay safe:** After edits, the app should build with `npm run build`. Do not commit secrets or `.env`; only document variables in `.env.example`. Do not add npm dependencies without explicit approval. When in doubt, prefer the existing implementation and ask for clarification.
|
|
@@ -1,274 +1,9 @@
|
|
|
1
|
-
# Claude Code
|
|
1
|
+
# Claude Code — Sitecore Content SDK Next.js (App Router) App
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
At the start of every session, read these files for full project guidance:
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
1. **`AGENTS.md`** — Canonical source of truth for this app: overview, commands, App Router structure, middleware, SitecoreClient, [site]/[locale]/[[...path]], next-intl, DO/DON'T, guardrails, boundaries
|
|
6
|
+
2. **`.cursor/rules/`** — Coding rules for this template: general, javascript, sitecore, app-router-setup
|
|
7
|
+
3. **`Skills.md`** and **`.agents/skills/`** — Capability-specific guidance (component registration, data fetching, editing, i18n, etc.) for tools that support the [Agent Skills](https://agentskills.io) standard.
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
- **Next.js App Router** - React framework with Server Components and modern routing
|
|
9
|
-
- **Sitecore Content SDK** - Official SDK for Sitecore XM Cloud integration
|
|
10
|
-
- **TypeScript** - Type-safe JavaScript development
|
|
11
|
-
- **Sitecore XM Cloud** - Headless CMS platform
|
|
12
|
-
- **React Server Components** - Server-side rendering for better performance
|
|
13
|
-
- **next-intl** - Internationalization support
|
|
14
|
-
|
|
15
|
-
## Coding Standards
|
|
16
|
-
|
|
17
|
-
### TypeScript Standards
|
|
18
|
-
- Use **strict mode** in tsconfig.json
|
|
19
|
-
- Prefer type assertions over `any`: `value as ContentItem`
|
|
20
|
-
- Use discriminated unions for complex state management
|
|
21
|
-
- Enable strict null checks and strict function types
|
|
22
|
-
|
|
23
|
-
### Naming Conventions
|
|
24
|
-
- **Variables/Functions**: camelCase (`getUserData()`, `isLoading`, `currentUser`)
|
|
25
|
-
- **Components**: PascalCase (`SitecoreComponent`, `PageLayout`, `ContentBlock`)
|
|
26
|
-
- **Constants**: UPPER_SNAKE_CASE (`API_ENDPOINT`, `DEFAULT_TIMEOUT`)
|
|
27
|
-
- **Directories**: kebab-case (`src/components`, `src/api-clients`)
|
|
28
|
-
- **Types/Interfaces**: PascalCase (`ContentItem`, `LayoutProps`, `SitecoreConfig`)
|
|
29
|
-
|
|
30
|
-
### Modular Layout (App Router)
|
|
31
|
-
```
|
|
32
|
-
src/
|
|
33
|
-
app/ # App Router pages and layouts
|
|
34
|
-
components/ # UI components (React)
|
|
35
|
-
lib/ # Configuration and utilities
|
|
36
|
-
i18n/ # Internationalization setup
|
|
37
|
-
types/ # TypeScript type definitions
|
|
38
|
-
hooks/ # Custom React hooks
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Library Usage
|
|
42
|
-
|
|
43
|
-
### @sitecore-content-sdk
|
|
44
|
-
- Use `SitecoreClient` for content fetching
|
|
45
|
-
- Implement proper error handling with try/catch blocks
|
|
46
|
-
- Cache API responses using React Query or SWR
|
|
47
|
-
- Handle content preview vs. published content scenarios
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
import { SitecoreClient } from '@sitecore-content-sdk/nextjs/client';
|
|
51
|
-
import scConfig from 'sitecore.config';
|
|
52
|
-
|
|
53
|
-
const client = new SitecoreClient({
|
|
54
|
-
...scConfig,
|
|
55
|
-
});
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### React App Router Patterns
|
|
59
|
-
- Use **Server Components** for data fetching and static content (default)
|
|
60
|
-
- Use **Client Components** for interactivity (use 'use client' directive)
|
|
61
|
-
- Implement proper error boundaries with error.tsx
|
|
62
|
-
- Use loading.tsx for loading states
|
|
63
|
-
- Leverage layout.tsx for shared page structure
|
|
64
|
-
|
|
65
|
-
### Sitecore Field Components
|
|
66
|
-
- Always use Sitecore field components: `<Text>`, `<RichText>`, `<Image>`
|
|
67
|
-
- Validate field existence before rendering
|
|
68
|
-
- Handle empty/null fields gracefully
|
|
69
|
-
- Prefer Sitecore field components over manual rendering
|
|
70
|
-
|
|
71
|
-
```typescript
|
|
72
|
-
// Good: Using Sitecore field components
|
|
73
|
-
<Text field={fields?.title} tag="h1" />
|
|
74
|
-
<RichText field={fields?.content} />
|
|
75
|
-
<Image field={fields?.backgroundImage} />
|
|
76
|
-
|
|
77
|
-
// Avoid: Manual field value extraction unless necessary
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## Example Patterns and Prompts
|
|
81
|
-
|
|
82
|
-
### Server Component Development
|
|
83
|
-
```typescript
|
|
84
|
-
// Server Component example (default in App Router)
|
|
85
|
-
import { SitecoreClient } from '@sitecore-content-sdk/nextjs/client';
|
|
86
|
-
import scConfig from 'sitecore.config';
|
|
87
|
-
|
|
88
|
-
const client = new SitecoreClient({
|
|
89
|
-
...scConfig,
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
export default async function SitecorePage({ params }: { params: { path: string[] } }) {
|
|
93
|
-
try {
|
|
94
|
-
const pageData = await client.getPage(params.path.join('/'));
|
|
95
|
-
return <SitecoreLayout layoutData={pageData?.layout} />;
|
|
96
|
-
} catch (error) {
|
|
97
|
-
return <div>Content not found</div>;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### Client Component Integration
|
|
103
|
-
|
|
104
|
-
Interactive Sitecore Components:
|
|
105
|
-
|
|
106
|
-
- Use 'use client' directive when needed
|
|
107
|
-
- Keep client components focused on interactivity
|
|
108
|
-
- Pass server-fetched data as props
|
|
109
|
-
- Handle hydration mismatches carefully
|
|
110
|
-
|
|
111
|
-
```typescript
|
|
112
|
-
'use client';
|
|
113
|
-
|
|
114
|
-
interface InteractiveSitecoreComponentProps {
|
|
115
|
-
fields: {
|
|
116
|
-
title: Field;
|
|
117
|
-
content: Field;
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export default function InteractiveSitecoreComponent({
|
|
122
|
-
fields,
|
|
123
|
-
}: InteractiveSitecoreComponentProps) {
|
|
124
|
-
// Client-side interactivity here
|
|
125
|
-
return (
|
|
126
|
-
<div>
|
|
127
|
-
<Text field={fields?.title} tag="h2" />
|
|
128
|
-
<RichText field={fields?.content} />
|
|
129
|
-
</div>
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### Component Development
|
|
135
|
-
```typescript
|
|
136
|
-
// Component props interface
|
|
137
|
-
interface HeroProps {
|
|
138
|
-
fields: {
|
|
139
|
-
title: Field;
|
|
140
|
-
subtitle: Field;
|
|
141
|
-
backgroundImage: Field;
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export default function Hero({ fields }: HeroProps) {
|
|
146
|
-
return (
|
|
147
|
-
<div>
|
|
148
|
-
<Text field={fields?.title} tag="h1" />
|
|
149
|
-
<Text field={fields?.subtitle} tag="p" />
|
|
150
|
-
<Image field={fields?.backgroundImage} />
|
|
151
|
-
</div>
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### Error Handling
|
|
157
|
-
|
|
158
|
-
API Calls:
|
|
159
|
-
|
|
160
|
-
- Always wrap in try/catch blocks
|
|
161
|
-
- Throw custom errors with context: `SitecoreFetchError`, `ConfigurationError`
|
|
162
|
-
- Handle edge cases with guard clauses
|
|
163
|
-
|
|
164
|
-
```typescript
|
|
165
|
-
async function fetchPageData(path: string): Promise<Page | null> {
|
|
166
|
-
if (!path) {
|
|
167
|
-
throw new Error('Page path is required');
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
try {
|
|
171
|
-
const pageData = await client.getPage(path);
|
|
172
|
-
return pageData;
|
|
173
|
-
} catch (error) {
|
|
174
|
-
throw new SitecoreFetchError(`Failed to fetch page data for ${path}`, error);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
### Configuration
|
|
180
|
-
```typescript
|
|
181
|
-
// sitecore.config.ts
|
|
182
|
-
import { defineConfig } from '@sitecore-content-sdk/nextjs/config';
|
|
183
|
-
|
|
184
|
-
export default defineConfig({
|
|
185
|
-
api: {
|
|
186
|
-
edge: {
|
|
187
|
-
contextId: process.env.SITECORE_EDGE_CONTEXT_ID || '',
|
|
188
|
-
clientContextId: process.env.NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID,
|
|
189
|
-
edgeUrl:
|
|
190
|
-
process.env.NEXT_PUBLIC_SITECORE_EDGE_PLATFORM_HOSTNAME ||
|
|
191
|
-
process.env.SITECORE_EDGE_PLATFORM_HOSTNAME ||
|
|
192
|
-
'https://edge-platform.sitecorecloud.io',
|
|
193
|
-
},
|
|
194
|
-
local: {
|
|
195
|
-
apiKey: process.env.SITECORE_API_KEY || '',
|
|
196
|
-
apiHost: process.env.SITECORE_API_HOST || '',
|
|
197
|
-
},
|
|
198
|
-
},
|
|
199
|
-
defaultSite: process.env.NEXT_PUBLIC_DEFAULT_SITE_NAME || 'default',
|
|
200
|
-
defaultLanguage: process.env.NEXT_PUBLIC_DEFAULT_LANGUAGE || 'en',
|
|
201
|
-
editingSecret: process.env.SITECORE_EDITING_SECRET,
|
|
202
|
-
});
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
### Internationalization
|
|
206
|
-
|
|
207
|
-
Multi-language Support:
|
|
208
|
-
|
|
209
|
-
- Configure next-intl for language routing
|
|
210
|
-
- Handle Sitecore language contexts
|
|
211
|
-
- Implement language switching
|
|
212
|
-
- Use proper locale-based data fetching
|
|
213
|
-
|
|
214
|
-
```typescript
|
|
215
|
-
// Language-aware data fetching
|
|
216
|
-
import { getTranslations } from 'next-intl/server';
|
|
217
|
-
|
|
218
|
-
export default async function LocalizedPage() {
|
|
219
|
-
const t = await getTranslations('common');
|
|
220
|
-
// Fetch Sitecore content for current locale
|
|
221
|
-
}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
## Development Workflow
|
|
225
|
-
|
|
226
|
-
1. **Install dependencies**: `npm install`
|
|
227
|
-
2. **Configure environment**: Copy `.env.example` to `.env.local`
|
|
228
|
-
3. **Start development**: `npm run dev`
|
|
229
|
-
4. **Build for production**: `npm run build`
|
|
230
|
-
|
|
231
|
-
## App Router Best Practices
|
|
232
|
-
|
|
233
|
-
### Server vs Client Components
|
|
234
|
-
- Use Server Components for Sitecore content rendering (default)
|
|
235
|
-
- Use Client Components for user interactions
|
|
236
|
-
- Minimize client-side JavaScript
|
|
237
|
-
- Leverage server-side data fetching
|
|
238
|
-
|
|
239
|
-
### Routing and Layouts
|
|
240
|
-
- Use layout.tsx for shared page structure
|
|
241
|
-
- Implement loading.tsx for loading states
|
|
242
|
-
- Create error.tsx for error boundaries
|
|
243
|
-
- Use page.tsx for route content
|
|
244
|
-
- Use [...path] for Sitecore catch-all routes
|
|
245
|
-
|
|
246
|
-
### Performance Optimization
|
|
247
|
-
- Leverage Server Components for better performance
|
|
248
|
-
- Use streaming for improved loading experience
|
|
249
|
-
- Implement proper caching strategies
|
|
250
|
-
- Optimize images with Next.js Image component
|
|
251
|
-
|
|
252
|
-
## Best Practices
|
|
253
|
-
|
|
254
|
-
### Performance
|
|
255
|
-
- Optimize images using Next.js Image component
|
|
256
|
-
- Implement proper loading states
|
|
257
|
-
- Cache expensive operations appropriately
|
|
258
|
-
- Consider server-side rendering implications
|
|
259
|
-
- Lazy-load non-critical modules
|
|
260
|
-
- Use Server Components for better performance
|
|
261
|
-
|
|
262
|
-
### Security
|
|
263
|
-
- Sanitize user inputs before processing
|
|
264
|
-
- Validate data at application boundaries
|
|
265
|
-
- Use HTTPS for all Sitecore connections
|
|
266
|
-
- Never expose sensitive configuration in client-side code
|
|
267
|
-
- Escape content when rendering to prevent XSS
|
|
268
|
-
|
|
269
|
-
### Code Quality
|
|
270
|
-
- Follow DRY principle - extract common functionality
|
|
271
|
-
- Use SOLID principles for maintainable code
|
|
272
|
-
- Write self-documenting code with clear intent
|
|
273
|
-
- Implement proper error boundaries
|
|
274
|
-
- Test behavior, not implementation details
|
|
9
|
+
This file applies to **this scaffolded head application only**. For the Content SDK monorepo (packages, CLI, templates source), use that repo's root `AGENTS.md` and `.cursor/rules/`.
|