索引に戻る

指標定義台帳

表
生成可能
指標定義台帳

作品として見る

持ち帰る

コピーして貼るか、ファイルに保存して渡す。ネットにつながらない環境には「全部入り」を 1 つ渡せば足りる。

全部入り

metric-definition-register-everything.md

このパネルの中身を、URL の先にあるファイルの中身まで含めて 1 つにまとめた Markdown

依頼文

1.7 KB
「指標定義台帳」で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 つから生成されています。 生成された文書

template.tsx

5.9 KB

/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>;
}

schema.ts

1.4 KB

/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>;

meta.yaml

1.7 KB

/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: []

sample-data.json

1.7 KB

/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、取消済み注文を除く。" }
  ]
}