Back to index

Metric Definition Register

Table
Generates documents
Metric Definition Register

Seen as a design

Take it with you

Copy and paste, or save a file and hand it over. For a machine with no network, one “Everything” file is enough.

Everything

metric-definition-register-everything.md

Everything in this panel, including the contents behind each URL, in one Markdown file

Prompt

1.6 KB
Build an HTML document with "Metric Definition Register". This layout runs, so there is no composition to rebuild — what it needs is content.

## What this layout does
Share consistent definitions of what each metric answers, how it is calculated, its grain, source, refresh, and exclusions.

## What you have to supply
- Define each metric's question, numerator and denominator, grain, owner, source, refresh cadence, and exclusions.

## The shape of the input
- `title` — string — 指標セットの目的または定義変更の要点
- `subtitle` — string? — 適用範囲・有効日・バージョン
- `domain` — string — 対象業務・データ領域
- `metrics` — array (3–10) — 問い、分子、分母、粒度、責任者、ソース、更新頻度、除外条件を揃えた定義

schema.ts holds the machine-checkable validation. Ask rather than guess when an input is missing.

## When not to use it
- Use KPI cards to report actual values, target attainment, and trends.

## How to build it
Put the input in a JSON file and run:

```bash
node scripts/render.mjs metric-definition-register <input.json> --theme ink -o out.html
```

The output is one self-contained file and fetches nothing at render time.

## The source
- 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

Files

Template, input schema, sample data and metadata. This document was generated from those four. The generated document

template.tsx

5.9 KB

/designs/metric-definition-register/source/template.tsx

Show contents
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

Show contents
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

Show contents
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

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