Back to index

Service Blueprint

Table
Generates documents
Service Blueprint

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-blueprint-everything.md

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

Prompt

1.3 KB
Build an HTML document with "Service Blueprint". This layout runs, so there is no composition to rebuild — what it needs is content.

## What this layout does
Service Blueprint 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? — 出典・時点・母集団や仮定
- `stages` — array (label, customer, frontstage, backstage, support, evidence) — 工程と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 service-blueprint <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-blueprint/source/template.tsx
- https://design-vault.pages.dev/designs/service-blueprint/source/schema.ts
- https://design-vault.pages.dev/designs/service-blueprint/source/sample-data.json
- https://design-vault.pages.dev/designs/service-blueprint/sample.html

Files

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

template.tsx

7.1 KB

/designs/service-blueprint/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 layers=[{key:"customer",label:"顧客行動"},{key:"frontstage",label:"対面・画面の対応"},{key:"backstage",label:"内部の処理"},{key:"support",label:"支援基盤"},{key:"evidence",label:"顧客に残るもの"}] as const;
return <section className="asset asset-service-blueprint"><style>{CSS}</style><header><p className="eyebrow">SERVICE BLUEPRINT</p><h1>{d.title}</h1>{d.subtitle && <p className="subtitle">{d.subtitle}</p>}</header>
<div className="desktop-only"><Ledger heads={["層",...d.stages.map(s=>s.label)]} rows={layers.map(l=>[l.label,...d.stages.map(s=>s[l.key])])}/></div><div className="mobile-only stack">{d.stages.map((s,i)=><article className="panel" key={i}><h2>{s.label}</h2><Ledger heads={["層","内容"]} rows={layers.map(l=>[l.label,s[l.key]])}/></article>)}</div><Notes><p>表の対応と裏の処理の境界を明確にします。各列は同じ工程を示し、異なる時間粒度を混在させません。</p></Notes>
<footer>各工程で顧客・業務・システムの対応を縦に読めるようにする。</footer></section>;
}

schema.ts

592 B

/designs/service-blueprint/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();

export const schema = z.object({
  title: text.describe("結論を伝える見出し"),
  subtitle: text.optional().describe("出典・時点・母集団や仮定"),
  stages:z.array(z.object({label:short,customer:text,frontstage:text,backstage:text,support:text,evidence:short}).strict()).min(3).max(5).describe("工程と5つの対応層"),
}).strict();
export type Props = z.infer<typeof schema>;

meta.yaml

1.3 KB

/designs/service-blueprint/source/meta.yaml

Show contents
id: service-blueprint
name:
  ja: サービス提供のブループリント
  en: Service Blueprint
purpose:
  ja: 顧客行動・表の対応・裏の処理・支援基盤を同じ工程列で揃える。
  en: Service Blueprint with explicit source values and reading conditions.
status: published
still: ./still.png
category: operations
catalogOrder: 580
jobs:
  - trace-flow
useCases:
  - process
layoutKinds:
  - table
tags:
  - service-blueprint
  - operations
  - offline
  - responsive
whenToUse:
  - ja: 顧客行動・表の対応・裏の処理・支援基盤を同じ工程列で揃える。
    en: Use to communicate service blueprint.
avoidWhen:
  - ja: 同じ条件・単位で比較できないデータには使わない
    en: Do not compare values with incompatible units, populations, or assumptions.
requiredInputs:
  - ja: 各工程で顧客・業務・システムの対応を縦に読めるようにする。
    en: Provide the source values, labels and decision conditions described by the schema.
relatedLayouts:
  - customer-journey-map
  - swimlane-process
dataSchema:
  title: string — 結論を伝える見出し
  subtitle: string? — 出典・時点・母集団や仮定
  stages: array (label, customer, frontstage, backstage, support, evidence) — 工程と5つの対応層
sources: []

sample-data.json

867 B

/designs/service-blueprint/source/sample-data.json

Show contents
{
  "title": "顧客に見えない確認待ちを、提供工程から把握する",
  "subtitle": "架空サンプル|レイアウトの使用例",
  "stages": [
    {
      "label": "申込",
      "customer": "情報を入力",
      "frontstage": "必須項目を案内",
      "backstage": "重複申込を確認",
      "support": "受付API",
      "evidence": "受付番号"
    },
    {
      "label": "確認",
      "customer": "証憑を提出",
      "frontstage": "不足書類を案内",
      "backstage": "本人確認を実施",
      "support": "確認サービス",
      "evidence": "確認通知"
    },
    {
      "label": "契約",
      "customer": "内容を確認",
      "frontstage": "条件と手順を説明",
      "backstage": "承認結果を登録",
      "support": "契約基盤",
      "evidence": "契約控え"
    }
  ]
}