| <!doctype html> |
| <html lang="en" data-theme="dark"> |
| <head> |
| <meta charset="utf-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1"> |
| <title>Modernization Guided Walkthrough · Legacy to Cloud</title> |
| <style> |
| :root { |
| --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; |
| --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; |
| |
| --bg-primary: #0f172a; |
| --bg-secondary: #1e293b; |
| --bg-card: rgba(30, 41, 59, 0.7); |
| --bg-card-hover: rgba(51, 65, 85, 0.8); |
| --bg-input: #0f172a; |
| |
| --text-primary: #f8fafc; |
| --text-secondary: #94a3b8; |
| --text-muted: #64748b; |
| --text-inverse: #0f172a; |
| |
| --border-color: rgba(255, 255, 255, 0.08); |
| --border-highlight: rgba(56, 189, 248, 0.3); |
| |
| --primary: #38bdf8; |
| --primary-glow: rgba(56, 189, 248, 0.25); |
| --secondary: #818cf8; |
| --accent-green: #34d399; |
| --accent-amber: #fbbf24; |
| --accent-rose: #f43f5e; |
| --accent-purple: #c084fc; |
| |
| --radius-sm: 6px; |
| --radius-md: 10px; |
| --radius-lg: 16px; |
| --radius-full: 9999px; |
| |
| --shadow-subtle: 0 4px 20px -2px rgba(0, 0, 0, 0.3); |
| --shadow-glow: 0 0 25px -5px var(--primary-glow); |
| } |
| |
| @media (prefers-color-scheme: light) { |
| :root[data-theme="system"], :root[data-theme="light"] { |
| --bg-primary: #f8fafc; |
| --bg-secondary: #ffffff; |
| --bg-card: rgba(255, 255, 255, 0.85); |
| --bg-card-hover: #f1f5f9; |
| --bg-input: #f8fafc; |
| |
| --text-primary: #0f172a; |
| --text-secondary: #475569; |
| --text-muted: #94a3b8; |
| --text-inverse: #ffffff; |
| |
| --border-color: rgba(15, 23, 42, 0.08); |
| --border-highlight: rgba(14, 165, 233, 0.4); |
| |
| --primary: #0284c7; |
| --primary-glow: rgba(2, 132, 199, 0.2); |
| --secondary: #6366f1; |
| --accent-green: #059669; |
| --accent-amber: #d97706; |
| --accent-rose: #e11d48; |
| --accent-purple: #9333ea; |
| } |
| } |
| |
| :root[data-theme="light"] { |
| --bg-primary: #f8fafc; |
| --bg-secondary: #ffffff; |
| --bg-card: rgba(255, 255, 255, 0.85); |
| --bg-card-hover: #f1f5f9; |
| --bg-input: #f8fafc; |
| |
| --text-primary: #0f172a; |
| --text-secondary: #475569; |
| --text-muted: #94a3b8; |
| --text-inverse: #ffffff; |
| |
| --border-color: rgba(15, 23, 42, 0.08); |
| --border-highlight: rgba(14, 165, 233, 0.4); |
| |
| --primary: #0284c7; |
| --primary-glow: rgba(2, 132, 199, 0.2); |
| --secondary: #6366f1; |
| --accent-green: #059669; |
| --accent-amber: #d97706; |
| --accent-rose: #e11d48; |
| --accent-purple: #9333ea; |
| } |
| |
| :root[data-theme="dark"] { |
| --bg-primary: #0f172a; |
| --bg-secondary: #1e293b; |
| --bg-card: rgba(30, 41, 59, 0.7); |
| --bg-card-hover: rgba(51, 65, 85, 0.8); |
| --bg-input: #0f172a; |
| |
| --text-primary: #f8fafc; |
| --text-secondary: #94a3b8; |
| --text-muted: #64748b; |
| --text-inverse: #0f172a; |
| |
| --border-color: rgba(255, 255, 255, 0.08); |
| --border-highlight: rgba(56, 189, 248, 0.3); |
| |
| --primary: #38bdf8; |
| --primary-glow: rgba(56, 189, 248, 0.25); |
| --secondary: #818cf8; |
| --accent-green: #34d399; |
| --accent-amber: #fbbf24; |
| --accent-rose: #f43f5e; |
| --accent-purple: #c084fc; |
| } |
| |
| * { |
| box-sizing: border-box; |
| margin: 0; |
| padding: 0; |
| } |
| |
| body { |
| font-family: var(--font-sans); |
| background-color: var(--bg-primary); |
| color: var(--text-primary); |
| line-height: 1.5; |
| padding: 24px 16px; |
| display: flex; |
| justify-content: center; |
| -webkit-font-smoothing: antialiased; |
| } |
| |
| .container { |
| width: 100%; |
| max-width: 1080px; |
| display: flex; |
| flex-direction: column; |
| gap: 20px; |
| } |
| |
| |
| .glass-panel { |
| background: var(--bg-card); |
| backdrop-filter: blur(12px); |
| -webkit-backdrop-filter: blur(12px); |
| border: 1px solid var(--border-color); |
| border-radius: var(--radius-lg); |
| padding: 20px 24px; |
| box-shadow: var(--shadow-subtle); |
| transition: border-color 0.2s ease, box-shadow 0.2s ease; |
| } |
| |
| |
| .header-bar { |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| flex-wrap: wrap; |
| gap: 16px; |
| } |
| |
| .brand-section { |
| display: flex; |
| flex-direction: column; |
| gap: 4px; |
| } |
| |
| .tagline { |
| display: inline-flex; |
| align-items: center; |
| gap: 6px; |
| font-size: 11px; |
| font-weight: 700; |
| text-transform: uppercase; |
| letter-spacing: 0.08em; |
| color: var(--primary); |
| } |
| |
| .tagline-dot { |
| width: 7px; |
| height: 7px; |
| border-radius: var(--radius-full); |
| background-color: var(--accent-green); |
| box-shadow: 0 0 8px var(--accent-green); |
| animation: pulse-dot 2s infinite; |
| } |
| |
| @keyframes pulse-dot { |
| 0%, 100% { transform: scale(1); opacity: 1; } |
| 50% { transform: scale(1.3); opacity: 0.7; } |
| } |
| |
| .main-title { |
| font-size: 24px; |
| font-weight: 800; |
| letter-spacing: -0.02em; |
| background: linear-gradient(135deg, var(--text-primary) 30%, var(--primary) 100%); |
| -webkit-background-clip: text; |
| -webkit-text-fill-color: transparent; |
| } |
| |
| .theme-toggle-group { |
| display: flex; |
| align-items: center; |
| gap: 10px; |
| } |
| |
| |
| .track-selector { |
| display: grid; |
| grid-template-columns: repeat(3, 1fr); |
| gap: 10px; |
| background: rgba(0, 0, 0, 0.15); |
| padding: 6px; |
| border-radius: var(--radius-lg); |
| border: 1px solid var(--border-color); |
| } |
| |
| .track-btn { |
| display: flex; |
| align-items: center; |
| gap: 10px; |
| padding: 10px 14px; |
| background: transparent; |
| border: 1px solid transparent; |
| border-radius: var(--radius-md); |
| color: var(--text-secondary); |
| font-family: inherit; |
| font-size: 13px; |
| font-weight: 600; |
| cursor: pointer; |
| transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); |
| text-align: left; |
| } |
| |
| .track-btn:hover { |
| background: var(--bg-card-hover); |
| color: var(--text-primary); |
| } |
| |
| .track-btn.active { |
| background: var(--bg-secondary); |
| color: var(--text-primary); |
| border-color: var(--border-highlight); |
| box-shadow: var(--shadow-subtle), 0 0 0 1px var(--primary-glow); |
| } |
| |
| .track-btn .track-icon { |
| font-size: 18px; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| } |
| |
| .track-meta { |
| display: flex; |
| flex-direction: column; |
| } |
| |
| .track-name { |
| font-weight: 700; |
| font-size: 13px; |
| } |
| |
| .track-desc { |
| font-size: 11px; |
| color: var(--text-muted); |
| font-weight: 400; |
| } |
| |
| |
| .stepper-container { |
| display: flex; |
| flex-direction: column; |
| gap: 10px; |
| } |
| |
| .stepper-nav { |
| display: flex; |
| align-items: center; |
| justify-content: space-between; |
| gap: 6px; |
| overflow-x: auto; |
| padding-bottom: 6px; |
| scrollbar-width: none; |
| } |
| .stepper-nav::-webkit-scrollbar { display: none; } |
| |
| .step-node { |
| flex: 1; |
| min-width: 105px; |
| display: flex; |
| flex-direction: column; |
| align-items: center; |
| gap: 6px; |
| padding: 8px 6px; |
| background: transparent; |
| border: 1px solid transparent; |
| border-radius: var(--radius-md); |
| cursor: pointer; |
| transition: all 0.2s ease; |
| position: relative; |
| } |
| |
| .step-node:hover { |
| background: var(--bg-card-hover); |
| } |
| |
| .step-node.active { |
| background: rgba(56, 189, 248, 0.08); |
| border-color: var(--border-highlight); |
| } |
| |
| .step-pill { |
| width: 24px; |
| height: 24px; |
| border-radius: var(--radius-full); |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| font-size: 11px; |
| font-weight: 700; |
| background: var(--bg-secondary); |
| color: var(--text-muted); |
| border: 1px solid var(--border-color); |
| transition: all 0.2s ease; |
| } |
| |
| .step-node.completed .step-pill { |
| background: var(--accent-green); |
| color: #ffffff; |
| border-color: var(--accent-green); |
| } |
| |
| .step-node.active .step-pill { |
| background: var(--primary); |
| color: var(--text-inverse); |
| border-color: var(--primary); |
| box-shadow: 0 0 12px var(--primary-glow); |
| } |
| |
| .step-label { |
| font-size: 11px; |
| font-weight: 600; |
| color: var(--text-muted); |
| white-space: nowrap; |
| transition: color 0.2s ease; |
| } |
| |
| .step-node.active .step-label { |
| color: var(--primary); |
| font-weight: 700; |
| } |
| |
| .step-node.completed .step-label { |
| color: var(--text-secondary); |
| } |
| |
| |
| .orchestrator-banner { |
| background: linear-gradient(135deg, rgba(99, 102, 241, 0.12) 0%, rgba(56, 189, 248, 0.08) 100%); |
| border: 1px solid rgba(129, 140, 248, 0.25); |
| border-radius: var(--radius-md); |
| padding: 14px 18px; |
| display: flex; |
| flex-direction: column; |
| gap: 10px; |
| position: relative; |
| overflow: hidden; |
| } |
| |
| .orchestrator-banner::before { |
| content: ""; |
| position: absolute; |
| top: 0; |
| left: 0; |
| width: 3px; |
| height: 100%; |
| background: linear-gradient(180deg, var(--secondary), var(--primary)); |
| } |
| |
| .orchestrator-header { |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| flex-wrap: wrap; |
| gap: 8px; |
| } |
| |
| .agent-identity { |
| display: flex; |
| align-items: center; |
| gap: 8px; |
| font-weight: 700; |
| font-size: 13px; |
| color: var(--text-primary); |
| } |
| |
| .agent-badge { |
| font-size: 10px; |
| padding: 2px 8px; |
| border-radius: var(--radius-full); |
| background: rgba(129, 140, 248, 0.2); |
| color: var(--secondary); |
| font-weight: 700; |
| letter-spacing: 0.04em; |
| } |
| |
| .orchestrator-spans { |
| display: grid; |
| grid-template-columns: repeat(3, 1fr); |
| gap: 8px; |
| } |
| |
| .span-pill { |
| padding: 6px 10px; |
| font-size: 11px; |
| border-radius: var(--radius-sm); |
| background: rgba(0, 0, 0, 0.15); |
| border: 1px solid var(--border-color); |
| color: var(--text-secondary); |
| text-align: center; |
| font-weight: 500; |
| transition: all 0.2s ease; |
| } |
| |
| .span-pill.current { |
| background: rgba(56, 189, 248, 0.15); |
| border-color: var(--border-highlight); |
| color: var(--primary); |
| font-weight: 700; |
| } |
| |
| |
| .stage-hero { |
| display: flex; |
| flex-direction: column; |
| gap: 16px; |
| } |
| |
| .stage-title-wrap { |
| display: flex; |
| justify-content: space-between; |
| align-items: flex-start; |
| flex-wrap: wrap; |
| gap: 10px; |
| } |
| |
| .stage-title-main { |
| font-size: 18px; |
| font-weight: 700; |
| color: var(--text-primary); |
| } |
| |
| .stage-category-badge { |
| font-size: 11px; |
| padding: 4px 10px; |
| border-radius: var(--radius-full); |
| font-weight: 700; |
| text-transform: uppercase; |
| letter-spacing: 0.05em; |
| background: rgba(56, 189, 248, 0.12); |
| color: var(--primary); |
| border: 1px solid var(--border-highlight); |
| } |
| |
| .flow-scene { |
| display: grid; |
| grid-template-columns: 1fr 40px 1.2fr 40px 1fr; |
| align-items: center; |
| gap: 8px; |
| background: var(--bg-secondary); |
| padding: 20px 16px; |
| border-radius: var(--radius-lg); |
| border: 1px solid var(--border-color); |
| position: relative; |
| } |
| |
| .flow-card { |
| display: flex; |
| flex-direction: column; |
| gap: 8px; |
| background: var(--bg-card); |
| padding: 14px; |
| border-radius: var(--radius-md); |
| border: 1px solid var(--border-color); |
| min-height: 120px; |
| justify-content: center; |
| transition: transform 0.2s ease, border-color 0.2s ease; |
| } |
| |
| .flow-card:hover { |
| transform: translateY(-2px); |
| border-color: var(--border-highlight); |
| } |
| |
| .flow-card.center-actor { |
| background: linear-gradient(135deg, rgba(56, 189, 248, 0.1) 0%, rgba(99, 102, 241, 0.1) 100%); |
| border-color: var(--border-highlight); |
| box-shadow: 0 4px 20px -2px rgba(56, 189, 248, 0.15); |
| } |
| |
| .card-role-tag { |
| font-size: 10px; |
| font-weight: 700; |
| text-transform: uppercase; |
| letter-spacing: 0.06em; |
| color: var(--text-muted); |
| } |
| |
| .center-actor .card-role-tag { |
| color: var(--primary); |
| } |
| |
| .card-main-text { |
| font-size: 13px; |
| font-weight: 700; |
| color: var(--text-primary); |
| line-height: 1.4; |
| } |
| |
| .center-actor .card-main-text { |
| font-size: 15px; |
| background: linear-gradient(135deg, #38bdf8, #818cf8); |
| -webkit-background-clip: text; |
| -webkit-text-fill-color: transparent; |
| } |
| |
| .card-sub-text { |
| font-size: 11px; |
| color: var(--text-secondary); |
| } |
| |
| .flow-connector { |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| position: relative; |
| height: 100%; |
| } |
| |
| .connector-line { |
| width: 100%; |
| height: 2px; |
| background: var(--border-color); |
| position: relative; |
| } |
| |
| .connector-pulse { |
| position: absolute; |
| top: 50%; |
| left: 0; |
| width: 8px; |
| height: 8px; |
| border-radius: var(--radius-full); |
| background: var(--primary); |
| box-shadow: 0 0 10px var(--primary); |
| transform: translateY(-50%); |
| animation: flow-pulse 1.8s infinite cubic-bezier(0.4, 0, 0.2, 1); |
| } |
| |
| .flow-connector:nth-child(4) .connector-pulse { |
| animation-delay: 0.9s; |
| } |
| |
| @keyframes flow-pulse { |
| 0% { left: 0%; opacity: 0; transform: translateY(-50%) scale(0.6); } |
| 20% { opacity: 1; transform: translateY(-50%) scale(1.1); } |
| 80% { opacity: 1; transform: translateY(-50%) scale(1.1); } |
| 100% { left: 100%; opacity: 0; transform: translateY(-50%) scale(0.6); } |
| } |
| |
| |
| .viewer-tabs { |
| display: flex; |
| gap: 8px; |
| border-bottom: 1px solid var(--border-color); |
| padding-bottom: 12px; |
| margin-top: 4px; |
| } |
| |
| .viewer-tab-btn { |
| padding: 6px 14px; |
| background: transparent; |
| border: 1px solid transparent; |
| border-radius: var(--radius-sm); |
| color: var(--text-secondary); |
| font-size: 12px; |
| font-weight: 600; |
| cursor: pointer; |
| transition: all 0.2s ease; |
| } |
| |
| .viewer-tab-btn:hover { |
| color: var(--text-primary); |
| background: var(--bg-card-hover); |
| } |
| |
| .viewer-tab-btn.active { |
| color: var(--primary); |
| background: rgba(56, 189, 248, 0.1); |
| border-color: var(--border-highlight); |
| } |
| |
| .tab-content-panel { |
| display: flex; |
| flex-direction: column; |
| gap: 14px; |
| } |
| |
| .narrative-box { |
| background: rgba(0, 0, 0, 0.15); |
| border-radius: var(--radius-md); |
| padding: 14px 16px; |
| border: 1px solid var(--border-color); |
| font-size: 13px; |
| color: var(--text-secondary); |
| line-height: 1.6; |
| } |
| |
| .narrative-box strong { |
| color: var(--text-primary); |
| } |
| |
| .example-callout { |
| display: flex; |
| align-items: flex-start; |
| gap: 10px; |
| background: rgba(56, 189, 248, 0.05); |
| border-left: 3px solid var(--primary); |
| padding: 10px 14px; |
| border-radius: 0 var(--radius-sm) var(--radius-sm) 0; |
| font-size: 12px; |
| color: var(--text-secondary); |
| } |
| |
| .example-icon { |
| color: var(--primary); |
| font-weight: bold; |
| } |
| |
| |
| .code-inspector { |
| background: #090d16; |
| border-radius: var(--radius-md); |
| border: 1px solid var(--border-color); |
| overflow: hidden; |
| font-family: var(--font-mono); |
| font-size: 12px; |
| } |
| |
| .code-header { |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| padding: 8px 14px; |
| background: rgba(255, 255, 255, 0.03); |
| border-bottom: 1px solid var(--border-color); |
| color: var(--text-muted); |
| font-size: 11px; |
| } |
| |
| .code-content { |
| padding: 14px; |
| color: #e2e8f0; |
| line-height: 1.6; |
| overflow-x: auto; |
| white-space: pre; |
| } |
| |
| .code-content .kw { color: #f472b6; } |
| .code-content .fn { color: #60a5fa; } |
| .code-content .str { color: #34d399; } |
| .code-content .num { color: #fbbf24; } |
| .code-content .cm { color: #64748b; font-style: italic; } |
| .code-content .diff-add { color: #34d399; background: rgba(52, 211, 153, 0.1); display: block; } |
| .code-content .diff-del { color: #f43f5e; background: rgba(244, 63, 94, 0.1); display: block; } |
| |
| |
| .sandbox-card { |
| background: rgba(15, 23, 42, 0.6); |
| border: 1px solid var(--border-highlight); |
| border-radius: var(--radius-md); |
| padding: 16px; |
| display: flex; |
| flex-direction: column; |
| gap: 12px; |
| } |
| |
| .sandbox-title { |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| font-size: 13px; |
| font-weight: 700; |
| color: var(--text-primary); |
| } |
| |
| .interactive-table { |
| width: 100%; |
| border-collapse: collapse; |
| font-size: 12px; |
| text-align: left; |
| } |
| |
| .interactive-table th, .interactive-table td { |
| padding: 8px 12px; |
| border-bottom: 1px solid var(--border-color); |
| } |
| |
| .interactive-table th { |
| color: var(--text-muted); |
| font-weight: 600; |
| text-transform: uppercase; |
| font-size: 10px; |
| letter-spacing: 0.05em; |
| } |
| |
| .status-badge { |
| display: inline-flex; |
| align-items: center; |
| gap: 4px; |
| padding: 2px 8px; |
| border-radius: var(--radius-full); |
| font-size: 11px; |
| font-weight: 600; |
| } |
| |
| .status-badge.match { |
| background: rgba(52, 211, 153, 0.15); |
| color: var(--accent-green); |
| border: 1px solid rgba(52, 211, 153, 0.3); |
| } |
| |
| .status-badge.mismatch { |
| background: rgba(244, 63, 94, 0.15); |
| color: var(--accent-rose); |
| border: 1px solid rgba(244, 63, 94, 0.3); |
| } |
| |
| |
| .footer-bar { |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| flex-wrap: wrap; |
| gap: 12px; |
| padding-top: 10px; |
| border-top: 1px solid var(--border-color); |
| } |
| |
| .btn-group { |
| display: flex; |
| align-items: center; |
| gap: 8px; |
| } |
| |
| .btn { |
| display: inline-flex; |
| align-items: center; |
| justify-content: center; |
| gap: 6px; |
| padding: 8px 16px; |
| font-family: inherit; |
| font-size: 13px; |
| font-weight: 600; |
| border-radius: var(--radius-md); |
| cursor: pointer; |
| transition: all 0.2s ease; |
| border: 1px solid var(--border-color); |
| background: var(--bg-secondary); |
| color: var(--text-primary); |
| user-select: none; |
| } |
| |
| .btn:hover:not(:disabled) { |
| background: var(--bg-card-hover); |
| border-color: var(--border-highlight); |
| } |
| |
| .btn:disabled { |
| opacity: 0.4; |
| cursor: not-allowed; |
| } |
| |
| .btn-primary { |
| background: var(--primary); |
| color: var(--text-inverse); |
| border-color: var(--primary); |
| box-shadow: 0 0 15px var(--primary-glow); |
| } |
| |
| .btn-primary:hover:not(:disabled) { |
| background: #0284c7; |
| border-color: #0284c7; |
| } |
| |
| .btn-ghost { |
| background: transparent; |
| border-color: transparent; |
| color: var(--text-secondary); |
| } |
| |
| .btn-ghost:hover:not(:disabled) { |
| color: var(--text-primary); |
| background: rgba(255, 255, 255, 0.05); |
| } |
| |
| .source-credit { |
| font-size: 11px; |
| color: var(--text-muted); |
| } |
| |
| |
| @media (max-width: 768px) { |
| .track-selector { |
| grid-template-columns: 1fr; |
| } |
| .flow-scene { |
| grid-template-columns: 1fr; |
| gap: 12px; |
| } |
| .flow-connector { |
| height: 30px; |
| transform: rotate(90deg); |
| } |
| .orchestrator-spans { |
| grid-template-columns: 1fr; |
| } |
| .header-bar, .footer-bar { |
| flex-direction: column; |
| align-items: stretch; |
| } |
| } |
| </style> |
| </head> |
| <body> |
|
|
| <div class="container"> |
| |
| |
| <div class="glass-panel header-bar"> |
| <div class="brand-section"> |
| <div class="tagline"> |
| <span class="tagline-dot"></span> |
| <span>Google Cloud Modernization Framework</span> |
| </div> |
| <h1 class="main-title">Modernization Guided Walkthrough</h1> |
| </div> |
| |
| <div class="theme-toggle-group"> |
| <span class="status-badge match" id="step-counter">Step 1 of 6</span> |
| <button type="button" class="btn btn-ghost" id="theme-btn" title="Toggle Theme">🌓 Theme</button> |
| </div> |
| </div> |
|
|
| |
| <div class="track-selector" role="tablist" aria-label="Modernization Pathways"> |
| <button type="button" class="track-btn" data-track="mainframe" id="tab-mainframe"> |
| <span class="track-icon">🏛️</span> |
| <div class="track-meta"> |
| <span class="track-name">Mainframe Pathway</span> |
| <span class="track-desc">COBOL · Claims Engine · Dual Run</span> |
| </div> |
| </button> |
| |
| <button type="button" class="track-btn active" data-track="app" id="tab-app"> |
| <span class="track-icon">⚡</span> |
| <div class="track-meta"> |
| <span class="track-name">Application Pathway</span> |
| <span class="track-desc">.NET / Java · CodMod · Cloud Run</span> |
| </div> |
| </button> |
| |
| <button type="button" class="track-btn" data-track="data" id="tab-data"> |
| <span class="track-icon">🗄️</span> |
| <div class="track-meta"> |
| <span class="track-name">Database Pathway</span> |
| <span class="track-desc">SQL Server / Oracle · DMS · AlloyDB</span> |
| </div> |
| </button> |
| </div> |
|
|
| |
| <div class="glass-panel stepper-container"> |
| <div class="stepper-nav" id="stepper-nav" role="navigation" aria-label="Step progress"> |
| |
| </div> |
| </div> |
|
|
| |
| <div class="orchestrator-banner" id="orchestrator-box"> |
| <div class="orchestrator-header"> |
| <div class="agent-identity"> |
| <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="color:var(--secondary)"><circle cx="12" cy="12" r="3"></circle><circle cx="19" cy="5" r="2"></circle><circle cx="5" cy="19" r="2"></circle><path d="M10.4 21.9a10 10 0 0 0 9.9-9.9"></path><path d="M13.6 2.1a10 10 0 0 0-9.9 9.9"></path></svg> |
| <span>Antigravity Orchestration Layer</span> |
| <span class="agent-badge">Agentic Control Plane</span> |
| </div> |
| <span id="agent-active-skill" class="status-badge match">Active Skill: codmod-analyzer</span> |
| </div> |
| |
| <div class="orchestrator-spans"> |
| <div class="span-pill" id="span-plan">1. Discovery & Planning</div> |
| <div class="span-pill" id="span-transform">2. Autonomous Transformation</div> |
| <div class="span-pill" id="span-validate">3. Continuous Validation</div> |
| </div> |
| <div style="font-size: 11px; color: var(--text-secondary);" id="agent-detail-text"> |
| Antigravity orchestrates end-to-end task decomposition, skill invocation, and feedback loops across codebase transformations. |
| </div> |
| </div> |
|
|
| |
| <div class="glass-panel stage-hero"> |
| <div class="stage-title-wrap"> |
| <div> |
| <div style="font-size: 11px; color: var(--text-muted); text-transform: uppercase; font-weight: 700; letter-spacing: 0.05em;" id="stage-step-num">Step 1</div> |
| <h2 class="stage-title-main" id="stage-heading">Assess · CodMod Application Advisor</h2> |
| </div> |
| <span class="stage-category-badge" id="stage-badge">Application Assessment</span> |
| </div> |
|
|
| |
| <div class="flow-scene" id="flow-scene"> |
| <div class="flow-card"> |
| <span class="card-role-tag">1. Input Context</span> |
| <div class="card-main-text" id="flow-input-title">Portal source code</div> |
| <div class="card-sub-text" id="flow-input-sub">Legacy repo & dependencies</div> |
| </div> |
|
|
| <div class="flow-connector"> |
| <div class="connector-line"></div> |
| <div class="connector-pulse"></div> |
| </div> |
|
|
| <div class="flow-card center-actor"> |
| <span class="card-role-tag" id="flow-actor-role">Active Engine</span> |
| <div class="card-main-text" id="flow-actor-title">CodMod Modernization Advisor</div> |
| <div class="card-sub-text" id="flow-actor-sub">Rule parsing & target blueprints</div> |
| </div> |
|
|
| <div class="flow-connector"> |
| <div class="connector-line"></div> |
| <div class="connector-pulse"></div> |
| </div> |
|
|
| <div class="flow-card"> |
| <span class="card-role-tag">3. Generated Artifact</span> |
| <div class="card-main-text" id="flow-output-title">Modernization Blueprint</div> |
| <div class="card-sub-text" id="flow-output-sub">Ordered task plan & APIs</div> |
| </div> |
| </div> |
|
|
| |
| <div class="viewer-tabs"> |
| <button type="button" class="viewer-tab-btn active" data-vtab="narrative">Overview & Architecture</button> |
| <button type="button" class="viewer-tab-btn" data-vtab="code">Artifact / Code Inspection</button> |
| <button type="button" class="viewer-tab-btn" data-vtab="sandbox" id="tab-btn-sandbox">Interactive Simulator</button> |
| </div> |
|
|
| |
| <div class="tab-content-panel" id="panel-narrative"> |
| <div class="narrative-box" id="narrative-text"> |
| CodMod analyzes the monolithic .NET Framework / Java code structure, identifying obsolete API usages, tight coupling to Windows-specific libraries, and external connection strings. |
| </div> |
| <div class="example-callout"> |
| <span class="example-icon">💡</span> |
| <span id="example-text">Example: Identify legacy WCF endpoints and SQL Server connections requiring conversion to REST and AlloyDB.</span> |
| </div> |
| </div> |
|
|
| |
| <div class="tab-content-panel" id="panel-code" style="display: none;"> |
| <div class="code-inspector"> |
| <div class="code-header"> |
| <span id="code-filename">modernization-spec.yaml</span> |
| <span id="code-lang-tag">YAML / SPEC</span> |
| </div> |
| <div class="code-content" id="code-view-content"></div> |
| </div> |
| </div> |
|
|
| |
| <div class="tab-content-panel" id="panel-sandbox" style="display: none;"> |
| <div class="sandbox-card" id="sandbox-container"> |
| |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="glass-panel footer-bar"> |
| <div class="btn-group"> |
| <button type="button" class="btn" id="btn-prev">← Previous</button> |
| <button type="button" class="btn btn-primary" id="btn-next">Next Step →</button> |
| <button type="button" class="btn btn-ghost" id="btn-autoplay">▶ Auto-Play</button> |
| </div> |
|
|
| <div class="source-credit" id="source-citation"> |
| Source: Google Cloud Modernization Framework (Slides 14–21) |
| </div> |
| </div> |
|
|
| </div> |
|
|
| <script> |
| (() => { |
| // Model Data for Modernization Pathways |
| const pathways = { |
| mainframe: { |
| name: "Mainframe Pathway", |
| steps: [ |
| { |
| phase: "Discover", |
| actor: "Modernize Hub", |
| role: "ESTATE DISCOVERY", |
| input: "Mainframe Core Estate", |
| inputSub: "COBOL, JCL, CICS, VSAM / DB2", |
| output: "Candidate Workload Assessment", |
| outputSub: "Priority score & dependency graph", |
| detail: "Modernize Hub inventories legacy mainframe workloads, analyzes code volume, transactions per second, and recommends starting with bounded batch or claims calculation routines.", |
| example: "Identify the high-volume claims pricing and deduction engine as candidate #1 for containerized rewrite.", |
| skill: "estate-inventory-scanner", |
| span: "plan", |
| slide: "4–5", |
| codeFile: "estate-inventory.json", |
| codeLang: "JSON", |
| codeSnippet: `{\n <span class="str">"workload"</span>: <span class="str">"CLAIMS_PRICING_ENGINE"</span>,\n <span class="str">"linesOfCode"</span>: <span class="num">142850</span>,\n <span class="str">"subroutines"</span>: [<span class="str">"CLM9000"</span>, <span class="str">"CLM9001"</span>, <span class="str">"POL_VALIDATE"</span>],\n <span class="str">"complexity"</span>: <span class="str">"HIGH"</span>,\n <span class="str">"targetRecommendation"</span>: <span class="str">"Cloud Run / Go Microservice"</span>\n}`, |
| sandboxType: "none" |
| }, |
| { |
| phase: "Assess", |
| actor: "MAT (Mainframe Assessment Tool)", |
| role: "BUSINESS RULE EXTRACTION", |
| input: "Legacy COBOL Source Code", |
| inputSub: "COPYBOOKs & Procedural Logic", |
| output: "Parsed Business Logic Rules", |
| outputSub: "Rule definitions & edge condition matrix", |
| detail: "MAT parses legacy COBOL statements (EVALUATE, COMPUTE, PERFORM) and extracts strict business logic, removing hardware-tied assembler details.", |
| example: "Extract rule determining deductible waiver on catastrophic threshold limits exceeding $10,000.", |
| skill: "cobol-rule-extractor", |
| span: "plan", |
| slide: "6–7", |
| codeFile: "CLM9000.CBL", |
| codeLang: "COBOL", |
| codeSnippet: `<span class="cm">* EXTRACTED FROM LEGACY CLAIMS CORE</span>\n<span class="kw">IDENTIFICATION DIVISION</span>.\n<span class="kw">PROGRAM-ID</span>. CLM9000.\n<span class="kw">PROCEDURE DIVISION</span>.\n <span class="kw">IF</span> CLAIM-AMOUNT > 10000 <span class="kw">AND</span> POLICY-TIER = <span class="str">'PLATINUM'</span>\n <span class="kw">MOVE</span> 0 <span class="kw">TO</span> DEDUCTIBLE-DUE\n <span class="kw">ELSE</span>\n <span class="kw">COMPUTE</span> DEDUCTIBLE-DUE = CLAIM-AMOUNT * 0.10\n <span class="kw">END-IF</span>.`, |
| sandboxType: "none" |
| }, |
| { |
| phase: "Specify", |
| actor: "Mainframe Agents", |
| role: "PRD & SPECIFICATION", |
| input: "Extracted Business Logic", |
| inputSub: "Decision tables & data dictionaries", |
| output: "Modern PRD & Acceptance Tests", |
| outputSub: "Gherkin feature files & OpenAPI schema", |
| detail: "Mainframe agents transform raw business rules into unambiguous requirements, OpenAPI 3.1 contracts, and executable test specifications for modern engineering teams.", |
| example: "Convert COBOL decimal arithmetic quirks into IEEE floating-point / BigNumber decimal precision specs.", |
| skill: "spec-generator", |
| span: "plan", |
| slide: "7", |
| codeFile: "claims-calculation.feature", |
| codeLang: "Gherkin / Spec", |
| codeSnippet: `<span class="kw">Feature</span>: Claims Deductible Calculation\n\n <span class="kw">Scenario Outline</span>: Evaluate deductible for policy tiers\n <span class="kw">Given</span> a policy with tier <span class="str">"<tier>"</span>\n <span class="kw">When</span> claim amount is <span class="num"><amount></span>\n <span class="kw">Then</span> the deductible due should be <span class="num"><deductible></span>\n\n <span class="kw">Examples</span>:\n | tier | amount | deductible |\n | STANDARD | 900 | 90 |\n | PLATINUM | 12000 | 0 |`, |
| sandboxType: "none" |
| }, |
| { |
| phase: "Rewrite", |
| actor: "Gemini CLI + Agents", |
| role: "CODE TRANSFORMATION", |
| input: "PRD & Cloud Architecture", |
| inputSub: "Spring Boot / Go target guidelines", |
| output: "Modern Microservice Code", |
| outputSub: "Idiomatic service & unit test suites", |
| detail: "Gemini CLI orchestrated with specialized modernization skills generates clean, cloud-native microservices matching legacy calculations with 100% precision.", |
| example: "Generate a Java 21 / Spring Boot service with BigInteger arithmetic for high-speed claims adjudication.", |
| skill: "cloud-code-transformer", |
| span: "transform", |
| slide: "6–7", |
| codeFile: "ClaimsEngineService.java", |
| codeLang: "Java", |
| codeSnippet: `<span class="kw">public class</span> <span class="fn">ClaimsEngineService</span> {\n <span class="kw">public</span> BigDecimal <span class="fn">calculateDeductible</span>(Claim claim) {\n <span class="kw">if</span> (claim.amount().compareTo(BigDecimal.valueOf(10000)) > 0 \n && claim.policy().isPlatinum()) {\n <span class="kw">return</span> BigDecimal.ZERO;\n }\n <span class="kw">return</span> claim.amount().multiply(BigDecimal.valueOf(0.10));\n }\n}`, |
| sandboxType: "none" |
| }, |
| { |
| phase: "Move Data", |
| actor: "Mainframe Connector", |
| role: "PARALLEL DATA STREAMING", |
| input: "Mainframe VSAM / DB2 EBCDIC", |
| inputSub: "Packed decimal records", |
| output: "BigQuery / AlloyDB Data Store", |
| outputSub: "UTF-8 partitioned data lake", |
| detail: "Mainframe Connector streams and converts mainframe datasets directly into Google Cloud storage without exhausting mainframe MIPS or locking operational tables.", |
| example: "Stream 50 million historical claims records into BigQuery for analytics and AlloyDB for real-time lookups.", |
| skill: "mainframe-data-streamer", |
| span: "transform", |
| slide: "6–7", |
| codeFile: "connector-job.yaml", |
| codeLang: "YAML", |
| codeSnippet: `apiVersion: <span class="str">mainframe.google.com/v1</span>\nkind: <span class="fn">DataTransferJob</span>\nspec:\n source:\n dataset: <span class="str">"PROD.CLAIMS.VSAM.HIST"</span>\n ebcdicEncoding: <span class="str">"IBM-037"</span>\n target:\n alloyDbInstance: <span class="str">"claims-core-primary"</span>\n table: <span class="str">"claims_historical"</span>`, |
| sandboxType: "none" |
| }, |
| { |
| phase: "Compare", |
| actor: "Dual Run", |
| role: "EQUIVALENCE TESTING", |
| input: "Live Workload Input Feeds", |
| inputSub: "Mirrored production transactions", |
| output: "Equivalence Audit Report", |
| outputSub: "Diff telemetry & edge-case fixes", |
| detail: "Dual Run sends identical transaction streams in parallel to both the Mainframe and the Google Cloud application, verifying bit-for-bit parity under live volume.", |
| example: "Catch a boundary condition discrepancy where zero-dollar claims were handled differently in the modern rewrite.", |
| skill: "dual-run-verifier", |
| span: "validate", |
| slide: "7–8", |
| codeFile: "dual-run-report.json", |
| codeLang: "JSON", |
| codeSnippet: `{\n <span class="str">"totalReplayed"</span>: <span class="num">250000</span>,\n <span class="str">"matches"</span>: <span class="num">249999</span>,\n <span class="str">"discrepancies"</span>: <span class="num">1</span>,\n <span class="str">"status"</span>: <span class="str">"ACTION_REQUIRED"</span>\n}`, |
| sandboxType: "dualrun" |
| }, |
| { |
| phase: "Deliver", |
| actor: "Modern Cloud Native App", |
| role: "PRODUCTION CUTOVER", |
| input: "Validated App + Replicated Data", |
| inputSub: "100% equivalence verified", |
| output: "Target Cloud Service on GCP", |
| outputSub: "Auto-scaling Cloud Run & AlloyDB", |
| detail: "With zero divergence proven via Dual Run, the traffic router cuts over production traffic to Google Cloud, allowing progressive mainframe decommissioning.", |
| example: "Decommission 450 mainframe MIPS while improving peak claims calculation latency from 450ms to 24ms.", |
| skill: "production-cutover-manager", |
| span: "validate", |
| slide: "7–8", |
| codeFile: "cutover-status.json", |
| codeLang: "JSON", |
| codeSnippet: `{\n <span class="str">"trafficDistribution"</span>: { <span class="str">"googleCloud"</span>: <span class="num">1.00</span>, <span class="str">"mainframe"</span>: <span class="num">0.00</span> },\n <span class="str">"slaCompliance"</span>: <span class="str">"99.999%"</span>,\n <span class="str">"costReduction"</span>: <span class="str">"68% MIPS savings"</span>\n}`, |
| sandboxType: "none" |
| } |
| ] |
| }, |
| app: { |
| name: "Application Pathway", |
| steps: [ |
| { |
| phase: "Discover", |
| actor: "Modernize Hub", |
| role: "PORTFOLIO DISCOVERY", |
| input: "Enterprise Application Repos", |
| inputSub: ".NET Framework & Java monoliths", |
| output: "Modernization Suitability Score", |
| outputSub: "Target container readiness", |
| detail: "Modernize Hub scans the application portfolio, cataloging framework versions (e.g. .NET Framework 4.7, Java 8, WebLogic) and architectural dependencies.", |
| example: "Flag customer portal monolith with 12 IIS-dependent services ready for containerization.", |
| skill: "app-portfolio-analyzer", |
| span: "plan", |
| slide: "4–5", |
| codeFile: "portfolio-scan.json", |
| codeLang: "JSON", |
| codeSnippet: `{\n <span class="str">"app"</span>: <span class="str">"CustomerPortal.Web"</span>,\n <span class="str">"framework"</span>: <span class="str">".NET Framework 4.8"</span>,\n <span class="str">"dependencies"</span>: [<span class="str">"System.Web"</span>, <span class="str">"WCF"</span>, <span class="str">"Windows Registry"</span>],\n <span class="str">"targetArchitecture"</span>: <span class="str">".NET 8 / Cloud Run"</span>\n}`, |
| sandboxType: "none" |
| }, |
| { |
| phase: "Assess", |
| actor: "CodMod Advisor", |
| role: "APPLICATION ASSESSMENT", |
| input: "Portal Source Code & Configs", |
| inputSub: "web.config, *.csproj, solution files", |
| output: "Target Blueprint & Dependencies", |
| outputSub: "Breaking changes & migration recipe", |
| detail: "CodMod (Application Modernization Advisor) evaluates NuGet/Maven dependencies, proprietary APIs, and constructs a step-by-step migration blueprint.", |
| example: "Identify System.Web session state dependencies needing migration to Redis / Memorystore.", |
| skill: "codmod-analyzer", |
| span: "plan", |
| slide: "17–21", |
| codeFile: "CodModReport.md", |
| codeLang: "Markdown", |
| codeSnippet: `<span class="kw"># CodMod Modernization Plan</span>\n- <span class="str">[CRITICAL]</span> Replace \`System.Web.Session\` with Redis Distributed Cache.\n- <span class="str">[UPDATE]</span> Migrate \`web.config\` appSettings to \`appsettings.json\`.\n- <span class="str">[REFACTOR]</span> Convert WCF SOAP bindings to gRPC / REST WebAPI endpoints.`, |
| sandboxType: "none" |
| }, |
| { |
| phase: "Plan", |
| actor: "Planning Agent + Skills", |
| role: "DESIGN & TASK BREAKDOWN", |
| input: "CodMod Assessment & Blueprint", |
| inputSub: "Micro-task dependency graph", |
| output: "Ordered Modernization Backlog", |
| outputSub: "Step-by-step refactoring tickets", |
| detail: "Antigravity Planning Agent creates structured transformation tickets with exact file paths, automated tests, and validation gates.", |
| example: "Sequence project upgrades: 1. Core library, 2. Auth middleware, 3. API controllers, 4. Health checks.", |
| skill: "task-planner", |
| span: "plan", |
| slide: "10, 14, 19", |
| codeFile: "migration-backlog.yaml", |
| codeLang: "YAML", |
| codeSnippet: `tasks:\n - id: <span class="str">task-01</span>\n title: <span class="str">"SDK Project File Upgrade"</span>\n target: <span class="str">"net8.0"</span>\n - id: <span class="str">task-02</span>\n title: <span class="str">"Migrate ASP.NET MVC Controllers to ASP.NET Core"</span>\n skills: [<span class="str">"dotnet-framework-to-core"</span>]`, |
| sandboxType: "none" |
| }, |
| { |
| phase: "Transform", |
| actor: "Application Agent Skills", |
| role: "CODE TRANSFORMATION", |
| input: "Legacy Code + Task Plan", |
| inputSub: "ASP.NET MVC / Java EE files", |
| output: "Modern ASP.NET Core 8 / Java 21", |
| outputSub: "Clean, cross-platform code", |
| detail: "Specialized agent skills execute code refactoring in place, replacing deprecated namespaces with modern async/await patterns and dependency injection.", |
| example: "Refactor synchronous HttpHandlers into ASP.NET Core Minimal APIs with built-in telemetry.", |
| skill: "dotnet-transform-agent", |
| span: "transform", |
| slide: "10, 14, 19", |
| codeFile: "Program.cs", |
| codeLang: "C# (.NET 8)", |
| codeSnippet: `<span class="cm">// MODERNIZED .NET 8 MINIMAL API</span>\n<span class="kw">var</span> builder = WebApplication.<span class="fn">CreateBuilder</span>(args);\nbuilder.Services.<span class="fn">AddStackExchangeRedisCache</span>(options => {\n options.Configuration = builder.Configuration[<span class="str">"Redis:Host"</span>];\n});\n\n<span class="kw">var</span> app = builder.<span class="fn">Build</span>();\napp.<span class="fn">MapGet</span>(<span class="str">"/api/claims/{id}"</span>, <span class="kw">async</span> (string id, ClaimsService svc) => \n <span class="kw">await</span> svc.<span class="fn">GetClaimAsync</span>(id));\napp.<span class="fn">Run</span>();`, |
| sandboxType: "codmod" |
| }, |
| { |
| phase: "Test", |
| actor: "Validation Agent", |
| role: "AUTOMATED TEST EXECUTION", |
| input: "Modernized Codebase", |
| inputSub: "Refactored code & unit suites", |
| output: "Test Results & Telemetry", |
| outputSub: "Code coverage & security report", |
| detail: "Validation agent runs unit, integration, and security scans (container vulnerability check) to ensure regression-free deployment.", |
| example: "Execute 1,240 automated test suites; automatically patch two broken mocked HTTP endpoints.", |
| skill: "automated-test-runner", |
| span: "validate", |
| slide: "10, 19", |
| codeFile: "test-summary.log", |
| codeLang: "Log", |
| codeSnippet: `[INFO] Running dotnet test /workspace/CustomerPortal.Tests\n[PASS] TestCustomerAuthWithClaimsBearer: PASSED (14ms)\n[PASS] TestClaimSubmissionCalculatesTotal: PASSED (22ms)\n[INFO] Test Run Successful. 1240 passed, 0 failed. Coverage: 94.2%`, |
| sandboxType: "none" |
| }, |
| { |
| phase: "Deploy", |
| actor: "Cloud Run / GKE", |
| role: "PRODUCTION DEPLOYMENT", |
| input: "Tested Container Image", |
| inputSub: "OCI Artifact Registry Image", |
| output: "Scalable Cloud Run Service", |
| outputSub: "Cloud Armor + Global Load Balancer", |
| detail: "Deploy the modernized application as serverless container instances on Cloud Run with automated scale-to-zero and zero-downtime traffic splitting.", |
| example: "Deploy to Cloud Run across us-central1 and europe-west1 with Google Cloud Armor DDoS protection.", |
| skill: "cloud-deployer", |
| span: "validate", |
| slide: "16, 21", |
| codeFile: "service.yaml", |
| codeLang: "YAML", |
| codeSnippet: `apiVersion: <span class="str">serving.knative.dev/v1</span>\nkind: <span class="fn">Service</span>\nmetadata:\n name: <span class="str">customer-portal-api</span>\nspec:\n template:\n spec:\n containers:\n - image: <span class="str">gcr.io/my-proj/customer-portal:v2.0.0</span>\n resources:\n limits:\n memory: <span class="str">512Mi</span>\n cpu: <span class="str">"1.0"</span>`, |
| sandboxType: "none" |
| } |
| ] |
| }, |
| data: { |
| name: "Database Pathway", |
| steps: [ |
| { |
| phase: "Discover", |
| actor: "Modernize Hub", |
| role: "DATABASE ESTATE SCAN", |
| input: "Enterprise Database Servers", |
| inputSub: "SQL Server 2012 / Oracle 11g instances", |
| output: "Database Assessment Summary", |
| outputSub: "Storage volume, procedures & compatibility", |
| detail: "Modernize Hub scans the relational database estate, evaluating schema complexity, proprietary PL/SQL or T-SQL constructs, and licensing liabilities.", |
| example: "Identify 14 legacy Oracle databases with proprietary stored procedures ripe for AlloyDB PostgreSQL modernization.", |
| skill: "database-estate-scanner", |
| span: "plan", |
| slide: "4, 14", |
| codeFile: "db-inventory.json", |
| codeLang: "JSON", |
| codeSnippet: `{\n <span class="str">"engine"</span>: <span class="str">"Oracle Database 11g Enterprise"</span>,\n <span class="str">"sizeGB"</span>: <span class="num">850</span>,\n <span class="str">"storedProcedures"</span>: <span class="num">142</span>,\n <span class="str">"targetEngine"</span>: <span class="str">"AlloyDB for PostgreSQL"</span>\n}`, |
| sandboxType: "none" |
| }, |
| { |
| phase: "Assess", |
| actor: "DMA (Database Migration Assessment)", |
| role: "SCHEMA COMPATIBILITY AUDIT", |
| input: "DDL & Stored Procedures", |
| inputSub: "Packages, Triggers & Dialect code", |
| output: "Compatibility Matrix Report", |
| outputSub: "Auto-convertible vs Manual effort tasks", |
| detail: "DMA evaluates proprietary SQL features, complex packages, data types, and generates an automated translation breakdown.", |
| example: "Flag Oracle NVL2, DECODE, and cursor loops for Gemini-assisted conversion to PostgreSQL dialect.", |
| skill: "dma-compatibility-analyzer", |
| span: "plan", |
| slide: "4, 14", |
| codeFile: "dma-assessment.json", |
| codeLang: "JSON", |
| codeSnippet: `{\n <span class="str">"autoConvertibleObjects"</span>: <span class="num">88.5</span>,\n <span class="str">"geminiAssistedRefactors"</span>: [<span class="str">"PKG_POLICY_UTILS"</span>, <span class="str">"SP_RENEW_CLAIM"</span>],\n <span class="str">"targetCompatibility"</span>: <span class="str">"AlloyDB PostgreSQL 15"</span>\n}`, |
| sandboxType: "none" |
| }, |
| { |
| phase: "Convert", |
| actor: "DMS + Gemini Assistance", |
| role: "SCHEMA & PROCEDURE CONVERSION", |
| input: "Source DDL & PL/SQL Code", |
| inputSub: "Oracle / T-SQL definitions", |
| output: "PostgreSQL DDL & Functions", |
| outputSub: "AlloyDB optimized schema", |
| detail: "Database Migration Service coupled with Gemini transforms proprietary stored procedures and triggers into idiomatic, performant PL/pgSQL.", |
| example: "Convert an Oracle recursive cursor into a PostgreSQL WITH RECURSIVE Common Table Expression.", |
| skill: "dms-schema-converter", |
| span: "transform", |
| slide: "12, 14", |
| codeFile: "converted_procedure.sql", |
| codeLang: "PL/pgSQL", |
| codeSnippet: `<span class="cm">-- GEMINI ASSISTED PL/PGSQL CONVERSION</span>\n<span class="kw">CREATE OR REPLACE FUNCTION</span> <span class="fn">sp_calculate_rebate</span>(p_claim_id <span class="kw">INT</span>)\n<span class="kw">RETURNS NUMERIC AS</span> $$\n<span class="kw">DECLARE</span>\n v_rebate <span class="kw">NUMERIC</span>(10,2);\n<span class="kw">BEGIN</span>\n <span class="kw">SELECT</span> COALESCE(amount * 0.05, 0)\n <span class="kw">INTO</span> v_rebate\n <span class="kw">FROM</span> claims\n <span class="kw">WHERE</span> claim_id = p_claim_id;\n \n <span class="kw">RETURN</span> v_rebate;\n<span class="kw">END</span>;\n$$ <span class="kw">LANGUAGE</span> plpgsql;`, |
| sandboxType: "dms" |
| }, |
| { |
| phase: "Migrate", |
| actor: "DMS (Database Migration Service)", |
| role: "CONTINUOUS DATA REPLICATION", |
| input: "Source Database Data", |
| inputSub: "Initial snapshot + CDC binlog stream", |
| output: "Target AlloyDB Instance", |
| outputSub: "Real-time synchronized data", |
| detail: "DMS handles initial bulk snapshot load followed by sub-second Change Data Capture (CDC) replication with zero source downtime.", |
| example: "Migrate 850GB of core policy records with continuous replication latency staying below 120ms.", |
| skill: "dms-cdc-replicator", |
| span: "transform", |
| slide: "6, 12, 14", |
| codeFile: "dms-connection-profile.yaml", |
| codeLang: "YAML", |
| codeSnippet: `apiVersion: <span class="str">datamigration.cnrm.cloud.google.com/v1beta1</span>\nkind: <span class="fn">MigrationJob</span>\nspec:\n type: <span class="str">CONTINUOUS</span>\n source: <span class="str">"oracle-onprem-prod"</span>\n destination: <span class="str">"alloydb-cluster-primary"</span>\n state: <span class="str">RUNNING_CDC</span>`, |
| sandboxType: "none" |
| }, |
| { |
| phase: "Connect", |
| actor: "Application Modernization", |
| role: "DATA ACCESS REFACTORING", |
| input: "AlloyDB Instance + Modern App", |
| inputSub: "Updated connection strings & drivers", |
| output: "Integrated Modern Stack", |
| outputSub: "Npgsql / JDBC PostgreSQL connectivity", |
| detail: "CodMod and agents update application data access layers (Entity Framework / Hibernate) from proprietary Oracle dialect to PostgreSQL dialect.", |
| example: "Update EF Core DbContext to use UseNpgsql() with AlloyDB Columnar Engine indexing.", |
| skill: "app-db-connector", |
| span: "transform", |
| slide: "21", |
| codeFile: "DbContextConfig.cs", |
| codeLang: "C#", |
| codeSnippet: `services.<span class="fn">AddDbContext</span><ClaimsDbContext>(options =>\n options.<span class="fn">UseNpgsql</span>(Configuration.<span class="fn">GetConnectionString</span>(<span class="str">"AlloyDbClaims"</span>),\n o => o.<span class="fn">UseAdminDatabase</span>(<span class="str">"postgres"</span>)));`, |
| sandboxType: "none" |
| }, |
| { |
| phase: "Validate", |
| actor: "Data Validation Framework", |
| role: "DATA INTEGRITY VERIFICATION", |
| input: "Source & Target Data Stores", |
| inputSub: "Row hashes & aggregate checksums", |
| output: "100% Data Integrity Certification", |
| outputSub: "Zero divergence audit report", |
| detail: "Automated verification pipelines validate row counts, decimal precision tolerances, and query results across source and target database instances.", |
| example: "Validate 14.8 million transaction records across 42 tables with checksum parity verified.", |
| skill: "data-checksum-verifier", |
| span: "validate", |
| slide: "12, 14, 21", |
| codeFile: "validation-summary.json", |
| codeLang: "JSON", |
| codeSnippet: `{\n <span class="str">"tablesValidated"</span>: <span class="num">42</span>,\n <span class="str">"recordsCompared"</span>: <span class="num">14820000</span>,\n <span class="str">"checksumMatchRate"</span>: <span class="num">1.00000</span>,\n <span class="str">"status"</span>: <span class="str">"VERIFIED"</span>\n}`, |
| sandboxType: "none" |
| }, |
| { |
| phase: "Deliver", |
| actor: "AlloyDB / Cloud SQL", |
| role: "MANAGED DATABASE IN PRODUCTION", |
| input: "Migrated Database on GCP", |
| inputSub: "High availability multi-zone cluster", |
| output: "Modern Cloud Database Tier", |
| outputSub: "AlloyDB with 4x faster analytics queries", |
| detail: "Switch live application connection pools to AlloyDB for PostgreSQL, leveraging automatic memory management and columnar engine acceleration.", |
| example: "Experience 4x analytical query acceleration while eliminating proprietary database licensing fees.", |
| skill: "database-promoter", |
| span: "validate", |
| slide: "12, 14", |
| codeFile: "alloydb-cluster.json", |
| codeLang: "JSON", |
| codeSnippet: `{\n <span class="str">"clusterName"</span>: <span class="str">"claims-alloydb-prod"</span>,\n <span class="str">"haStatus"</span>: <span class="str">"MULTI_ZONE_ENABLED"</span>,\n <span class="str">"columnarEngine"</span>: <span class="str">"ENABLED"</span>,\n <span class="str">"readPoolInstances"</span>: <span class="num">3</span>\n}`, |
| sandboxType: "none" |
| } |
| ] |
| } |
| }; |
| |
| // State |
| let currentTrack = "app"; |
| let currentStep = 0; |
| let currentTab = "narrative"; |
| let autoPlayTimer = null; |
| let dualRunFixed = false; |
| let dmsConverted = false; |
| |
| // DOM Elements |
| const el = id => document.getElementById(id); |
| |
| function renderStepper() { |
| const steps = pathways[currentTrack].steps; |
| const nav = el("stepper-nav"); |
| nav.innerHTML = ""; |
| |
| steps.forEach((s, idx) => { |
| const node = document.createElement("div"); |
| node.className = `step-node ${idx === currentStep ? "active" : ""} ${idx < currentStep ? "completed" : ""}`; |
| node.innerHTML = ` |
| <div class="step-pill">${idx < currentStep ? "✓" : idx + 1}</div> |
| <div class="step-label">${idx + 1}. ${s.phase}</div> |
| `; |
| node.onclick = () => { |
| currentStep = idx; |
| renderStep(); |
| }; |
| nav.appendChild(node); |
| }); |
| } |
| |
| function renderOrchestrator(stepObj) { |
| el("agent-active-skill").textContent = `Active Skill: ${stepObj.skill}`; |
| |
| // Spans |
| ["plan", "transform", "validate"].forEach(span => { |
| const pill = el(`span-${span}`); |
| if (stepObj.span === span) { |
| pill.className = "span-pill current"; |
| } else { |
| pill.className = "span-pill"; |
| } |
| }); |
| |
| if (stepObj.span === "plan") { |
| el("agent-detail-text").textContent = "Antigravity decomposes estate discovery and architecture specifications into structured, reviewable milestones."; |
| } else if (stepObj.span === "transform") { |
| el("agent-detail-text").textContent = "Antigravity coordinates code rewrite and data transformation agents with specialized skills and contextual awareness."; |
| } else { |
| el("agent-detail-text").textContent = "Antigravity runs automated validation, test replays, and parity audits prior to target cloud deployment."; |
| } |
| } |
| |
| function renderSandbox(stepObj) { |
| const container = el("sandbox-container"); |
| const tabBtn = el("tab-btn-sandbox"); |
| |
| if (stepObj.sandboxType === "dualrun") { |
| tabBtn.style.display = "inline-block"; |
| tabBtn.textContent = "Interactive Dual-Run Sandbox"; |
| container.innerHTML = ` |
| <div class="sandbox-title"> |
| <span>Dual Run Equivalence Replay Simulator</span> |
| <span class="status-badge ${dualRunFixed ? "match" : "mismatch"}">${dualRunFixed ? "All Cases Matched" : "Discrepancy Detected"}</span> |
| </div> |
| <p style="font-size: 12px; color: var(--text-secondary);"> |
| Dual Run replicates live transaction streams against both Mainframe and Google Cloud microservices to verify functional parity. |
| </p> |
| <table class="interactive-table"> |
| <thead> |
| <tr> |
| <th>Test Case ID</th> |
| <th>Workload Payload</th> |
| <th>Mainframe Output</th> |
| <th>Modern Cloud App Output</th> |
| <th>Status</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td><code>CASE-101</code></td> |
| <td>Standard Claim ($900.00)</td> |
| <td><strong>$90.00</strong> deductible</td> |
| <td><strong>$90.00</strong> deductible</td> |
| <td><span class="status-badge match">✓ Matched</span></td> |
| </tr> |
| <tr> |
| <td><code>CASE-102</code></td> |
| <td>Boundary Threshold ($10,000.01 Platinum)</td> |
| <td><strong>$0.00</strong> deductible (waived)</td> |
| <td id="sandbox-result-val"><strong>${dualRunFixed ? "$0.00" : "$1,000.00"}</strong> ${dualRunFixed ? "deductible (waived)" : "deductible (mismatch)"}</td> |
| <td id="sandbox-result-badge"><span class="status-badge ${dualRunFixed ? "match" : "mismatch"}">${dualRunFixed ? "✓ Matched" : "✗ Mismatch"}</span></td> |
| </tr> |
| </tbody> |
| </table> |
| <div style="display:flex; justify-content:flex-end; gap:8px; margin-top:8px;"> |
| <button type="button" class="btn ${dualRunFixed ? "btn-ghost" : "btn-primary"}" id="btn-fix-dualrun"> |
| ${dualRunFixed ? "✓ Boundary Rule Corrected & Verified" : "⚡ Apply Agent Rule Fix & Replay"} |
| </button> |
| </div> |
| `; |
| |
| el("btn-fix-dualrun").onclick = () => { |
| dualRunFixed = true; |
| renderStep(false); |
| }; |
| |
| } else if (stepObj.sandboxType === "codmod") { |
| tabBtn.style.display = "inline-block"; |
| tabBtn.textContent = "Interactive Refactor Sandbox"; |
| container.innerHTML = ` |
| <div class="sandbox-title"> |
| <span>CodMod Automated Refactoring Engine</span> |
| <span class="status-badge match">Ready for compilation</span> |
| </div> |
| <p style="font-size: 12px; color: var(--text-secondary);"> |
| Test the automated translation of legacy ASP.NET <code>System.Web</code> APIs to .NET 8 modern asynchronous handlers. |
| </p> |
| <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;"> |
| <div style="background: #090d16; padding: 10px; border-radius: 6px; font-family: monospace; font-size: 11px;"> |
| <div style="color: #f43f5e; font-weight: bold; margin-bottom: 4px;">Legacy ASP.NET MVC (Source)</div> |
| <div style="color: #94a3b8;"> |
| public ActionResult GetClaim(int id) {<br> |
| var claim = ClaimsDal.Fetch(id);<br> |
| Session["LastId"] = id;<br> |
| return Json(claim);<br> |
| } |
| </div> |
| </div> |
| <div style="background: #090d16; padding: 10px; border-radius: 6px; font-family: monospace; font-size: 11px;"> |
| <div style="color: #34d399; font-weight: bold; margin-bottom: 4px;">Modern ASP.NET Core 8 (Target)</div> |
| <div style="color: #94a3b8;"> |
| app.MapGet("/api/claims/{id}", async (int id, IClaimsRepo repo, IDistributedCache cache) => {<br> |
| await cache.SetStringAsync("LastId", id.ToString());<br> |
| return Results.Ok(await repo.GetAsync(id));<br> |
| }); |
| </div> |
| </div> |
| </div> |
| <div style="display:flex; justify-content:flex-end; gap:8px; margin-top:8px;"> |
| <button type="button" class="btn btn-primary" id="btn-run-tests"> |
| ⚡ Run Validation Test Suite |
| </button> |
| </div> |
| `; |
| |
| el("btn-run-tests").onclick = () => { |
| alert("✅ All 12 unit and integration tests passed with 0 warnings!"); |
| }; |
| |
| } else if (stepObj.sandboxType === "dms") { |
| tabBtn.style.display = "inline-block"; |
| tabBtn.textContent = "Interactive SQL Conversion"; |
| container.innerHTML = ` |
| <div class="sandbox-title"> |
| <span>DMS + Gemini Assisted SQL Translator</span> |
| <span class="status-badge ${dmsConverted ? "match" : ""}">AlloyDB Dialect</span> |
| </div> |
| <p style="font-size: 12px; color: var(--text-secondary);"> |
| Convert Oracle PL/SQL stored procedures with proprietary packages into modern PostgreSQL / AlloyDB PL/pgSQL functions. |
| </p> |
| <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;"> |
| <div style="background: #090d16; padding: 10px; border-radius: 6px; font-family: monospace; font-size: 11px;"> |
| <div style="color: #fbbf24; font-weight: bold; margin-bottom: 4px;">Oracle PL/SQL (Source)</div> |
| <div style="color: #94a3b8;"> |
| NVL2(v_rebate, v_rebate, 0.00);<br> |
| DBMS_OUTPUT.PUT_LINE('Done');<br> |
| SYSDATE; |
| </div> |
| </div> |
| <div style="background: #090d16; padding: 10px; border-radius: 6px; font-family: monospace; font-size: 11px;"> |
| <div style="color: #38bdf8; font-weight: bold; margin-bottom: 4px;">PostgreSQL / AlloyDB (Target)</div> |
| <div style="color: #94a3b8;"> |
| CASE WHEN v_rebate IS NOT NULL THEN v_rebate ELSE 0.00 END;<br> |
| RAISE NOTICE 'Done';<br> |
| CURRENT_TIMESTAMP; |
| </div> |
| </div> |
| </div> |
| <div style="display:flex; justify-content:flex-end; gap:8px; margin-top:8px;"> |
| <button type="button" class="btn btn-primary" id="btn-verify-sql"> |
| ⚡ Verify Syntax in PostgreSQL Parser |
| </button> |
| </div> |
| `; |
| |
| el("btn-verify-sql").onclick = () => { |
| dmsConverted = true; |
| alert("✅ PL/pgSQL syntax validated successfully against AlloyDB PostgreSQL 15 engine!"); |
| }; |
| |
| } else { |
| tabBtn.style.display = "none"; |
| if (currentTab === "sandbox") { |
| switchTab("narrative"); |
| } |
| } |
| } |
| |
| function renderStep(resetTab = false) { |
| const list = pathways[currentTrack].steps; |
| const s = list[currentStep]; |
| |
| // Counter |
| el("step-counter").textContent = `Step ${currentStep + 1} of ${list.length}`; |
| el("stage-step-num").textContent = `Step ${currentStep + 1} · ${s.phase.toUpperCase()}`; |
| el("stage-heading").textContent = `${s.phase} · ${s.actor}`; |
| el("stage-badge").textContent = s.role; |
| |
| // Flow Graph |
| el("flow-input-title").textContent = s.input; |
| el("flow-input-sub").textContent = s.inputSub; |
| el("flow-actor-role").textContent = "ACTIVE ENGINE / TOOL"; |
| el("flow-actor-title").textContent = s.actor; |
| el("flow-actor-sub").textContent = s.role; |
| el("flow-output-title").textContent = s.output; |
| el("flow-output-sub").textContent = s.outputSub; |
| |
| // Narrative |
| el("narrative-text").innerHTML = s.detail; |
| el("example-text").textContent = s.example; |
| |
| // Code Inspector |
| el("code-filename").textContent = s.codeFile; |
| el("code-lang-tag").textContent = s.codeLang; |
| el("code-view-content").innerHTML = s.codeSnippet; |
| |
| // Citation |
| el("source-citation").textContent = `Source: Google Cloud Modernization Framework (Slide ${s.slide}). Interactive execution model.`; |
| |
| // Buttons |
| el("btn-prev").disabled = currentStep === 0; |
| el("btn-next").disabled = currentStep === list.length - 1; |
| |
| renderStepper(); |
| renderOrchestrator(s); |
| renderSandbox(s); |
| |
| if (resetTab && currentTab === "sandbox" && s.sandboxType === "none") { |
| switchTab("narrative"); |
| } |
| } |
| |
| function switchTab(tabName) { |
| currentTab = tabName; |
| document.querySelectorAll(".viewer-tab-btn").forEach(btn => { |
| btn.classList.toggle("active", btn.dataset.vtab === tabName); |
| }); |
| |
| el("panel-narrative").style.display = tabName === "narrative" ? "flex" : "none"; |
| el("panel-code").style.display = tabName === "code" ? "flex" : "none"; |
| el("panel-sandbox").style.display = tabName === "sandbox" ? "flex" : "none"; |
| } |
| |
| // Setup Event Listeners |
| document.querySelectorAll(".track-btn").forEach(btn => { |
| btn.onclick = () => { |
| document.querySelectorAll(".track-btn").forEach(b => b.classList.remove("active")); |
| btn.classList.add("active"); |
| currentTrack = btn.dataset.track; |
| currentStep = 0; |
| dualRunFixed = false; |
| dmsConverted = false; |
| renderStep(true); |
| }; |
| }); |
| |
| document.querySelectorAll(".viewer-tab-btn").forEach(btn => { |
| btn.onclick = () => { |
| switchTab(btn.dataset.vtab); |
| }; |
| }); |
| |
| el("btn-prev").onclick = () => { |
| if (currentStep > 0) { |
| currentStep--; |
| renderStep(); |
| } |
| }; |
| |
| el("btn-next").onclick = () => { |
| if (currentStep < pathways[currentTrack].steps.length - 1) { |
| currentStep++; |
| renderStep(); |
| } |
| }; |
| |
| // Auto-Play Feature |
| el("btn-autoplay").onclick = () => { |
| if (autoPlayTimer) { |
| clearInterval(autoPlayTimer); |
| autoPlayTimer = null; |
| el("btn-autoplay").textContent = "▶ Auto-Play"; |
| el("btn-autoplay").classList.remove("btn-primary"); |
| } else { |
| el("btn-autoplay").textContent = "⏸ Pause"; |
| el("btn-autoplay").classList.add("btn-primary"); |
| autoPlayTimer = setInterval(() => { |
| if (currentStep < pathways[currentTrack].steps.length - 1) { |
| currentStep++; |
| renderStep(); |
| } else { |
| clearInterval(autoPlayTimer); |
| autoPlayTimer = null; |
| el("btn-autoplay").textContent = "▶ Auto-Play"; |
| el("btn-autoplay").classList.remove("btn-primary"); |
| } |
| }, 3500); |
| } |
| }; |
| |
| // Theme Toggle |
| el("theme-btn").onclick = () => { |
| const current = document.documentElement.getAttribute("data-theme"); |
| const next = current === "light" ? "dark" : "light"; |
| document.documentElement.setAttribute("data-theme", next); |
| }; |
| |
| // Keyboard navigation |
| window.addEventListener("keydown", (e) => { |
| if (e.key === "ArrowRight") { |
| if (currentStep < pathways[currentTrack].steps.length - 1) { |
| currentStep++; |
| renderStep(); |
| } |
| } else if (e.key === "ArrowLeft") { |
| if (currentStep > 0) { |
| currentStep--; |
| renderStep(); |
| } |
| } else if (e.key === " ") { |
| e.preventDefault(); |
| el("btn-autoplay").click(); |
| } |
| }); |
| |
| // Initial render |
| renderStep(); |
| })(); |
| </script> |
| </body> |
| </html> |
|
|