@jahia/agentic 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/antigravity/.agents/rules/jahia.md +51 -0
  3. package/dist/antigravity/.agents/skills/jahia-cnd-author/SKILL.md +94 -0
  4. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/cnd-area-types.md +55 -0
  5. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/cnd-authoring-experience.md +92 -0
  6. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/cnd-child-nodes.md +74 -0
  7. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/cnd-jahia-mixins.md +510 -0
  8. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/cnd-modeling-decisions.md +87 -0
  9. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/cnd-numbers-dates.md +92 -0
  10. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/cnd-string-selectors.md +133 -0
  11. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/cnd-syntax.md +119 -0
  12. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/types-ts-mapping.md +73 -0
  13. package/dist/antigravity/.agents/skills/jahia-dev-accessibility/SKILL.md +11 -0
  14. package/dist/antigravity/.agents/skills/jahia-dev-build-component/SKILL.md +133 -0
  15. package/dist/antigravity/.agents/skills/jahia-dev-create-page-template/SKILL.md +341 -0
  16. package/dist/antigravity/.agents/skills/jahia-dev-create-template-set/SKILL.md +205 -0
  17. package/dist/antigravity/.agents/skills/jahia-dev-create-view/SKILL.md +896 -0
  18. package/dist/antigravity/.agents/skills/jahia-dev-debug/SKILL.md +176 -0
  19. package/dist/antigravity/.agents/skills/jahia-dev-import-from/SKILL.md +244 -0
  20. package/dist/antigravity/.agents/skills/jahia-dev-jexperience/SKILL.md +269 -0
  21. package/dist/antigravity/.agents/skills/jahia-dev-ops/SKILL.md +50 -0
  22. package/dist/antigravity/.agents/skills/jahia-dev-ops/references/docker.md +151 -0
  23. package/dist/antigravity/.agents/skills/jahia-dev-ops/references/monitoring.md +195 -0
  24. package/dist/antigravity/.agents/skills/jahia-dev-ops/references/provisioning.md +269 -0
  25. package/dist/antigravity/.agents/skills/jahia-dev-properties/SKILL.md +147 -0
  26. package/dist/antigravity/.agents/skills/jahia-dev-properties/references/all-properties.md +231 -0
  27. package/dist/antigravity/.agents/skills/jahia-dev-query-content/SKILL.md +204 -0
  28. package/dist/antigravity/.agents/skills/jahia-dev-review/SKILL.md +228 -0
  29. package/dist/antigravity/.agents/skills/jahia-dev-review-cnd/SKILL.md +79 -0
  30. package/dist/antigravity/.agents/skills/jahia-dev-review-cnd/scripts/check-cnd.d.mts +13 -0
  31. package/dist/antigravity/.agents/skills/jahia-dev-review-cnd/scripts/check-cnd.mjs +198 -0
  32. package/dist/antigravity/.agents/skills/jahia-dev-screenshot/SKILL.md +177 -0
  33. package/dist/antigravity/.agents/skills/jahia-dev-site-review/SKILL.md +70 -0
  34. package/dist/antigravity/.agents/skills/jahia-dev-site-review/scripts/review-pages.mjs +85 -0
  35. package/dist/antigravity/.agents/skills/jahia-dev-start-local/SKILL.md +121 -0
  36. package/dist/antigravity/.agents/skills/jahia-jcr-sql2/SKILL.md +258 -0
  37. package/dist/antigravity/AGENTS.md +62 -0
  38. package/dist/claude/.mcp.json +11 -0
  39. package/dist/cursor/.cursor/mcp.json +11 -0
  40. package/dist/gemini/.gemini/settings.json +10 -0
  41. package/dist/index.js +12 -0
  42. package/dist/kiro/.kiro/settings/mcp.json +10 -0
  43. package/dist/kiro/.kiro/skills/jahia-cnd-author/SKILL.md +94 -0
  44. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/cnd-area-types.md +55 -0
  45. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/cnd-authoring-experience.md +92 -0
  46. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/cnd-child-nodes.md +74 -0
  47. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/cnd-jahia-mixins.md +510 -0
  48. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/cnd-modeling-decisions.md +87 -0
  49. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/cnd-numbers-dates.md +92 -0
  50. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/cnd-string-selectors.md +133 -0
  51. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/cnd-syntax.md +119 -0
  52. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/types-ts-mapping.md +73 -0
  53. package/dist/kiro/.kiro/skills/jahia-dev-accessibility/SKILL.md +11 -0
  54. package/dist/kiro/.kiro/skills/jahia-dev-build-component/SKILL.md +133 -0
  55. package/dist/kiro/.kiro/skills/jahia-dev-create-page-template/SKILL.md +341 -0
  56. package/dist/kiro/.kiro/skills/jahia-dev-create-template-set/SKILL.md +205 -0
  57. package/dist/kiro/.kiro/skills/jahia-dev-create-view/SKILL.md +896 -0
  58. package/dist/kiro/.kiro/skills/jahia-dev-debug/SKILL.md +176 -0
  59. package/dist/kiro/.kiro/skills/jahia-dev-import-from/SKILL.md +244 -0
  60. package/dist/kiro/.kiro/skills/jahia-dev-jexperience/SKILL.md +269 -0
  61. package/dist/kiro/.kiro/skills/jahia-dev-ops/SKILL.md +50 -0
  62. package/dist/kiro/.kiro/skills/jahia-dev-ops/references/docker.md +151 -0
  63. package/dist/kiro/.kiro/skills/jahia-dev-ops/references/monitoring.md +195 -0
  64. package/dist/kiro/.kiro/skills/jahia-dev-ops/references/provisioning.md +269 -0
  65. package/dist/kiro/.kiro/skills/jahia-dev-properties/SKILL.md +147 -0
  66. package/dist/kiro/.kiro/skills/jahia-dev-properties/references/all-properties.md +231 -0
  67. package/dist/kiro/.kiro/skills/jahia-dev-query-content/SKILL.md +204 -0
  68. package/dist/kiro/.kiro/skills/jahia-dev-review/SKILL.md +228 -0
  69. package/dist/kiro/.kiro/skills/jahia-dev-review-cnd/SKILL.md +79 -0
  70. package/dist/kiro/.kiro/skills/jahia-dev-review-cnd/scripts/check-cnd.d.mts +13 -0
  71. package/dist/kiro/.kiro/skills/jahia-dev-review-cnd/scripts/check-cnd.mjs +198 -0
  72. package/dist/kiro/.kiro/skills/jahia-dev-screenshot/SKILL.md +177 -0
  73. package/dist/kiro/.kiro/skills/jahia-dev-site-review/SKILL.md +70 -0
  74. package/dist/kiro/.kiro/skills/jahia-dev-site-review/scripts/review-pages.mjs +85 -0
  75. package/dist/kiro/.kiro/skills/jahia-dev-start-local/SKILL.md +121 -0
  76. package/dist/kiro/.kiro/skills/jahia-jcr-sql2/SKILL.md +258 -0
  77. package/dist/kiro/.kiro/steering/jahia.md +55 -0
  78. package/dist/kiro/AGENTS.md +62 -0
  79. package/dist/opencode/opencode.json +12 -0
  80. package/package.json +1 -1
@@ -0,0 +1,176 @@
1
+ ---
2
+ name: jahia-dev-debug
3
+ description: Debugs a Jahia JavaScript module end-to-end — build, deploy, and runtime errors. Finds the first error after deployment using live Docker logs.
4
+ ---
5
+
6
+ # Skill: jahia-dev-debug
7
+
8
+ Diagnoses why a Jahia JavaScript module fails to load. Follows the deployment pipeline from source to runtime.
9
+
10
+ ---
11
+
12
+ ## Step 1 — Build
13
+
14
+ From the module directory (where `package.json` is):
15
+
16
+ ```bash
17
+ yarn build
18
+ ```
19
+
20
+ - **Build fails** → fix the TypeScript / bundling error shown and stop here. Do not proceed to deploy until the build is clean.
21
+ - **Build succeeds** → proceed to Step 2.
22
+
23
+ ---
24
+
25
+ ## Step 2 — Deploy
26
+
27
+ ```bash
28
+ yarn jahia-deploy
29
+ ```
30
+
31
+ Interpret the output:
32
+ - `"Operation successful"` in the response → deployment was accepted. Proceed to Step 3 — the module may still fail at runtime.
33
+ - `"{}"` or empty JSON → deployment was **rejected** (usually a CND parse error or missing dependency). Proceed to Step 3 to find the cause in the logs.
34
+ - Any other error → fix the connection issue (is Docker running?) then retry.
35
+
36
+ ---
37
+
38
+ ## Step 3 — Watch live Docker logs
39
+
40
+ > Do NOT analyse logs that already exist — an old error is not necessarily the cause of the current issue. Start a fresh log stream, then deploy again to capture only what happens as a result of this deployment.
41
+
42
+ ### 3a — Start watching logs in the background
43
+
44
+ Find the Jahia container name:
45
+
46
+ ```bash
47
+ docker ps --format '{{.Names}}' | grep -i jahia | head -1
48
+ ```
49
+
50
+ Then start tailing:
51
+
52
+ ```bash
53
+ docker logs -f <container-name> 2>&1 | grep -v "^\s*$" &
54
+ LOG_PID=$!
55
+ ```
56
+
57
+ ### 3b — Deploy again while logs are streaming
58
+
59
+ ```bash
60
+ yarn jahia-deploy
61
+ ```
62
+
63
+ ### 3c — Wait ~15 seconds, then stop the log stream
64
+
65
+ ```bash
66
+ sleep 15 && kill $LOG_PID 2>/dev/null
67
+ ```
68
+
69
+ ### 3d — Verify component registration
70
+
71
+ ```bash
72
+ docker logs <container-name> 2>&1 | grep "Registered Jahia component"
73
+ ```
74
+
75
+ Expected: one line per view registered, e.g.:
76
+ ```
77
+ Registered Jahia component: mymodule_view_ns:hero_default
78
+ Registered Jahia component: mymodule_view_ns:hero_small
79
+ ```
80
+
81
+ If a component you just deployed is **absent** from this list, its `jahiaComponent` call was never reached — usually a syntax/import error in the view file that prevented the module from fully loading.
82
+
83
+ ---
84
+
85
+ ## Step 4 — Find the first error
86
+
87
+ Scan the captured log output for the **first** error that appears **after** the deploy timestamp. Common patterns to look for:
88
+
89
+ | Pattern | Likely cause |
90
+ |---|---|
91
+ | `CND parse error` / `invalid node type` | CND syntax error or illegal field declaration |
92
+ | `NoSuchNodeTypeException` | A referenced type doesn't exist (wrong namespace, typo, missing dependency) |
93
+ | `ClassNotFoundException` / `NoClassDefFoundError` | Java dependency missing |
94
+ | `Cannot set property` / `TypeError` in JS stack | View runtime error |
95
+ | `Module ... failed to start` | Any of the above |
96
+ | `Unresolved requirement` | OSGi dependency not satisfied |
97
+ | Missing `Registered Jahia component` for a specific type | View file has a syntax/import error, or `jahiaComponent` not reached |
98
+
99
+ **Focus on the first error, not the last.** Later errors are often cascading failures caused by the first one.
100
+
101
+ ---
102
+
103
+ ## Step 5 — Fix and retry
104
+
105
+ Once the root cause is identified:
106
+
107
+ 1. Fix the issue in the source files
108
+ 2. Run `yarn build` again
109
+ 3. Go back to Step 2
110
+
111
+ Repeat until `yarn jahia-deploy` succeeds and the module loads cleanly (no errors in the 15-second window after deploy).
112
+
113
+ ---
114
+
115
+ ## Common fixes by error type
116
+
117
+ ### CND: `j:linknode` or `j:url` declared explicitly
118
+ These fields are injected by Jahia's `linkTypeInitializer` mixin. Remove them from the CND.
119
+
120
+ ### CND: unknown mixin or type
121
+ Check that the namespace is declared at the top of `settings/definitions.cnd` and that all referenced types exist.
122
+
123
+ ### import.xml: reference to a non-existent type
124
+ Any `jcr:primaryType` or `jcr:mixinTypes` value in `import.xml` must exist in the deployed CND. Check for typos.
125
+
126
+ ### import.xml: `jmix:nolive` used as `jcr:primaryType`
127
+ `jmix:nolive` is a mixin — it goes in `jcr:mixinTypes`, not `jcr:primaryType`.
128
+
129
+ ### import.xml: OSGi fails with `missing requirement … (nodetypes=jmix:nolive)`
130
+ Every `jcr:mixinTypes` value in `import.xml` is scanned by the OSGi bundle resolver. If the mixin is not declared in the module's own CND and is not provided by a resolvable dependency, the bundle will not start. Correct spelling is `jmix:nolive` (all lowercase). Verify the mixin exists in your Jahia instance before using it in `import.xml`.
131
+
132
+ ### View: module loads but page is blank
133
+ Run `yarn dev` and check the Vite / SSR console for a React render error.
134
+
135
+ ---
136
+
137
+ ## GraalJS (server-side JS) debugging with Chrome DevTools
138
+
139
+ Use this when you need to step through server-side view code running inside GraalVM.
140
+
141
+ ### Step 1 — Enable the inspector via GraphQL
142
+
143
+ In Jahia's Developer Tools > GraphQL editor, run:
144
+
145
+ ```graphql
146
+ mutation {
147
+ admin {
148
+ jahia {
149
+ configuration(pid: "org.jahia.modules.javascript.modules.engine.jsengine.GraalVMEngine") {
150
+ polyGlotInspect: value(name: "polyglot.inspect", value: "0.0.0.0:9229")
151
+ polyGlotInspectSuspend: value(name: "polyglot.inspect.Suspend", value: "false")
152
+ polyGlotInspectSecure: value(name: "polyglot.inspect.Secure", value: "false")
153
+ }
154
+ }
155
+ }
156
+ }
157
+ ```
158
+
159
+ ### Step 2 — Map the port
160
+
161
+ If running in Docker, ensure port `9229` is mapped in `docker-compose.yml`:
162
+
163
+ ```yaml
164
+ ports:
165
+ - "9229:9229"
166
+ ```
167
+
168
+ ### Step 3 — Connect Chrome
169
+
170
+ After the mutation, Jahia logs a `devtools://...` URL. Open it in Chrome (use latest; Chrome 117–118 had known debugger bugs).
171
+
172
+ ### Step 4 — Set a breakpoint and debug
173
+
174
+ In Chrome DevTools Sources tab, open `<module>/dist/main.js`, set a breakpoint, then reload the page. The server-side render pauses at the breakpoint. Full scope inspection, step-over, and continue are supported.
175
+
176
+ The config file `org.jahia.modules.javascript.modules.engine.jsengine.GraalVMEngine.cfg` accepts any `polyglot.*` key as an engine option — you can persist these settings there instead of using the GraphQL mutation.
@@ -0,0 +1,244 @@
1
+ ---
2
+ name: jahia-dev-import-from
3
+ description: Builds a Jahia component inspired by a component on an external URL. Fetches the page, lets the developer target one section, extracts its HTML structure and CSS/JS dependencies, then creates a proper CND + view. Use when asked to "create a component like the one on this page".
4
+ allowed-tools: Bash, Read, Write, Edit, WebFetch
5
+ ---
6
+
7
+ # Skill: jahia-dev-import-from
8
+
9
+ Turns a component on an external website into a Jahia component. This is a developer workflow — the result uses CSS Modules, proper Jahia architecture, and is maintainable code. It is not a wholesale site clone.
10
+
11
+ ---
12
+
13
+ ## Step 1 — Fetch and map the page
14
+
15
+ Fetch the URL with `WebFetch`. If WebFetch fails (403/503), fall back to:
16
+
17
+ ```bash
18
+ wget --quiet --user-agent="Mozilla/5.0" -O /tmp/imported-page.html "<URL>"
19
+ ```
20
+
21
+ Scan the HTML for semantic section boundaries (`<section>`, `<article>`, `<header>`, `<footer>`, `<main>`, or `<div>` with class names matching patterns like `hero`, `banner`, `card`, `grid`, `slider`, `features`).
22
+
23
+ Print a numbered text map:
24
+
25
+ ```
26
+ [1] HEADER — logo + nav + CTA button
27
+ [2] HERO — animated text + background image + scroll indicator
28
+ [3] FEATURES — 3-column icon grid
29
+ [4] CAROUSEL — auto-sliding testimonials (Swiper)
30
+ [5] FOOTER — 4-column links + social icons
31
+ ```
32
+
33
+ Ask the developer: **"Which section do you want to implement?"**
34
+
35
+ ---
36
+
37
+ ## Step 2 — Extract the HTML fragment
38
+
39
+ Locate the target section in the fetched HTML. Extract the **complete HTML block** — every element, every attribute, every nesting level. Do not simplify, summarize, or rewrite any part of it.
40
+
41
+ **For repeating patterns** (card grid, carousel), copy the wrapper structure **plus one complete child item** with all its attributes.
42
+
43
+ **Replace only dynamic content** with typed placeholders:
44
+
45
+ | Source HTML | Replacement |
46
+ |---|---|
47
+ | Text inside an element | `{title}`, `{description}`, etc. |
48
+ | Image `src` / `data-bg` / `data-src` URL | `{image}` (will become a `weakreference` field) |
49
+ | Link `href` | `{href}` (will become `j:linkType` / `j:linknode`) |
50
+
51
+ **Keep verbatim:**
52
+ - All CSS classes
53
+ - All `data-*` attributes (animation libraries, carousel config, IDs)
54
+ - `aria-*` and `role` attributes
55
+ - `<noscript>` blocks and `<picture>/<source>` elements
56
+ - Carousel/slider wrapper `id`s — JS libraries use these for initialization
57
+
58
+ > ⚠️ Self-check: count the attributes on 2–3 key elements in the source HTML. If your extraction has fewer, you dropped something — re-extract.
59
+
60
+ ---
61
+
62
+ ## Step 3 — Identify content fields vs structural HTML
63
+
64
+ Show the developer a proposed split:
65
+
66
+ **Will become CND fields (editable in Jahia):**
67
+ - User-facing text: titles, subtitles, descriptions, button labels
68
+ - Images (→ `weakreference, picker[type='image']`)
69
+ - Links (→ `j:linkType / j:linknode / j:url`)
70
+ - Any value that should vary between instances
71
+
72
+ **Will be hardcoded in the view:**
73
+ - Layout wrapper divs
74
+ - Icon SVGs that are decorative / never change
75
+ - Animation class names and `data-*` config attributes
76
+ - ARIA labels that are structural (e.g. `aria-label="Main navigation"`)
77
+
78
+ Ask the developer to confirm or adjust. If they want something to be editable that wasn't identified, add it as a field.
79
+
80
+ ---
81
+
82
+ ## Step 4 — Identify CSS and JS dependencies
83
+
84
+ Scan the page `<head>` for resources that the target component depends on:
85
+
86
+ ```bash
87
+ # From downloaded HTML, extract stylesheet and script references
88
+ grep -E '<link[^>]+stylesheet|<script[^>]+src' /tmp/imported-page.html | head -30
89
+ ```
90
+
91
+ Categorize findings:
92
+
93
+ | Type | Examples | Action |
94
+ |---|---|---|
95
+ | **Animation library** | AOS, GSAP, ScrollReveal, Animate.css | Likely needed — check npm first |
96
+ | **Carousel/slider** | Swiper, Glide, Owl Carousel, Splide | Likely needed — check npm first |
97
+ | **Utility CSS** | Bootstrap, Tailwind | May already be in the module or can be imported |
98
+ | **Site-specific CSS** | `main.css`, `theme.css` | Targeted import only (see Step 5b) |
99
+ | **Fonts** | Google Fonts, custom woff2 | Import if not already in the module |
100
+
101
+ Report findings, then ask: **"Should I import any of these? (yes / no / specific ones)"**
102
+
103
+ ---
104
+
105
+ ## Step 5 — Create the Jahia component
106
+
107
+ ### Step 5a — CND and view
108
+
109
+ Using the confirmed field split from Step 3, run the `jahia-dev-define-content-type` and `jahia-dev-create-view` patterns to create:
110
+
111
+ - `src/components/<Category>/<Name>/definition.cnd`
112
+ - `src/components/<Category>/<Name>/types.ts`
113
+ - `src/components/<Category>/<Name>/default.server.tsx`
114
+ - `src/components/<Category>/<Name>/component.module.css`
115
+
116
+ **TSX conversion rules** (mechanical, not creative):
117
+
118
+ 1. `class="foo bar"` → `className="foo bar"` — keep class strings as-is if vendor CSS is imported, OR map to `classes.fooBar` if authoring new CSS
119
+ 2. Void elements: `<img>`, `<input>`, `<br>` → add ` />`
120
+ 3. `{placeholder}` → `{propName}` matching `Props`
121
+ 4. Every `data-*`, `aria-*`, `id`, `<noscript>`, `<source>` stays in the TSX
122
+
123
+ **CSS Modules:** Write new CSS in `component.module.css` that achieves the same visual result. Rename source class names to semantic camelCase keys (`hero__title` → `.heroTitle`). Exception: if you're importing the original CSS as a static asset, use the original class names as plain strings — CSS Modules would rename them and break the imported CSS.
124
+
125
+ **Interactive components** (animations, carousels, event handlers) → Island architecture:
126
+
127
+ ```tsx
128
+ // default.server.tsx — passes config, initializes nothing
129
+ ({ title, subtitle }: Props, { renderContext }) => (
130
+ <Island component={MyComponentClient} props={{ title, subtitle }} />
131
+ )
132
+
133
+ // MyComponent.client.tsx — owns the browser-side lifecycle
134
+ import { useEffect } from "react";
135
+
136
+ export default function MyComponentClient({ title, subtitle }: Props) {
137
+ useEffect(() => {
138
+ import("aos").then(({ default: AOS }) => AOS.init({ duration: 800 }));
139
+ }, []);
140
+
141
+ return (
142
+ <div data-aos="fade-up" className="hero">
143
+ <h1>{title}</h1>
144
+ </div>
145
+ );
146
+ }
147
+ ```
148
+
149
+ **Edit mode for carousels/sliders:** Render all items flat so editors can see and reorder them:
150
+
151
+ ```tsx
152
+ ({ slides }, { renderContext }) =>
153
+ renderContext.isEditMode() ? (
154
+ <div className={classes.editStack}>
155
+ <RenderChildren />
156
+ <p className={classes.hint}>Carousel — add or reorder slides above</p>
157
+ </div>
158
+ ) : (
159
+ <Island component={CarouselClient} props={{ count: slides?.length }} />
160
+ )
161
+ ```
162
+
163
+ ---
164
+
165
+ ### Step 5b — Import static assets (if confirmed in Step 4)
166
+
167
+ For each confirmed CSS file:
168
+
169
+ ```bash
170
+ mkdir -p static/css
171
+ curl -sL "<css-url>" -o "static/css/<filename>.css"
172
+ ```
173
+
174
+ For JS libraries — prefer npm over manual download:
175
+
176
+ ```bash
177
+ # Check if available on npm
178
+ npm info <library-name> version 2>/dev/null
179
+
180
+ # If available:
181
+ yarn add <library-name>
182
+ # Then import in the .client.tsx: import AOS from "aos";
183
+
184
+ # If not on npm, download to static:
185
+ mkdir -p static/js
186
+ curl -sL "<js-url>" -o "static/js/<filename>.js"
187
+ ```
188
+
189
+ For fonts:
190
+
191
+ ```bash
192
+ mkdir -p static/fonts
193
+ curl -sL "<font-url>" -o "static/fonts/<filename>.woff2"
194
+ ```
195
+
196
+ Update the module's `Layout` template (`src/templates/Layout.server.tsx` or `src/templates/Layout.jsx`) to include the assets:
197
+
198
+ ```tsx
199
+ import { AddResources, buildModuleFileUrl } from "@jahia/javascript-modules-library";
200
+
201
+ // In the <head> section:
202
+ <AddResources type="css" url={buildModuleFileUrl("static/css/vendor.css")} />
203
+ <AddResources type="javascript" url={buildModuleFileUrl("static/js/aos.js")} />
204
+ ```
205
+
206
+ Update `package.json` → `jahia.static-resources` to expose the static directories:
207
+
208
+ ```json
209
+ {
210
+ "jahia": {
211
+ "static-resources": "/dist/client,/dist/assets,/locales,/static/css,/static/js,/static/fonts"
212
+ }
213
+ }
214
+ ```
215
+
216
+ > **Never hardcode `/modules/<name>/...` paths** — use `buildModuleFileUrl` so the path resolves correctly across environments and module name changes.
217
+
218
+ ---
219
+
220
+ ## Step 6 — Build, deploy, and verify
221
+
222
+ ```bash
223
+ yarn build && yarn jahia-deploy
224
+ ```
225
+
226
+ Verify the component registered:
227
+
228
+ ```bash
229
+ docker logs $(docker ps --format '{{.Names}}' | grep -i jahia | head -1) 2>&1 \
230
+ | grep "Registered Jahia component" | grep "<ComponentName>"
231
+ ```
232
+
233
+ Expected: one line per view. If absent, check the build output for TypeScript errors in the new view file.
234
+
235
+ ---
236
+
237
+ ## Rules that always apply
238
+
239
+ - **CSS Modules for authored styles** — use `classes.propertyName`, not plain string class names
240
+ - **Vendor class names stay as-is** — when importing external CSS, don't route those classes through CSS Modules
241
+ - **No hardcoded links** — `href` and `src` must come from JCR props or `buildModuleFileUrl`
242
+ - **Island for anything interactive** — animations, browser events, `useState`, third-party JS → `.client.tsx`
243
+ - **All props optional in `types.ts`** — even CND `mandatory` fields
244
+ - **Edit mode awareness** — carousels, sliders, and tabs should render flat in edit mode
@@ -0,0 +1,269 @@
1
+ ---
2
+ name: jahia-dev-jexperience
3
+ description: Integrate a Jahia JavaScript module with jExperience and jCustomer — set up the local stack, push visitor events from client components, visualize data in Kibana, and package dashboards for deployment.
4
+ allowed-tools: Bash, Read, Write, Edit
5
+ ---
6
+
7
+ ## What is jExperience / jCustomer?
8
+
9
+ **jCustomer** (built on Apache Unomi) collects and processes visitor events to create personalized digital experiences. **jExperience** is the Jahia module that bridges Jahia with jCustomer — it injects the `window.wem` tracker into every page and exposes dashboards inside jContent.
10
+
11
+ Together they form Jahia's **DXP** (Digital Experience Platform). You only need this skill when you want to track interactions, build personalization, or visualize visitor data.
12
+
13
+ ---
14
+
15
+ ## Step 1 — Set up jCustomer locally
16
+
17
+ ### 1a — Update `docker-compose.yml`
18
+
19
+ Give the `jahia` service a static IP, add three containers, and declare the subnet:
20
+
21
+ ```yaml
22
+ services:
23
+ jahia:
24
+ # ... existing config ...
25
+ networks:
26
+ default:
27
+ ipv4_address: 172.16.1.100
28
+
29
+ elasticsearch:
30
+ image: elasticsearch:7.17.28
31
+ ports:
32
+ - 9200:9200
33
+ environment:
34
+ discovery.type: single-node
35
+ cluster.name: jahia-es-cluster
36
+
37
+ kibana:
38
+ image: kibana:7.17.28
39
+ ports:
40
+ - 5601:5601
41
+ environment:
42
+ discovery.type: single-node
43
+ elasticsearch.hosts: http://elasticsearch:9200
44
+
45
+ jcustomer:
46
+ image: jahia/jcustomer:2.6
47
+ depends_on:
48
+ - elasticsearch
49
+ ports:
50
+ - 9443:9443
51
+ - 8181:8181
52
+ - 8102:8102
53
+ environment:
54
+ UNOMI_ELASTICSEARCH_ADDRESSES: elasticsearch:9200
55
+ UNOMI_ELASTICSEARCH_CLUSTERNAME: jahia-es-cluster
56
+ UNOMI_CLUSTER_PUBLIC_ADDRESS: http://localhost:8181
57
+ UNOMI_CLUSTER_INTERNAL_ADDRESS: https://jcustomer:9443
58
+ UNOMI_THIRDPARTY_PROVIDER1_IPADDRESSES: 172.16.1.100
59
+ UNOMI_THIRDPARTY_PROVIDER1_ALLOWEDEVENTS: login,updateProperties
60
+ UNOMI_ROOT_PASSWORD: karaf
61
+ UNOMI_HAZELCAST_TCPIP_MEMBERS: jcustomer
62
+
63
+ networks:
64
+ default:
65
+ ipam:
66
+ config:
67
+ - subnet: 172.16.1.0/24
68
+ ```
69
+
70
+ ### 1b — Update `docker/provisioning.yml`
71
+
72
+ Append at the end of the file:
73
+
74
+ ```yaml
75
+ # Install and start jExperience
76
+ - installModule:
77
+ - "mvn:org.jahia.modules/jexperience/3.6.2"
78
+ - "mvn:org.jahia.modules/jexperience-dashboards/1.0.0"
79
+ autoStart: true
80
+ uninstallPreviousVersion: true
81
+
82
+ # Connect jExperience to jCustomer
83
+ - editConfiguration: "org.jahia.modules.jexperience.settings"
84
+ configIdentifier: "global"
85
+ properties:
86
+ jexperience.jCustomerURL: "https://jcustomer:9443"
87
+ jexperience.jCustomerUsername: "karaf"
88
+ jexperience.jCustomerPassword: "karaf"
89
+ jexperience.jCustomerTrustAllCertificates: "true"
90
+ jexperience.jCustomerUsePublicAddressesForAdmin: "false"
91
+ jexperience.jCustomerKey: "670c26d1cc413346c3b2fd9ce65dab41"
92
+
93
+ # Configure Kibana dashboards proxy
94
+ - editConfiguration: "org.jahia.modules.kibana_dashboards_provider"
95
+ properties:
96
+ kibana_dashboards_provider.kibanaURL: "http://kibana:5601"
97
+ kibana_dashboards_provider.kibanaUser: "elastic"
98
+ kibana_dashboards_provider.kibanaPassword: "ELASTIC_PASSWORD"
99
+ kibana_dashboards_provider.KibanaProxy.enable: "true"
100
+ kibana_dashboards_provider.KibanaProxy.cloud: "true"
101
+ - installModule:
102
+ - "mvn:org.jahia.modules/kibana-dashboards-provider/1.4.0"
103
+ autoStart: true
104
+ uninstallPreviousVersion: true
105
+ ```
106
+
107
+ ### 1c — Start the stack
108
+
109
+ ```bash
110
+ docker compose down jahia && docker compose up --wait
111
+ ```
112
+
113
+ ### 1d — Enable jExperience on the site
114
+
115
+ 1. Open **Administration → Modules → jExperience → Usage in sites**
116
+ 2. Check the box next to your site. Repeat for **jExperience Dashboards**.
117
+ 3. Open jContent — a new **jExperience** tab should appear in the vertical bar (refresh if needed).
118
+
119
+ ---
120
+
121
+ ## Step 2 — Push events from a client component
122
+
123
+ jExperience injects `window.wem` (Web Experience Manager) into every page. It is only available in the browser — use it inside `.client.tsx` files.
124
+
125
+ ### Event model
126
+
127
+ Every event has two parts:
128
+
129
+ | Part | What it is | Helper |
130
+ |------|------------|--------|
131
+ | **source** | Where the event happened (usually the current page) | `wem.buildSourcePage()` |
132
+ | **target** | What happened (the action) | `wem.buildTarget(id, type, properties)` |
133
+
134
+ ### Full example — feedback widget
135
+
136
+ ```tsx
137
+ // src/components/FeedbackWidget/definition.cnd
138
+ // [hydrogen:feedbackWidget] > jnt:content, hydrogenmix:component
139
+ // - question (string) = 'Was this helpful?'
140
+ ```
141
+
142
+ ```tsx
143
+ // Widget.client.tsx
144
+ import { useState } from "react";
145
+
146
+ export default function Widget({ question }: { question: string }) {
147
+ const [sent, setSent] = useState(false);
148
+
149
+ const handler = (happy: boolean) => () => {
150
+ const source = wem.buildSourcePage();
151
+ const target = wem.buildTarget("feedback", "click", { happy });
152
+ const event = wem.buildEvent("click", target, source);
153
+ wem.collectEvents({ events: [event] });
154
+ setSent(true);
155
+ };
156
+
157
+ if (sent) return <aside>Thank you for your feedback!</aside>;
158
+
159
+ return (
160
+ <aside>
161
+ {question}
162
+ <button type="button" onClick={handler(true)}>Yes</button>
163
+ <button type="button" onClick={handler(false)}>No</button>
164
+ </aside>
165
+ );
166
+ }
167
+ ```
168
+
169
+ ```tsx
170
+ // default.server.tsx
171
+ import { jahiaComponent, Island } from "@jahia/javascript-modules-library";
172
+ import Widget from "./Widget.client.jsx";
173
+
174
+ interface Props { question: string; }
175
+
176
+ jahiaComponent(
177
+ { nodeType: "hydrogen:feedbackWidget", componentType: "view" },
178
+ ({ question }: Props) => (
179
+ <Island clientOnly component={Widget} props={{ question }}>
180
+ Loading…
181
+ </Island>
182
+ ),
183
+ );
184
+ ```
185
+
186
+ ### `window.wem` API reference
187
+
188
+ | Method | Signature | Returns |
189
+ |--------|-----------|---------|
190
+ | `buildSourcePage` | `()` | Source object for the current page |
191
+ | `buildTarget` | `(id: string, type: string, properties?: object)` | Target object |
192
+ | `buildEvent` | `(eventType: string, target, source)` | Event object |
193
+ | `collectEvents` | `({ events: Event[] })` | Sends events to jCustomer |
194
+
195
+ `buildTarget` properties are free-form — pass any serializable data you want to analyse downstream (e.g. `{ happy: true }`, `{ productId: "p-123" }`).
196
+
197
+ > The `window.wem` object comes from the [apache/unomi-tracker](https://github.com/apache/unomi-tracker) package. Refer to its documentation for advanced event types.
198
+
199
+ ### Google Tag Manager alternative
200
+
201
+ If your site uses GTM instead of jCustomer:
202
+
203
+ ```tsx
204
+ dataLayer.push({ event: "feedback", happy });
205
+ ```
206
+
207
+ ---
208
+
209
+ ## Step 3 — Verify events in Kibana
210
+
211
+ 1. Open [localhost:5601](http://localhost:5601)
212
+ 2. Go to **Discover**, select the `*-event` index, and expand the time range
213
+ 3. Browse an event — confirm the `source.properties.pageInfo.pagePath` and `target.properties.happy` fields are present
214
+
215
+ ---
216
+
217
+ ## Step 4 — Create a Kibana dashboard
218
+
219
+ ### Create a saved search
220
+
221
+ In **Discover**, add column filters for:
222
+ - `eventType` = `click`
223
+ - `itemType` = `event`
224
+ - `target.itemId` = `feedback`
225
+ - `target.itemType` = `click`
226
+
227
+ Add display columns: `source.properties.pageInfo.pagePath`, `target.properties.happy`. Save as e.g. **All Feedbacks**.
228
+
229
+ ### Create the dashboard
230
+
231
+ 1. **Dashboards → Create dashboard**
232
+ 2. **Add from library** → add the saved search (table of all feedbacks)
233
+ 3. **Create visualization** → paste this KQL filter into the search bar:
234
+ ```
235
+ eventType: click and itemType: event and target.itemId: feedback and target.itemType: click
236
+ ```
237
+ 4. Drop **Records** onto the panel, then in **Break down by** select `target.properties.happy`. Use the **Status** color palette for red/green.
238
+ 5. **Save and return**, then **Save** the dashboard with a meaningful name — this name becomes the entry label inside Jahia's jExperience tab.
239
+
240
+ ---
241
+
242
+ ## Step 5 — Package the dashboard in the module
243
+
244
+ Dashboards exported from Kibana are automatically imported when the module is deployed.
245
+
246
+ 1. In Kibana go to **Analytics → Overview → Manage → Saved Objects**
247
+ 2. Select your dashboard, click **Export** — you get a `.ndjson` file
248
+ 3. Save it to your module:
249
+ ```
250
+ settings/kibana-dashboard/dashboards/<dashboard-name>.ndjson
251
+ ```
252
+ 4. Deploy the module — the dashboard will appear in the jExperience tab on any Jahia instance running the module.
253
+
254
+ ---
255
+
256
+ ## Validation checklist
257
+ - [ ] `docker compose up --wait` completed with elasticsearch, kibana, jcustomer healthy
258
+ - [ ] jExperience and jExperience Dashboards enabled on the target site
259
+ - [ ] jExperience tab visible in jContent
260
+ - [ ] Client component uses `.client.tsx` extension and `Island clientOnly`
261
+ - [ ] `wem.collectEvents` called with a valid event (source + target)
262
+ - [ ] Events visible in Kibana Discover under `*-event` index
263
+ - [ ] Dashboard saved and visible under the jExperience tab in Jahia
264
+ - [ ] Dashboard `.ndjson` saved to `settings/kibana-dashboard/dashboards/` for packaging
265
+
266
+ ## References
267
+ - Apache Unomi tracker: https://github.com/apache/unomi-tracker
268
+ - KQL query syntax: https://www.elastic.co/guide/en/kibana/current/kuery-query.html
269
+ - jExperience guide: https://github.com/Jahia/javascript-modules/blob/main/docs/2-guides/1-building-a-feedback-form/README.md