作品として見る 生成された文書そのもの — 切り替えも開閉もそのまま動きます
作品として見る 生成された文書そのもの — 切り替えも開閉もそのまま動きます
コピーして貼るか、ファイルに保存して渡す。ネットにつながらない環境には「全部入り」を 1 つ渡せば足りる。
このパネルの中身を、URL の先にあるファイルの中身まで含めて 1 つにまとめた Markdown — 大きいのでファイルで渡す(コピーは 32KB まで)
「指標定義台帳」でHTML資料を作ってください。この型は実行できるので、版面を組み直す必要はありません — 必要なのは中身です。 ## この型がすること 指標が答える問い、算式、粒度、正本ソース、更新条件、除外条件を一貫した定義として共有する。 ## 渡す必要があるもの - 各指標の業務上の問い、分子と分母、粒度、責任者、ソース、更新頻度、除外条件を定義する。 ## 入力の形 - `title` — string — 指標セットの目的または定義変更の要点 - `subtitle` — string? — 適用範囲・有効日・バージョン - `domain` — string — 対象業務・データ領域 - `metrics` — array (3–10) — 問い、分子、分母、粒度、責任者、ソース、更新頻度、除外条件を揃えた定義 入力の機械可読な検証は schema.ts が持ちます。足りない入力は推測せず質問してください。 ## 向かない場合 - KPIの実績値・目標達成・推移そのものを報告する場合は、KPIカードを使う。 ## 作り方 入力を JSON にまとめ、次を実行します。 ```bash node scripts/render.mjs metric-definition-register <入力.json> --theme ink -o out.html ``` 出力は 1 ファイルで完結し、外部から何も読み込みません。 ## 原本 - https://design-vault.pages.dev/designs/metric-definition-register/source/template.tsx - https://design-vault.pages.dev/designs/metric-definition-register/source/schema.ts - https://design-vault.pages.dev/designs/metric-definition-register/source/sample-data.json - https://design-vault.pages.dev/designs/metric-definition-register/sample.html
テンプレート・入力スキーマ・サンプルデータ・メタ情報。この文書はこの 4 つから生成されています。 生成された文書
/designs/metric-definition-register/source/template.tsx
import type { Props } from "./schema";
const CSS = String.raw`
.asset-metric-definition-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-metric-definition-register *{box-sizing:border-box}.asset-metric-definition-register header{margin-bottom:1.25rem}.asset-metric-definition-register .eyebrow{font-family:var(--font-mono);font-size:var(--text-label);color:var(--color-tertiary);margin:0 0 .6rem}.asset-metric-definition-register h1{font-size:var(--text-h1);line-height:1.25;max-width:28em;margin:0}.asset-metric-definition-register .subtitle{color:var(--color-secondary);margin:.65rem 0 0}.asset-metric-definition-register .metric{padding:1rem 0;border-top:1px solid var(--color-outline);display:grid;grid-template-columns:minmax(0,.75fr) minmax(0,1.6fr);gap:.4rem 1.5rem}.asset-metric-definition-register .metric:last-of-type{border-bottom:1px solid var(--color-outline)}.asset-metric-definition-register .identity{min-width:0}.asset-metric-definition-register .identity code{font-family:var(--font-mono);font-size:var(--text-label);color:var(--color-tertiary);overflow-wrap:anywhere}.asset-metric-definition-register .identity h2{font-size:var(--text-body-md);margin:.2rem 0}.asset-metric-definition-register .owner{font-size:var(--text-label);color:var(--color-secondary)}.asset-metric-definition-register .definition{display:grid;grid-template-columns:1fr 1fr;gap:.55rem 1.1rem;min-width:0}.asset-metric-definition-register .field{min-width:0}.asset-metric-definition-register .label{display:block;font-size:var(--text-label);color:var(--color-secondary);margin-bottom:.08rem}.asset-metric-definition-register .field p{margin:0;overflow-wrap:anywhere}.asset-metric-definition-register .field.question{grid-column:1/3;padding-bottom:.35rem;border-bottom:1px dashed var(--color-outline)}.asset-metric-definition-register .field.exclusions{grid-column:1/3}.asset-metric-definition-register .still-svg{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
@media(max-width:680px){.asset-metric-definition-register{padding:1.5rem 1rem}.asset-metric-definition-register h1{font-size:var(--text-h2)}.asset-metric-definition-register .metric{grid-template-columns:minmax(0,1fr);gap:.6rem}.asset-metric-definition-register .definition{grid-template-columns:minmax(0,1fr)}.asset-metric-definition-register .field.question,.asset-metric-definition-register .field.exclusions{grid-column:auto}}
@media print{.asset-metric-definition-register{max-width:none;padding:1rem}.asset-metric-definition-register .metric{break-inside:avoid}}
`;
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="45" fontSize="14" fontFamily="sans-serif" fill="var(--color-secondary)">{data.domain}</text>
<text x="48" y="87" fontSize="27" fontWeight="700" fontFamily="sans-serif" fill="var(--color-on-surface)">{compact(data.title, 62)}</text>
<text x="48" y="123" fontSize="13" fontFamily="sans-serif" fill="var(--color-secondary)">問い · 分子 / 分母 · 粒度 · 正本ソース · 更新 · 除外条件</text>
{data.metrics.slice(0, 8).map((metric, index) => {
const y = 175 + index * 62;
return <g key={metric.id}>
<line x1="48" x2="1232" y1={y - 19} y2={y - 19} stroke="var(--color-outline)" />
<text x="52" y={y + 2} fontSize="11" fontFamily="monospace" fill="var(--color-tertiary)">{metric.id}</text>
<text x="180" y={y + 2} fontSize="13" fontWeight="700" fontFamily="sans-serif" fill="var(--color-on-surface)">{compact(metric.name, 30)}</text>
<text x="465" y={y + 2} fontSize="11" fontFamily="sans-serif" fill="var(--color-secondary)">{compact(metric.grain, 24)}</text>
<text x="670" y={y + 2} fontSize="11" fontFamily="monospace" fill="var(--color-on-surface)">{compact(metric.source, 34)}</text>
<text x="1040" y={y + 2} fontSize="11" fontFamily="sans-serif" fill="var(--color-secondary)">{compact(metric.refresh, 22)}</text>
</g>;
})}
<text x="48" y="704" fontSize="12" fontFamily="sans-serif" fill="var(--color-secondary)">{data.metrics.length}指標定義 · 正本の意味と集計条件を共有</text>
</svg>;
}
export default function Template(data: Props) {
return <section className="asset asset-metric-definition-register">
<style>{CSS}</style>
<header>
<p className="eyebrow">{data.domain} · 指標定義台帳</p>
<h1>{data.title}</h1>
{data.subtitle && <p className="subtitle">{data.subtitle}</p>}
</header>
{data.metrics.map((metric) => <article className="metric" key={metric.id}>
<div className="identity"><code>{metric.id}</code><h2>{metric.name}</h2><span className="owner">定義責任: {metric.owner}</span></div>
<div className="definition">
<div className="field question"><span className="label">答える問い</span><p>{metric.question}</p></div>
<div className="field"><span className="label">分子・集計対象</span><p>{metric.numerator}</p></div>
<div className="field"><span className="label">分母・母集団</span><p>{metric.denominator}</p></div>
<div className="field"><span className="label">粒度</span><p>{metric.grain}</p></div>
<div className="field"><span className="label">正本ソース</span><p>{metric.source}</p></div>
<div className="field"><span className="label">更新</span><p>{metric.refresh}</p></div>
<div className="field exclusions"><span className="label">除外・注意</span><p>{metric.exclusions}</p></div>
</div>
</article>)}
<Still data={data} />
</section>;
}
/designs/metric-definition-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 metricSchema = z.object({
id: short.describe("安定した指標識別子"),
name: short.describe("指標の表示名"),
owner: short.describe("定義の責任者"),
question: text.describe("この指標で答える業務上の問い"),
numerator: text.describe("分子または集計する対象"),
denominator: text.describe("分母または対象母集団"),
grain: short.describe("集計粒度・単位"),
source: short.describe("正本となるデータソース"),
refresh: short.describe("更新頻度と締め時刻"),
exclusions: text.describe("除外条件・解釈上の注意"),
}).strict();
export const schema = z.object({
title: text.describe("指標セットの目的または定義変更の要点"),
subtitle: text.optional().describe("適用範囲・有効日・バージョン"),
domain: short.describe("対象業務・データ領域"),
metrics: z.array(metricSchema).min(3).max(10).describe("再利用する指標定義"),
}).strict().superRefine((data, ctx) => {
const ids = data.metrics.map(({ id }) => id);
if (new Set(ids).size !== ids.length) {
ctx.addIssue({ code: "custom", path: ["metrics"], message: "指標IDは一意にすること" });
}
});
export type Props = z.infer<typeof schema>;
/designs/metric-definition-register/source/meta.yaml
id: metric-definition-register
name:
ja: 指標定義台帳
en: Metric Definition Register
purpose:
ja: 指標が答える問い、算式、粒度、正本ソース、更新条件、除外条件を一貫した定義として共有する。
en: Share consistent definitions of what each metric answers, how it is calculated, its grain, source, refresh, and exclusions.
status: published
still: ./still.png
category: metrics
catalogOrder: 840
jobs:
- explain-structure
- assign-governance
useCases:
- kpi
- status
layoutKinds:
- table
- stack
tags:
- metric-definition
- data-dictionary
- numerator-denominator
- governance
- responsive
whenToUse:
- ja: チーム間で指標名だけが共有され、分母・粒度・除外条件の解釈が異なるとき。
en: Use when teams share metric names but disagree on denominators, grain, or exclusions.
avoidWhen:
- ja: KPIの実績値・目標達成・推移そのものを報告する場合は、KPIカードを使う。
en: Use KPI cards to report actual values, target attainment, and trends.
requiredInputs:
- ja: 各指標の業務上の問い、分子と分母、粒度、責任者、ソース、更新頻度、除外条件を定義する。
en: Define each metric's question, numerator and denominator, grain, owner, source, refresh cadence, and exclusions.
relatedLayouts:
- kpi-cards
- data-lineage-stages
dataSchema:
title: string — 指標セットの目的または定義変更の要点
subtitle: string? — 適用範囲・有効日・バージョン
domain: string — 対象業務・データ領域
metrics: array (3–10) — 問い、分子、分母、粒度、責任者、ソース、更新頻度、除外条件を揃えた定義
sources: []
/designs/metric-definition-register/source/sample-data.json
{
"title": "週次アクティブ利用者の母集団と重複排除ルールを統一する",
"subtitle": "Product Analytics v2.1 · 2026-09-22適用",
"domain": "Product Analytics",
"metrics": [
{ "id": "MET-ACTIVE-7D", "name": "週次アクティブ利用者", "owner": "Product Analytics", "question": "直近7日間に価値ある操作をした利用者は何人か。", "numerator": "期間内に有効イベントを1回以上行ったdistinct user_id", "denominator": "対象期間に有効な個人アカウント", "grain": "週 / 利用者", "source": "event_warehouse", "refresh": "毎日 06:00 UTC", "exclusions": "社内アカウント、bot、匿名セッションを除く。" },
{ "id": "MET-RET-28D", "name": "28日継続率", "owner": "Lifecycle Data", "question": "初回利用者のうち4週後も利用する割合はいくらか。", "numerator": "初回から28日後の窓に有効イベントがある利用者", "denominator": "観測期間を完了した初回利用者 cohort", "grain": "初回登録週 / cohort", "source": "analytics_mart.retention", "refresh": "毎週 月曜 08:00 UTC", "exclusions": "28日間の追跡期間が未完了のcohortは含めない。" },
{ "id": "MET-ORDER-COMPLETE", "name": "注文完了率", "owner": "Commerce Insights", "question": "開始された注文のうち決済完了に至った割合はいくらか。", "numerator": "決済成功となった一意なorder_id件数", "denominator": "有効なcheckout_startedの一意なorder_id件数", "grain": "日 / 注文", "source": "commerce.orders", "refresh": "1時間ごと", "exclusions": "テスト注文、重複webhook、取消済み注文を除く。" }
]
}