Back to index

Risk Matrix and Register

Matrix
Generates documents
Risk Matrix and 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

risk-matrix-register-everything.md

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

Prompt

1.4 KB
Build an HTML document with "Risk Matrix and Register". This layout runs, so there is no composition to rebuild — what it needs is content.

## What this layout does
Risk Matrix and Register with explicit source values and reading conditions.

## What you have to supply
- Provide the source values, labels and decision conditions described by the schema.

## The shape of the input
- `title` — string — 結論を伝える見出し
- `subtitle` — string? — 出典・時点・母集団や仮定
- `risks` — array (id, label, likelihood, impact, owner, response) — リスクID、1〜5の評価、担当、対応策

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

## When not to use it
- Do not compare values with incompatible units, populations, or assumptions.

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

```bash
node scripts/render.mjs risk-matrix-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/risk-matrix-register/source/template.tsx
- https://design-vault.pages.dev/designs/risk-matrix-register/source/schema.ts
- https://design-vault.pages.dev/designs/risk-matrix-register/source/sample-data.json
- https://design-vault.pages.dev/designs/risk-matrix-register/sample.html

Files

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

template.tsx

7.4 KB

/designs/risk-matrix-register/source/template.tsx

Show contents
import type { ReactNode } from "react";
import type { Props } from "./schema";
function Ledger({heads,rows,caption}:{heads:string[];rows:ReactNode[][];caption?:string}) { return <table className="ledger">{caption && <caption>{caption}</caption>}<thead><tr>{heads.map((h,i)=><th key={i} scope="col">{h}</th>)}</tr></thead><tbody>{rows.map((r,i)=><tr key={i}>{r.map((v,j)=><td key={j} data-label={heads[j]}>{v}</td>)}</tr>)}</tbody></table>; }
function Notes({children}:{children:ReactNode}) { return <details><summary>データ・判断条件を確認</summary>{children}</details>; }

const CSS = String.raw`
.asset{font-family:var(--font-sans);color:var(--color-primary);background:var(--color-surface);max-width:var(--container-slide);margin:auto;padding:3rem 2rem;line-height:1.6;font-size:var(--text-body-sm)}
.asset *{box-sizing:border-box}.asset header{margin-bottom:2rem}.asset .eyebrow{font-family:var(--font-mono);font-size:var(--text-label);letter-spacing:.08em;color:var(--color-secondary);margin-bottom:.75rem}.asset h1{font-size:var(--text-h1);font-weight:700;line-height:1.35;letter-spacing:-.025em;max-width:32em}.asset h2{font-size:var(--text-h3);font-weight:600;margin-bottom:.75rem}.asset h3{font-size:var(--text-body-md);font-weight:600}.asset .subtitle,.asset .muted{color:var(--color-secondary)}.asset .subtitle{margin-top:.75rem}.asset .number{font-variant-numeric:tabular-nums;font-family:var(--font-mono)}.asset .hero-number{font-size:var(--text-display);line-height:1.2;font-weight:700;letter-spacing:-.04em}.asset .callout{border-left:.25rem solid var(--color-tertiary);padding:1rem 1.5rem;background:var(--color-surface-subtle);margin-bottom:1.5rem}.asset .grid2{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem}.asset .grid3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1.5rem}.asset .panel{padding:1.5rem;background:var(--color-surface-subtle);border-radius:var(--radius-md);min-width:0}.asset .rule{border-top:1px solid var(--color-outline);padding-top:1rem;margin-top:1rem}.asset .pill{display:inline-block;padding:.25rem .75rem;border:1px solid var(--color-outline);border-radius:var(--radius-full);font-size:var(--text-label)}.asset .focus{background:var(--color-tertiary-container);color:var(--color-on-tertiary-container)}.asset .dark{background:var(--color-primary);color:var(--color-on-primary)}.asset .dark .muted{color:var(--color-on-primary-container)}.asset .row{display:grid;grid-template-columns:12rem minmax(0,1fr) 6rem;gap:1rem;align-items:center;padding:.75rem 0;border-bottom:1px solid var(--color-outline)}.asset .row>*{min-width:0}.asset .track{height:1rem;position:relative;background:var(--color-neutral);border-radius:var(--radius-sm)}.asset .bar{height:100%;background:var(--color-tertiary);border-radius:var(--radius-sm)}.asset .track.tall{height:2rem}.asset .flex{display:flex;gap:1rem;align-items:center;justify-content:space-between;flex-wrap:wrap}.asset .stack>*+*{margin-top:1rem}.asset ul{list-style:disc;padding-left:1.25rem}.asset li+li{margin-top:.5rem}.asset .plot{display:block;width:100%;height:auto;overflow:visible}.asset .plot text{font-family:var(--font-sans);font-size:14px;fill:var(--color-secondary)}.asset .plot .ink{fill:var(--color-primary)}.asset .plot .axis{stroke:var(--color-outline);stroke-width:1}.asset .plot .accent{stroke:var(--color-tertiary);fill:none;stroke-width:3}.asset .legend{display:flex;gap:1.5rem;flex-wrap:wrap;font-size:var(--text-label);margin-bottom:1rem}.asset .legend b{display:inline-block;width:.75rem;height:.75rem;margin-right:.5rem}.asset .ledger{border-collapse:collapse;width:100%;font-variant-numeric:tabular-nums}.asset .ledger caption{text-align:left;font-weight:600;margin:1rem 0}.asset .ledger th{font-weight:600;color:var(--color-secondary);text-align:left}.asset .ledger th,.asset .ledger td{padding:.75rem 1rem;border-bottom:1px solid var(--color-outline);vertical-align:top;overflow-wrap:anywhere}.asset .ledger th:first-child,.asset .ledger td:first-child{padding-left:0}.asset .ledger th:last-child,.asset .ledger td:last-child{padding-right:0}.asset .ledger tbody tr:hover{background:var(--color-surface-subtle)}.asset details{border-top:1px solid var(--color-outline);margin-top:1.5rem;padding-top:1rem}.asset summary{cursor:pointer;color:var(--color-secondary);padding:.5rem 0;min-height:2.75rem}.asset summary:focus-visible{outline:2px solid var(--color-tertiary);outline-offset:.25rem}.asset .small{font-size:var(--text-label)}.asset .mobile-only{display:none}.asset .horizontal-list{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1rem}.asset .board-column{border-top:.25rem solid var(--color-primary);padding-top:1rem;min-width:0}.asset .board-item{padding:1rem 0;border-bottom:1px solid var(--color-outline)}.asset .board-item p{margin-top:.5rem}.asset .statement{font-size:var(--text-h2);line-height:1.5;font-weight:600}.asset .meta-line{margin-top:.75rem;font-size:var(--text-label);color:var(--color-secondary)}.asset pre{white-space:pre-wrap;overflow-wrap:anywhere}.asset footer{margin-top:2rem;font-size:var(--text-label);color:var(--color-secondary)}
@media(max-width:640px){.asset{padding:1.5rem 1rem}.asset h1{font-size:var(--text-h2)}.asset header{margin-bottom:1.5rem}.asset .grid2,.asset .grid3,.asset .horizontal-list{grid-template-columns:1fr}.asset .row{grid-template-columns:minmax(0,1fr) 5rem;gap:.5rem}.asset .row>:first-child{grid-column:1/-1}.asset .desktop-only{display:none!important}.asset .mobile-only{display:block}.asset .panel{padding:1rem}.asset .ledger,.asset .ledger tbody,.asset .ledger tr,.asset .ledger td{display:block}.asset .ledger thead{display:none}.asset .ledger tr{padding:.75rem 0;border-bottom:1px solid var(--color-outline)}.asset .ledger td{display:grid;grid-template-columns:7rem minmax(0,1fr);gap:.75rem;border:0;padding:.25rem 0!important}.asset .ledger td:before{content:attr(data-label);color:var(--color-secondary);font-size:var(--text-label)}.asset .hero-number{font-size:var(--text-h1)}}
@media print{.asset{max-width:none;padding:1rem}.asset details>*{display:block}.asset summary{display:none}}
`;

export default function Template(d: Props) {
const risks=[...d.risks].sort((a,b)=>b.likelihood*b.impact-a.likelihood*a.impact);
return <section className="asset asset-risk-matrix-register"><style>{CSS}</style><header><p className="eyebrow">RISK MATRIX AND REGISTER</p><h1>{d.title}</h1>{d.subtitle && <p className="subtitle">{d.subtitle}</p>}</header>
<div className="grid2"><div><p className="small muted">↑ 影響 / 発生可能性 →</p><div style={{display:"grid",gridTemplateColumns:"repeat(5,minmax(0,1fr))",gap:".5rem"}}>{Array.from({length:25},(_,i)=>{const imp=5-Math.floor(i/5),like=i%5+1;return <div key={i} style={{minHeight:"3rem",padding:".25rem",background:imp*like>=16?"var(--color-tertiary-container)":"var(--color-surface-subtle)",border:"1px solid var(--color-outline)"}}><span className="small muted">{like}×{imp}</span>{d.risks.filter(r=>r.impact===imp&&r.likelihood===like).map(r=><strong key={r.id} style={{display:"block"}}>{r.id}</strong>)}</div>})}</div></div><div className="panel"><h2>重点対応</h2><p className="statement">{risks[0].label}</p><p className="rule">{risks[0].response}</p><p className="meta-line">担当:{risks[0].owner}</p></div></div><Notes><Ledger heads={["ID / リスク","可能性","影響","担当","対応"]} rows={risks.map(r=>[r.id+" / "+r.label,r.likelihood,r.impact,r.owner,r.response])}/></Notes>
<footer>1〜5は序数評価。積は並び替えの目安で、損失期待値ではない。</footer></section>;
}

schema.ts

798 B

/designs/risk-matrix-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 value = z.number().finite();
const positive = value.positive();
const unique = (values: string[]) => new Set(values).size === values.length;

export const schema = z.object({
  title: text.describe("結論を伝える見出し"),
  subtitle: text.optional().describe("出典・時点・母集団や仮定"),
  risks:z.array(z.object({id:short,label:short,likelihood:z.number().int().min(1).max(5),impact:z.number().int().min(1).max(5),owner:short,response:text}).strict()).min(2).max(10).describe("リスクID、1〜5の評価、担当、対応策"),
}).strict().refine(d=>unique(d.risks.map(r=>r.id)),"リスクIDは一意");
export type Props = z.infer<typeof schema>;

meta.yaml

1.3 KB

/designs/risk-matrix-register/source/meta.yaml

Show contents
id: risk-matrix-register
name:
  ja: リスクマトリクスと対応台帳
  en: Risk Matrix and Register
purpose:
  ja: 発生可能性と影響の位置を、担当・対応策と結びつけて管理する。
  en: Risk Matrix and Register with explicit source values and reading conditions.
status: published
still: ./still.png
category: decision
catalogOrder: 430
jobs:
  - prioritize-diagnose
useCases:
  - prioritization
layoutKinds:
  - matrix
tags:
  - risk-matrix-register
  - decision
  - offline
  - responsive
whenToUse:
  - ja: 発生可能性と影響の位置を、担当・対応策と結びつけて管理する。
    en: Use to communicate risk matrix and register.
avoidWhen:
  - ja: 同じ条件・単位で比較できないデータには使わない
    en: Do not compare values with incompatible units, populations, or assumptions.
requiredInputs:
  - ja: 1〜5は序数評価。積は並び替えの目安で、損失期待値ではない。
    en: Provide the source values, labels and decision conditions described by the schema.
relatedLayouts:
  - matrix-2x2
  - action-register
dataSchema:
  title: string — 結論を伝える見出し
  subtitle: string? — 出典・時点・母集団や仮定
  risks: array (id, label, likelihood, impact, owner, response) — リスクID、1〜5の評価、担当、対応策
sources: []

sample-data.json

914 B

/designs/risk-matrix-register/source/sample-data.json

Show contents
{
  "title": "移行リハーサルの不足を最優先で解消する",
  "subtitle": "架空サンプル|レイアウトの使用例",
  "risks": [
    {
      "id": "R1",
      "label": "移行リハ不足",
      "likelihood": 4,
      "impact": 5,
      "owner": "移行責任者",
      "response": "本番相当データで再検証"
    },
    {
      "id": "R2",
      "label": "業務教育遅延",
      "likelihood": 3,
      "impact": 3,
      "owner": "業務責任者",
      "response": "教材を先行公開"
    },
    {
      "id": "R3",
      "label": "権限不整合",
      "likelihood": 2,
      "impact": 4,
      "owner": "基盤責任者",
      "response": "権限棚卸しを実施"
    },
    {
      "id": "R4",
      "label": "問合せ増加",
      "likelihood": 4,
      "impact": 2,
      "owner": "運用責任者",
      "response": "初週の受付を増員"
    }
  ]
}