作品として見る 生成された文書そのもの — 切り替えも開閉もそのまま動きます
作品として見る 生成された文書そのもの — 切り替えも開閉もそのまま動きます
コピーして貼るか、ファイルに保存して渡す。ネットにつながらない環境には「全部入り」を 1 つ渡せば足りる。
このパネルの中身を、URL の先にあるファイルの中身まで含めて 1 つにまとめた Markdown — 大きいのでファイルで渡す(コピーは 32KB まで)
「サービス階層・SLA比較表」でHTML資料を作ってください。この型は実行できるので、版面を組み直す必要はありません — 必要なのは中身です。 ## この型がすること サービス階層ごとの稼働率保証、障害応答、サポート時間、補償条件を同じ基準で比較する。 ## 渡す必要があるもの - 月間稼働率目標、優先度別初回応答時間、サポート時間・窓口、補償上限、測定除外を定義する。 ## 入力の形 - `title` — string — サービス水準の要点 - `subtitle` — string? — 契約版・有効日・測定期間 - `service` — string — サービスまたは契約対象 - `measurementWindow` — string — 稼働率を計測する期間 - `tiers` — array (3–6) — 稼働率、P1/P2応答時間、サポート条件、補償上限、除外条件 入力の機械可読な検証は schema.ts が持ちます。足りない入力は推測せず質問してください。 ## 向かない場合 - インシデントの重大度ごとに社内対応の引き継ぎ時間を決める場合は、インシデント対応方針を使う。 ## 作り方 入力を JSON にまとめ、次を実行します。 ```bash node scripts/render.mjs service-tier-sla-matrix <入力.json> --theme ink -o out.html ``` 出力は 1 ファイルで完結し、外部から何も読み込みません。 ## 原本 - https://design-vault.pages.dev/designs/service-tier-sla-matrix/source/template.tsx - https://design-vault.pages.dev/designs/service-tier-sla-matrix/source/schema.ts - https://design-vault.pages.dev/designs/service-tier-sla-matrix/source/sample-data.json - https://design-vault.pages.dev/designs/service-tier-sla-matrix/sample.html
テンプレート・入力スキーマ・サンプルデータ・メタ情報。この文書はこの 4 つから生成されています。 生成された文書
/designs/service-tier-sla-matrix/source/template.tsx
import type { Props } from "./schema";
const CSS = String.raw`
.asset-service-tier-sla-matrix{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-service-tier-sla-matrix *{box-sizing:border-box}.asset-service-tier-sla-matrix header{margin-bottom:1.2rem}.asset-service-tier-sla-matrix .eyebrow{font-family:var(--font-mono);font-size:var(--text-label);color:var(--color-tertiary);margin:0 0 .6rem}.asset-service-tier-sla-matrix h1{font-size:var(--text-h1);line-height:1.25;max-width:28em;margin:0}.asset-service-tier-sla-matrix .subtitle{color:var(--color-secondary);margin:.65rem 0 0}.asset-service-tier-sla-matrix .context{display:flex;gap:1.5rem;flex-wrap:wrap;padding:.7rem 0;border-block:1px solid var(--color-outline);margin-bottom:1rem}.asset-service-tier-sla-matrix .context span{font-size:var(--text-label);color:var(--color-secondary)}.asset-service-tier-sla-matrix .context strong{color:var(--color-primary);margin-left:.3rem;overflow-wrap:anywhere}.asset-service-tier-sla-matrix .tiers{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:.8rem}.asset-service-tier-sla-matrix .tier{border-top:2px solid var(--color-primary);background:var(--color-surface);min-width:0}.asset-service-tier-sla-matrix .tier-head{padding:.7rem .75rem;background:var(--color-surface-subtle)}.asset-service-tier-sla-matrix .tier-head code{font-family:var(--font-mono);font-size:var(--text-label);color:var(--color-tertiary)}.asset-service-tier-sla-matrix .tier-head h2{font-size:var(--text-body-md);margin:.15rem 0}.asset-service-tier-sla-matrix .availability{padding:.7rem .75rem;border-bottom:1px solid var(--color-outline)}.asset-service-tier-sla-matrix .availability span{display:block;font-size:var(--text-label);color:var(--color-secondary)}.asset-service-tier-sla-matrix .availability strong{font-family:var(--font-mono);font-size:var(--text-h3);color:var(--color-primary)}.asset-service-tier-sla-matrix .details{padding:.65rem .75rem}.asset-service-tier-sla-matrix .field{margin-bottom:.55rem;min-width:0}.asset-service-tier-sla-matrix .field:last-child{margin-bottom:0}.asset-service-tier-sla-matrix .label{display:block;font-size:var(--text-label);color:var(--color-secondary)}.asset-service-tier-sla-matrix .field p{margin:.08rem 0 0;overflow-wrap:anywhere}.asset-service-tier-sla-matrix .response{display:grid;grid-template-columns:1fr 1fr;gap:.5rem}.asset-service-tier-sla-matrix .response strong{font-family:var(--font-mono)}.asset-service-tier-sla-matrix .still-svg{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
@media(max-width:760px){.asset-service-tier-sla-matrix{padding:1.5rem 1rem}.asset-service-tier-sla-matrix h1{font-size:var(--text-h2)}.asset-service-tier-sla-matrix .tiers{grid-template-columns:repeat(2,minmax(0,1fr))}.asset-service-tier-sla-matrix .context{gap:.7rem}}
@media(max-width:480px){.asset-service-tier-sla-matrix .tiers{grid-template-columns:minmax(0,1fr)}}
@media print{.asset-service-tier-sla-matrix{max-width:none;padding:1rem}.asset-service-tier-sla-matrix .tier{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="43" fontSize="13" fontFamily="sans-serif" fill="var(--color-secondary)">{data.service} · {data.measurementWindow}</text>
<text x="48" y="83" fontSize="25" 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)">契約階層 · 稼働率 · P1/P2初回応答 · サポート時間 · 補償上限</text>
{data.tiers.map((tier, index) => {
const y = 165 + index * 78;
return <g key={tier.id}>
<line x1="48" x2="1232" y1={y - 20} y2={y - 20} stroke="var(--color-outline)" />
<text x="52" y={y + 3} fontSize="11" fontFamily="monospace" fill="var(--color-tertiary)">{tier.id}</text>
<text x="180" y={y + 3} fontSize="13" fontWeight="700" fontFamily="sans-serif" fill="var(--color-on-surface)">{tier.name}</text>
<text x="390" y={y + 3} fontSize="13" fontWeight="700" fontFamily="monospace" fill="var(--color-on-surface)">{tier.availabilityPercent}%</text>
<text x="570" y={y + 3} fontSize="12" fontFamily="sans-serif" fill="var(--color-secondary)">P1 {tier.p1ResponseMinutes}m · P2 {tier.p2ResponseMinutes}m</text>
<text x="830" y={y + 3} fontSize="11" fontFamily="sans-serif" fill="var(--color-on-surface)">{compact(tier.supportHours, 36)}</text>
<text x="1120" y={y + 3} fontSize="11" fontFamily="sans-serif" fill="var(--color-secondary)">上限 {tier.creditCapPercent}%</text>
</g>;
})}
<text x="48" y="704" fontSize="12" fontFamily="sans-serif" fill="var(--color-secondary)">{data.tiers.length}階層 · 契約条件を同じ基準で比較</text>
</svg>;
}
export default function Template(data: Props) {
return <section className="asset asset-service-tier-sla-matrix">
<style>{CSS}</style>
<header>
<p className="eyebrow">サービス水準比較 · {data.tiers.length}契約階層</p>
<h1>{data.title}</h1>
{data.subtitle && <p className="subtitle">{data.subtitle}</p>}
</header>
<div className="context"><span>サービス<strong>{data.service}</strong></span><span>測定期間<strong>{data.measurementWindow}</strong></span></div>
<div className="tiers">
{data.tiers.map((tier) => <article className="tier" key={tier.id}>
<div className="tier-head"><code>{tier.id}</code><h2>{tier.name}</h2></div>
<div className="availability"><span>月間稼働率保証</span><strong>{tier.availabilityPercent}%</strong></div>
<div className="details">
<div className="field"><span className="label">初回応答目標</span><div className="response"><span>P1 <strong>{tier.p1ResponseMinutes}分</strong></span><span>P2 <strong>{tier.p2ResponseMinutes}分</strong></span></div></div>
<div className="field"><span className="label">サポート時間</span><p>{tier.supportHours}</p></div>
<div className="field"><span className="label">サポート経路</span><p>{tier.supportRoute}</p></div>
<div className="field"><span className="label">補償クレジット上限</span><p>{tier.creditCapPercent}% of monthly fee</p></div>
<div className="field"><span className="label">測定・補償の除外</span><p>{tier.exclusions}</p></div>
</div>
</article>)}
</div>
<Still data={data} />
</section>;
}
/designs/service-tier-sla-matrix/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 tierSchema = z.object({
id: short.describe("サービス階層の一意な識別子"),
name: short.describe("契約プラン名"),
availabilityPercent: z.number().min(95).max(99.999).describe("月間稼働率の保証値(%)"),
p1ResponseMinutes: z.number().int().positive().describe("重大障害の初回応答目標(分)"),
p2ResponseMinutes: z.number().int().positive().describe("高優先度障害の初回応答目標(分)"),
supportHours: text.describe("サポートの提供時間・休日条件"),
supportRoute: text.describe("サポート窓口または連絡経路"),
creditCapPercent: z.number().min(0).max(100).describe("月額料金に対するサービスクレジット上限(%)"),
exclusions: text.describe("稼働率計算・補償の対象外条件"),
}).strict();
export const schema = z.object({
title: text.describe("サービス水準の要点"),
subtitle: text.optional().describe("契約版・有効日・測定期間"),
service: short.describe("サービスまたは契約対象"),
measurementWindow: text.describe("稼働率を計測する期間"),
tiers: z.array(tierSchema).min(3).max(6).describe("比較・選択可能なサービス階層"),
}).strict().superRefine((data, ctx) => {
const ids = data.tiers.map(({ id }) => id);
if (new Set(ids).size !== ids.length) {
ctx.addIssue({ code: "custom", path: ["tiers"], message: "階層IDは一意にすること" });
}
data.tiers.forEach((tier, index) => {
if (tier.p1ResponseMinutes > tier.p2ResponseMinutes) {
ctx.addIssue({ code: "custom", path: ["tiers", index, "p1ResponseMinutes"], message: "P1はP2より優先して短い応答目標にすること" });
}
if (index > 0) {
const prior = data.tiers[index - 1];
if (tier.availabilityPercent <= prior.availabilityPercent) {
ctx.addIssue({ code: "custom", path: ["tiers", index, "availabilityPercent"], message: "上位階層ほど稼働率保証を高くすること" });
}
if (tier.p1ResponseMinutes > prior.p1ResponseMinutes || tier.p2ResponseMinutes > prior.p2ResponseMinutes) {
ctx.addIssue({ code: "custom", path: ["tiers", index], message: "上位階層の応答目標を下位階層より遅くできない" });
}
if (tier.creditCapPercent < prior.creditCapPercent) {
ctx.addIssue({ code: "custom", path: ["tiers", index, "creditCapPercent"], message: "上位階層の補償上限を下位階層より低くできない" });
}
}
});
});
export type Props = z.infer<typeof schema>;
/designs/service-tier-sla-matrix/source/meta.yaml
id: service-tier-sla-matrix
name:
ja: サービス階層・SLA比較表
en: Service Tier and SLA Comparison Matrix
purpose:
ja: サービス階層ごとの稼働率保証、障害応答、サポート時間、補償条件を同じ基準で比較する。
en: Compare availability, incident response, support coverage, and service credits consistently across service tiers.
status: published
still: ./still.png
category: service
catalogOrder: 875
jobs:
- compare-choose
- assign-governance
useCases:
- pricing
- comparison
layoutKinds:
- grid
- table
tags:
- service-level-agreement
- sla
- uptime
- support-coverage
- service-credit
whenToUse:
- ja: 顧客や契約階層に提示するサービス保証と補償条件を比較・合意するとき。
en: Use to compare and agree on service commitments and credits offered across customer tiers.
avoidWhen:
- ja: インシデントの重大度ごとに社内対応の引き継ぎ時間を決める場合は、インシデント対応方針を使う。
en: Use an incident response policy to set internal escalation times by incident severity.
requiredInputs:
- ja: 月間稼働率目標、優先度別初回応答時間、サポート時間・窓口、補償上限、測定除外を定義する。
en: Define monthly availability, priority response targets, support hours and route, credit cap, and measurement exclusions.
relatedLayouts:
- incident-escalation-policy
- comparison-table
dataSchema:
title: string — サービス水準の要点
subtitle: string? — 契約版・有効日・測定期間
service: string — サービスまたは契約対象
measurementWindow: string — 稼働率を計測する期間
tiers: array (3–6) — 稼働率、P1/P2応答時間、サポート条件、補償上限、除外条件
sources: []
/designs/service-tier-sla-matrix/source/sample-data.json
{
"title": "クリティカル業務には99.95%稼働率と30分以内のP1応答を適用する",
"subtitle": "Cloud Ledger SLA v4.0 · effective 2026-10-01",
"service": "Northstar Cloud Ledger",
"measurementWindow": "暦月・UTC集計",
"tiers": [
{ "id": "TIER-STANDARD", "name": "Standard", "availabilityPercent": 99.5, "p1ResponseMinutes": 120, "p2ResponseMinutes": 360, "supportHours": "平日 09:00–17:00 local", "supportRoute": "Support portal", "creditCapPercent": 5, "exclusions": "顧客側設定、予定保守、不可抗力による停止は稼働率から除く。" },
{ "id": "TIER-BUSINESS", "name": "Business", "availabilityPercent": 99.9, "p1ResponseMinutes": 60, "p2ResponseMinutes": 240, "supportHours": "24×5 · local business days", "supportRoute": "Priority queue + phone", "creditCapPercent": 10, "exclusions": "予定保守は72時間前告知を条件に計測対象外。顧客起因の停止を除く。" },
{ "id": "TIER-CRITICAL", "name": "Critical", "availabilityPercent": 99.95, "p1ResponseMinutes": 30, "p2ResponseMinutes": 120, "supportHours": "24×7 · all regions", "supportRoute": "Named duty manager bridge", "creditCapPercent": 15, "exclusions": "合意済み保守枠と利用規約違反による停止を対象外とする。" }
]
}