Back to index

Integration Contract Catalog

Stack
Generates documents
Integration Contract Catalog

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

integration-contract-catalog-everything.md

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

Prompt

1.5 KB
Build an HTML document with "Integration Contract Catalog". This layout runs, so there is no composition to rebuild — what it needs is content.

## What this layout does
Integration Contract Catalog 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? — 出典・時点・母集団や仮定
- `interfaces` — array (from, id, to, payload, mode, frequency, owner, failure) — 連携ID・接続先・データ・方式・頻度・保守責任・失敗時動作

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 integration-contract-catalog <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/integration-contract-catalog/source/template.tsx
- https://design-vault.pages.dev/designs/integration-contract-catalog/source/schema.ts
- https://design-vault.pages.dev/designs/integration-contract-catalog/source/sample-data.json
- https://design-vault.pages.dev/designs/integration-contract-catalog/sample.html

Files

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

template.tsx

6.6 KB

/designs/integration-contract-catalog/source/template.tsx

Show contents
import type { ReactNode } from "react";
import type { Props } from "./schema";
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 modes={sync:"同期",async:"非同期",batch:"バッチ"};
return <section className="asset asset-integration-contract-catalog"><style>{CSS}</style><header><p className="eyebrow">INTEGRATION CONTRACT CATALOG</p><h1>{d.title}</h1>{d.subtitle && <p className="subtitle">{d.subtitle}</p>}</header>
<div className="stack">{d.interfaces.map(r=><article className="panel" key={r.id}><div className="flex"><h2>{r.from} → {r.to}</h2><span className="pill">{r.id} / {modes[r.mode]} / {r.frequency}</span></div><div className="grid2"><p>{r.payload}</p><p>失敗時:{r.failure}</p></div><p className="meta-line">保守責任:{r.owner}</p></article>)}</div><Notes><p>矢印はデータを送る向きです。呼出し元とレスポンスの方向が異なる場合は、連携を分けて記録します。</p></Notes>
<footer>連携方式と頻度は別項目。担当の空欄を認めない。</footer></section>;
}

schema.ts

832 B

/designs/integration-contract-catalog/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("出典・時点・母集団や仮定"),
  interfaces:z.array(z.object({id:short,from:short,to:short,payload:text,mode:z.enum(["sync","async","batch"]),frequency:short,owner:short,failure:text}).strict()).min(2).max(8).describe("連携ID・接続先・データ・方式・頻度・保守責任・失敗時動作"),
}).strict().refine(d=>unique(d.interfaces.map(r=>r.id)),"連携IDは一意");
export type Props = z.infer<typeof schema>;

meta.yaml

1.4 KB

/designs/integration-contract-catalog/source/meta.yaml

Show contents
id: integration-contract-catalog
name:
  ja: システム連携の契約一覧
  en: Integration Contract Catalog
purpose:
  ja: 送信元・送信先・方式・頻度・責任者・障害時動作を揃えて比較する。
  en: Integration Contract Catalog with explicit source values and reading conditions.
status: published
still: ./still.png
category: specification
catalogOrder: 630
jobs:
  - trace-flow
useCases:
  - process
layoutKinds:
  - stack
tags:
  - integration-contract-catalog
  - specification
  - offline
  - responsive
whenToUse:
  - ja: 送信元・送信先・方式・頻度・責任者・障害時動作を揃えて比較する。
    en: Use to communicate integration contract catalog.
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:
  - system-landscape-map
  - api-contract-sheet
dataSchema:
  title: string — 結論を伝える見出し
  subtitle: string? — 出典・時点・母集団や仮定
  interfaces: array (from, id, to, payload, mode, frequency, owner, failure) — 連携ID・接続先・データ・方式・頻度・保守責任・失敗時動作
sources: []

sample-data.json

900 B

/designs/integration-contract-catalog/source/sample-data.json

Show contents
{
  "title": "連携の方式だけでなく、失敗時の責任を明確にする",
  "subtitle": "架空サンプル|レイアウトの使用例",
  "interfaces": [
    {
      "from": "受付",
      "id": "IF1",
      "to": "審査",
      "payload": "申込情報",
      "mode": "async",
      "frequency": "随時",
      "owner": "連携担当",
      "failure": "再送キューへ退避"
    },
    {
      "from": "審査",
      "id": "IF2",
      "to": "契約",
      "payload": "審査結果",
      "mode": "sync",
      "frequency": "照会時",
      "owner": "審査担当",
      "failure": "エラーを返し手動確認"
    },
    {
      "from": "契約",
      "id": "IF3",
      "to": "分析",
      "payload": "契約実績",
      "mode": "batch",
      "frequency": "日次",
      "owner": "データ担当",
      "failure": "翌朝までに再実行"
    }
  ]
}