作品として見る 生成された文書そのもの — 切り替えも開閉もそのまま動きます
作品として見る 生成された文書そのもの — 切り替えも開閉もそのまま動きます
コピーして貼るか、ファイルに保存して渡す。ネットにつながらない環境には「全部入り」を 1 つ渡せば足りる。
このパネルの中身を、URL の先にあるファイルの中身まで含めて 1 つにまとめた Markdown — 大きいのでファイルで渡す(コピーは 32KB まで)
「移行データ照合・切替ゲート台帳」でHTML資料を作ってください。この型は実行できるので、版面を組み直す必要はありません — 必要なのは中身です。 ## この型がすること 移行元と移行先の実測値、許容差、合否、差分の処置と例外承認を切替判断に結びつける。 ## 渡す必要があるもの - 移行元・移行先、同じ単位で比較した値、許容差、責任者、処置、例外承認根拠を記録する。 ## 入力の形 - `title` — string — 移行照合の結論 - `subtitle` — string? — 対象・移行窓・照合時刻 - `sourceSystem` — string — 移行元システム - `targetSystem` — string — 移行先システム - `checks` — array (3–12) — 指標、元先の値、算出差分、許容差、責任者、処置、合否、例外承認根拠 入力の機械可読な検証は schema.ts が持ちます。足りない入力は推測せず質問してください。 ## 向かない場合 - システム間のデータ連携経路と変換順序を説明する場合は、データリネージを使う。 ## 作り方 入力を JSON にまとめ、次を実行します。 ```bash node scripts/render.mjs migration-reconciliation-register <入力.json> --theme ink -o out.html ``` 出力は 1 ファイルで完結し、外部から何も読み込みません。 ## 原本 - https://design-vault.pages.dev/designs/migration-reconciliation-register/source/template.tsx - https://design-vault.pages.dev/designs/migration-reconciliation-register/source/schema.ts - https://design-vault.pages.dev/designs/migration-reconciliation-register/source/sample-data.json - https://design-vault.pages.dev/designs/migration-reconciliation-register/sample.html
テンプレート・入力スキーマ・サンプルデータ・メタ情報。この文書はこの 4 つから生成されています。 生成された文書
/designs/migration-reconciliation-register/source/template.tsx
import type { Props } from "./schema";
const CSS = String.raw`
.asset-migration-reconciliation-register{font-family:var(--font-sans);color:var(--color-primary);background:var(--color-surface);max-width:var(--container-slide);margin:auto;padding:3rem 2.5rem;line-height:1.55;font-size:var(--text-body-sm)}
.asset-migration-reconciliation-register *{box-sizing:border-box}.asset-migration-reconciliation-register header{margin-bottom:1.2rem}.asset-migration-reconciliation-register .eyebrow{font-family:var(--font-mono);font-size:var(--text-label);color:var(--color-tertiary);margin:0 0 .6rem}.asset-migration-reconciliation-register h1{font-size:var(--text-h1);line-height:1.25;max-width:28em;margin:0}.asset-migration-reconciliation-register .subtitle{color:var(--color-secondary);margin:.65rem 0 0}.asset-migration-reconciliation-register .systems{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:1rem;padding:.8rem 0;border-block:1px solid var(--color-outline);margin:1rem 0}.asset-migration-reconciliation-register .systems span{font-size:var(--text-label);color:var(--color-secondary)}.asset-migration-reconciliation-register .systems strong{display:block;color:var(--color-primary);overflow-wrap:anywhere}.asset-migration-reconciliation-register .checks{border-top:2px solid var(--color-primary)}.asset-migration-reconciliation-register .check{display:grid;grid-template-columns:minmax(7rem,.8fr) minmax(7rem,1fr) minmax(11rem,1.3fr) minmax(7rem,.8fr) minmax(10rem,1.2fr);gap:.65rem;align-items:start;padding:.75rem .4rem;border-bottom:1px solid var(--color-outline);min-width:0}.asset-migration-reconciliation-register .check>*{min-width:0;overflow-wrap:anywhere}.asset-migration-reconciliation-register code{font-family:var(--font-mono);font-size:var(--text-label)}.asset-migration-reconciliation-register .measure{font-weight:600}.asset-migration-reconciliation-register .values{font-family:var(--font-mono);font-size:var(--text-label);font-variant-numeric:tabular-nums}.asset-migration-reconciliation-register .values span{display:block;color:var(--color-secondary)}.asset-migration-reconciliation-register .delta{font-family:var(--font-mono);font-size:var(--text-label)}.asset-migration-reconciliation-register .delta strong{display:block;color:var(--color-primary)}.asset-migration-reconciliation-register .status{display:inline-block;border:1px solid var(--color-outline);padding:.05rem .4rem;font-size:var(--text-label);color:var(--color-secondary)}.asset-migration-reconciliation-register .owner{font-size:var(--text-label);color:var(--color-secondary);margin-top:.3rem}.asset-migration-reconciliation-register .action{font-size:var(--text-label)}.asset-migration-reconciliation-register .waiver{margin-top:.3rem;padding-left:.5rem;border-left:2px solid var(--color-tertiary);color:var(--color-secondary)}.asset-migration-reconciliation-register .still-svg{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
@media(max-width:760px){.asset-migration-reconciliation-register{padding:1.5rem 1rem}.asset-migration-reconciliation-register h1{font-size:var(--text-h2)}.asset-migration-reconciliation-register .systems{grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);gap:.5rem}.asset-migration-reconciliation-register .check{grid-template-columns:minmax(0,1fr) auto;gap:.35rem .7rem;padding:.8rem .2rem}.asset-migration-reconciliation-register .measure{grid-column:1}.asset-migration-reconciliation-register .status{grid-column:2;grid-row:1}.asset-migration-reconciliation-register .values{grid-column:1}.asset-migration-reconciliation-register .delta{grid-column:2;grid-row:2;text-align:right}.asset-migration-reconciliation-register .owner{grid-column:1/3}.asset-migration-reconciliation-register .action{grid-column:1/3}}
@media print{.asset-migration-reconciliation-register{max-width:none;padding:1rem}.asset-migration-reconciliation-register .check{break-inside:avoid}}
`;
const statusLabel = { pass: "合格", review: "要確認", waived: "例外承認" };
const compact = (value: string, max: number) => [...value].length > max ? `${[...value].slice(0, max - 1).join("")}…` : value;
function Still({ data }: { data: Props }) {
return <svg className="still-svg" data-layout-still="true" width="1280" height="720" viewBox="0 0 1280 720" aria-hidden="true">
<rect width="1280" height="720" fill="var(--color-surface)" />
<text x="48" y="43" fontSize="13" fontFamily="sans-serif" fill="var(--color-secondary)">{data.sourceSystem} → {data.targetSystem}</text>
<text x="48" y="83" fontSize="26" fontWeight="700" fontFamily="sans-serif" fill="var(--color-on-surface)">{compact(data.title, 66)}</text>
<text x="48" y="118" fontSize="12" fontFamily="sans-serif" fill="var(--color-secondary)">照合値 · 差分 · 許容差 · 判定 · 責任者</text>
{data.checks.slice(0, 8).map((check, index) => {
const y = 164 + index * 62;
return <g key={check.id}>
<line x1="48" x2="1232" y1={y - 19} y2={y - 19} stroke="var(--color-outline)" />
<text x="52" y={y + 3} fontSize="11" fontFamily="monospace" fill="var(--color-tertiary)">{check.id}</text>
<text x="145" y={y + 3} fontSize="12" fontWeight="700" fontFamily="sans-serif" fill="var(--color-on-surface)">{compact(check.measure, 31)}</text>
<text x="430" y={y + 3} fontSize="11" fontFamily="monospace" fill="var(--color-secondary)">{check.sourceValue} → {check.targetValue}</text>
<text x="670" y={y + 3} fontSize="12" fontFamily="monospace" fill="var(--color-on-surface)">Δ {check.delta} / ±{check.tolerance}</text>
<text x="930" y={y + 3} fontSize="11" fontFamily="sans-serif" fill="var(--color-secondary)">{statusLabel[check.status]} · {compact(check.owner, 27)}</text>
</g>;
})}
<text x="48" y="704" fontSize="12" fontFamily="sans-serif" fill="var(--color-secondary)">{data.checks.length}照合項目 · 差分と例外承認を切替ゲートに記録</text>
</svg>;
}
export default function Template(data: Props) {
return <section className="asset asset-migration-reconciliation-register">
<style>{CSS}</style>
<header>
<p className="eyebrow">移行データ照合 · {data.checks.length}項目</p>
<h1>{data.title}</h1>
{data.subtitle && <p className="subtitle">{data.subtitle}</p>}
</header>
<div className="systems"><div><span>移行元</span><strong>{data.sourceSystem}</strong></div><span aria-hidden="true">→</span><div><span>移行先</span><strong>{data.targetSystem}</strong></div></div>
<div className="checks">
{data.checks.map((check) => <article className="check" key={check.id}>
<div><code>{check.id}</code><div className="measure">{check.measure}</div><div className="owner">判断責任: {check.owner}</div></div>
<div className="values"><span>元: {check.sourceValue} {check.unit}</span><span>先: {check.targetValue} {check.unit}</span></div>
<div className="delta"><strong>差分 {check.delta} {check.unit}</strong><span>許容 ±{check.tolerance} {check.unit}</span></div>
<span className="status" data-status={check.status}>{statusLabel[check.status]}</span>
<div className="action">{check.action}{check.waiver && <div className="waiver">承認根拠: {check.waiver}</div>}</div>
</article>)}
</div>
<Still data={data} />
</section>;
}
/designs/migration-reconciliation-register/source/schema.ts
import { z } from "zod";
const text = z.string().trim().min(1).max(160);
const short = z.string().trim().min(1).max(48);
const checkSchema = z.object({
id: short.describe("照合項目の一意な識別子"),
measure: short.describe("件数・金額・ハッシュなど比較する値"),
unit: short.describe("値の単位または比較方式"),
sourceValue: z.number().describe("移行元で観測した値"),
targetValue: z.number().describe("移行先で観測した値"),
delta: z.number().describe("移行先値から移行元値を引いた差"),
tolerance: z.number().nonnegative().describe("受け入れ可能な絶対差"),
owner: short.describe("照合の判断責任者"),
action: text.describe("不一致時または完了時の次の行動"),
status: z.enum(["pass", "review", "waived"]).describe("許容差と例外承認に対する判定"),
waiver: text.optional().describe("差分を受け入れる承認根拠"),
}).strict();
export const schema = z.object({
title: text.describe("移行照合の結論"),
subtitle: text.optional().describe("切替対象・移行窓・照合時刻"),
sourceSystem: short.describe("移行元システム"),
targetSystem: short.describe("移行先システム"),
checks: z.array(checkSchema).min(3).max(12).describe("元先で照合する移行データと受け入れ判定"),
}).strict().superRefine((data, ctx) => {
const ids = data.checks.map(({ id }) => id);
if (new Set(ids).size !== ids.length) {
ctx.addIssue({ code: "custom", path: ["checks"], message: "照合IDは一意にすること" });
}
data.checks.forEach((check, index) => {
const difference = check.targetValue - check.sourceValue;
if (Math.abs(check.delta - difference) > 1e-9) {
ctx.addIssue({ code: "custom", path: ["checks", index, "delta"], message: "差分は移行先値−移行元値に一致させること" });
}
const withinTolerance = Math.abs(difference) <= check.tolerance;
if (check.status === "pass" && !withinTolerance) {
ctx.addIssue({ code: "custom", path: ["checks", index, "status"], message: "許容差を超えた項目を合格にできない" });
}
if (check.status === "review" && withinTolerance) {
ctx.addIssue({ code: "custom", path: ["checks", index, "status"], message: "許容差内の項目は合格または例外承認にすること" });
}
if (check.status === "waived" && (!check.waiver || withinTolerance)) {
ctx.addIssue({ code: "custom", path: ["checks", index, "waiver"], message: "例外承認には許容差を超えた差分の承認根拠が必要" });
}
});
});
export type Props = z.infer<typeof schema>;
/designs/migration-reconciliation-register/source/meta.yaml
id: migration-reconciliation-register
name:
ja: 移行データ照合・切替ゲート台帳
en: Migration Reconciliation and Cutover Gate Register
purpose:
ja: 移行元と移行先の実測値、許容差、合否、差分の処置と例外承認を切替判断に結びつける。
en: Tie measured source-to-target values, tolerances, outcomes, remediation, and approved exceptions to a migration cutover decision.
status: published
still: ./still.png
category: governance
catalogOrder: 845
jobs:
- prioritize-diagnose
- assign-governance
useCases:
- migration
- requirements
layoutKinds:
- table
- stack
tags:
- data-migration
- reconciliation
- cutover
- data-parity
- responsive
whenToUse:
- ja: 移行リハーサルや本番切替で、元先の値の差分を許容差と承認記録つきで判定するとき。
en: Use during migration rehearsals or cutovers to judge source-to-target differences against tolerances and approvals.
avoidWhen:
- ja: システム間のデータ連携経路と変換順序を説明する場合は、データリネージを使う。
en: Use data lineage to explain integration paths and transformation order.
requiredInputs:
- ja: 移行元・移行先、同じ単位で比較した値、許容差、責任者、処置、例外承認根拠を記録する。
en: Record source and target, comparable values and units, tolerance, owner, action, and any exception approval.
relatedLayouts:
- data-lineage-stages
- requirement-traceability-matrix
dataSchema:
title: string — 移行照合の結論
subtitle: string? — 対象・移行窓・照合時刻
sourceSystem: string — 移行元システム
targetSystem: string — 移行先システム
checks: array (3–12) — 指標、元先の値、算出差分、許容差、責任者、処置、合否、例外承認根拠
sources: []
/designs/migration-reconciliation-register/source/sample-data.json
{
"title": "請求明細の件数と残高は許容差内、通貨コード異常2件は切替前に修正する",
"subtitle": "Billing v1 → Billing Cloud · rehearsal 2026-09-21 02:00 UTC",
"sourceSystem": "Billing v1",
"targetSystem": "Billing Cloud",
"checks": [
{ "id": "REC-001", "measure": "Open invoice rows", "unit": "rows", "sourceValue": 18240, "targetValue": 18240, "delta": 0, "tolerance": 0, "owner": "Data Migration", "action": "合格。切替チェックシートへ照合ログを添付する。", "status": "pass" },
{ "id": "REC-002", "measure": "Open balance", "unit": "USD", "sourceValue": 748250.5, "targetValue": 748250.49, "delta": -0.01, "tolerance": 0.05, "owner": "Finance Ops", "action": "許容差内。通貨丸めの説明を監査記録へ残す。", "status": "pass" },
{ "id": "REC-003", "measure": "Invalid currency codes", "unit": "rows", "sourceValue": 0, "targetValue": 2, "delta": 2, "tolerance": 0, "owner": "Billing Platform", "action": "対象請求を修正して照合を再実行する。", "status": "review" }
]
}