Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 30 additions & 3 deletions docs/tutorials/nexus/sync-nexus-tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,29 @@ description: Learn how to decouple Temporal services with Nexus and the Java SDK
image: /img/temporal-logo-twitter-card.png
---

import {useEffect} from 'react';

export const IframeAutoResize = () => {
useEffect(() => {
const handler = (e) => {
if (e.data?.type === 'iframeResize' && typeof e.data.height === 'number') {
document.querySelectorAll('iframe').forEach(iframe => {
try {
if (iframe.contentWindow === e.source) {
iframe.style.setProperty('height', e.data.height + 'px', 'important');
}
} catch(err) {}
});
Comment on lines +19 to +27
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The iframe resize message handler accepts postMessage events from any origin. Since these embedded iframes are served from the same origin (e.g. /html/...), add an e.origin === window.location.origin (or explicit allowed-origin) check before applying the height update to avoid other iframes/windows on the page being able to force layout changes via iframeResize messages.

Copilot uses AI. Check for mistakes.
}
};
window.addEventListener('message', handler);
return () => window.removeEventListener('message', handler);
}, []);
return null;
};

<IframeAutoResize />

# Decoupling Temporal Services with Nexus and the Java SDK

<p style={{fontSize: '14px'}}>
Expand Down Expand Up @@ -86,9 +109,13 @@ Right now, **both teams' code runs on the same Worker**. One process. One deploy
0%, 100% { box-shadow: 0 0 12px rgba(249,115,22,0.5), 0 0 24px rgba(249,115,22,0.2); }
50% { box-shadow: 0 0 20px rgba(249,115,22,0.8), 0 0 40px rgba(249,115,22,0.4); }
}
@media (max-width: 768px) {
iframe[title*="Match the Change"],
iframe[title*="Quick Match"] { display: none !important; }
}
Comment on lines +112 to +115
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new mobile CSS rule hides the “Quick Match” and “Match the Change” iframes entirely for screens <= 768px. That prevents mobile users from accessing the interactive exercises, and it also contradicts the PR goal of fixing mobile issues. Consider removing this rule (or replacing it with a mobile-friendly layout/tap-support fallback message instead of display: none).

Copilot uses AI. Check for mistakes.
`}</style>

<iframe src="/html/nexus-decouple.html" width="100%" height="900" style={{border: 'none', borderRadius: '8px'}} title="Interactive: Monolith vs Nexus architecture"></iframe>
<iframe src="/html/nexus-decouple.html" width="100%" height="500" scrolling="no" style={{border: 'none', borderRadius: '8px', overflow: 'hidden'}} title="Interactive: Monolith vs Nexus architecture"></iframe>

Compliance isn't optional — every payment must pass risk assessment before execution. This hard dependency is dangerous: a bug in compliance code at 3 AM crashes payments too, because they share the same namespace and blast radius. The obvious fix is to split into separate namespaces and use an Activity to call across the boundary — wrapping an HTTP client or starting a remote Workflow. But then you're managing HTTP clients, routing, error mapping, and callback infrastructure yourself.

Expand Down Expand Up @@ -284,7 +311,7 @@ Service → Operation → Endpoint → Registry

Can you match each Nexus concept to what it represents in our payments scenario?

<iframe src="/html/nexus-quick-match.html" width="100%" height="680" style={{border: 'none', borderRadius: '8px'}} title="Nexus Building Blocks — Quick Match"></iframe>
<iframe src="/html/nexus-quick-match.html" width="100%" height="580" style={{border: 'none', borderRadius: '8px'}} title="Nexus Building Blocks — Quick Match"></iframe>

</details>

Expand Down Expand Up @@ -614,7 +641,7 @@ ComplianceResult compliance = complianceService.checkCompliance(compReq);

**What changed:** Drag each Nexus replacement to its monolith equivalent:

<iframe src="/html/nexus-match-change.html" width="100%" height="900" style={{border: 'none', borderRadius: '8px'}} title="Match the Change — Monolith to Nexus"></iframe>
<iframe src="/html/nexus-match-change.html" width="100%" height="680" style={{border: 'none', borderRadius: '8px'}} title="Match the Change — Monolith to Nexus"></iframe>

:::tip
**Your feedback shapes what we make next**. Use the Feedback widget on the side to tell us what’s working and what’s missing!
Expand Down
119 changes: 118 additions & 1 deletion static/html/nexus-decouple.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
color: var(--text);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 14px;
min-height: 100vh;
display: flex;
flex-direction: column;
}
Expand Down Expand Up @@ -610,6 +609,106 @@
50% { border-color: var(--compliance-color); box-shadow: 0 0 20px rgba(34,197,94,0.3); }
100% { border-color: var(--compliance-border); }
}

/* ── Mobile responsive ─────────────────────────────── */
@media (max-width: 768px) {
header {
flex-wrap: wrap;
padding: 10px 12px;
gap: 8px;
}
header h1 { font-size: 14px; }
header .subtitle { font-size: 12px; }

.controls {
padding: 8px 12px;
gap: 8px;
}
.step-dots { margin-left: 0; }

.step-bar {
flex-wrap: wrap;
padding: 8px 12px;
gap: 8px;
min-height: auto;
}
.step-text strong { font-size: 13px; }
.step-text .tip { font-size: 11px; }

.main {
flex: none;
flex-direction: column;
overflow: visible;
}

.side-panel {
width: 100%;
border-left: none;
border-top: 1px solid var(--border);
max-height: 180px;
overflow-y: auto;
}

.canvas {
flex: none;
flex-direction: column;
padding: 12px 8px;
overflow: visible;
}

.team-zone {
padding: 10px;
}

.nexus-boundary {
width: 100%;
height: auto;
flex-direction: row;
padding: 8px 0;
}
.nexus-line {
width: 100%;
height: 3px;
}

/* Monolith overrides for column layout */
.canvas.monolith .nexus-boundary {
height: 0;
padding: 0;
}
.canvas.monolith .team-zone.compliance {
height: 0;
flex: 0;
}

.component-title { font-size: 12px; }
.component-type { font-size: 10px; }
.component { padding: 10px; }

.nav-btn { padding: 6px 12px; font-size: 12px; }
.mode-toggle { padding: 4px 8px; }

.waiting-banner {
position: fixed;
bottom: auto;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
white-space: normal;
font-size: 12px;
max-width: 85vw;
}
.crash-banner {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 14px 16px;
max-width: 85vw;
}
.crash-banner .crash-title { font-size: 14px; }
.crash-banner .crash-detail { font-size: 12px; }
}
</style>
</head>
<body>
Expand Down Expand Up @@ -1256,6 +1355,24 @@ <h3>${content.title}</h3>
// ── Init ─────────────────────────────────────────────────────────
document.getElementById('canvas').classList.add('monolith');
renderStep();

// ── Auto-resize iframe ──────────────────────────────────────────
(function() {
var lastH = 0;
function notifyHeight() {
var h = document.body.offsetHeight;
if (h !== lastH && window.parent && window.parent !== window) {
lastH = h;
window.parent.postMessage({ type: 'iframeResize', height: h }, '*');
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This auto-resize code posts messages with targetOrigin='*'. Since the parent page is expected to be same-origin, set an explicit targetOrigin (e.g. window.location.origin) to avoid sending messages to an unexpected embedding parent and to support origin validation on the receiver.

Suggested change
window.parent.postMessage({ type: 'iframeResize', height: h }, '*');
window.parent.postMessage({ type: 'iframeResize', height: h }, window.location.origin);

Copilot uses AI. Check for mistakes.
}
}
window.addEventListener('load', notifyHeight);
window.addEventListener('resize', notifyHeight);
setInterval(notifyHeight, 300);
if (typeof ResizeObserver !== 'undefined') {
new ResizeObserver(notifyHeight).observe(document.body);
Comment on lines +1371 to +1373
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setInterval(notifyHeight, 300) will wake up and post messages ~3x/sec even when nothing changes (and even though a ResizeObserver is also registered). Consider using the interval only as a fallback when ResizeObserver is unavailable, or throttling/debouncing notifyHeight to reduce unnecessary work and postMessage traffic (especially on mobile).

Suggested change
setInterval(notifyHeight, 300);
if (typeof ResizeObserver !== 'undefined') {
new ResizeObserver(notifyHeight).observe(document.body);
if (typeof ResizeObserver !== 'undefined') {
new ResizeObserver(notifyHeight).observe(document.body);
} else {
setInterval(notifyHeight, 300);

Copilot uses AI. Check for mistakes.
}
})();
</script>
</body>
</html>
Loading