Back to index

Service Tier and SLA Comparison Matrix

Grid
Generates documents
Service Tier and SLA Comparison Matrix

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

service-tier-sla-matrix-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 "Service Tier and SLA Comparison Matrix". This layout runs, so there is no composition to rebuild — what it needs is content.

## What this layout does
Compare availability, incident response, support coverage, and service credits consistently across service tiers.

## What you have to supply
- Define monthly availability, priority response targets, support hours and route, credit cap, and measurement exclusions.

## The shape of the input
- `title` — string — サービス水準の要点
- `subtitle` — string? — 契約版・有効日・測定期間
- `service` — string — サービスまたは契約対象
- `measurementWindow` — string — 稼働率を計測する期間
- `tiers` — array (3–6) — 稼働率、P1/P2応答時間、サポート条件、補償上限、除外条件

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

## When not to use it
- Use an incident response policy to set internal escalation times by incident severity.

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

```bash
node scripts/render.mjs service-tier-sla-matrix <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/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

Files

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

template.tsx

6.8 KB

/designs/service-tier-sla-matrix/source/template.tsx

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

schema.ts

2.6 KB

/designs/service-tier-sla-matrix/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 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>;

meta.yaml

1.8 KB

/designs/service-tier-sla-matrix/source/meta.yaml

Show contents
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: []

sample-data.json

1.3 KB

/designs/service-tier-sla-matrix/source/sample-data.json

Show contents
{
  "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": "合意済み保守枠と利用規約違反による停止を対象外とする。" }
  ]
}