索引に戻る

ビジネス能力マップ(投資ギャップ)

グリッド
生成可能
ビジネス能力マップ(投資ギャップ)

作品として見る

持ち帰る

コピーして貼るか、ファイルに保存して渡す。ネットにつながらない環境には「全部入り」を 1 つ渡せば足りる。

全部入り

business-capability-map-everything.md

このパネルの中身を、URL の先にあるファイルの中身まで含めて 1 つにまとめた Markdown

依頼文

2.1 KB
「ビジネス能力マップ(投資ギャップ)」でHTML資料を作ってください。この型は実行できるので、版面を組み直す必要はありません — 必要なのは中身です。

## この型がすること
事業ドメインの内側へ能力を包含し、領域内工数比率を区画幅、成熟度を面、戦略優先度を境界へ写す。成熟度不足と優先度から最大投資ギャップを1件導出し、能力マップと根拠ledgerを同じidentityで切り替えて追える

## 渡す必要があるもの
- 能力を包含する事業・業務ドメイン
- 各能力の計画工数
- 各能力の成熟度と戦略優先度(ともに1〜5)

## 入力の形
- `title` — string — 最大投資ギャップを結論として書く
- `subtitle` — string(任意)— 評価時点・対象範囲・尺度・出典など
- `effortUnit` — string — 計画工数の単位(人月、ptなど)
- `domains` — { name, capabilities }[] — 能力を包含する事業・業務ドメイン(2〜5件)
- `domains[].capabilities` — { name, effort, maturity, strategicPriority, note? }[] — 各2〜5件。effortは正数、maturityとstrategicPriorityは1〜5整数

入力の機械可読な検証は schema.ts が持ちます。足りない入力は推測せず質問してください。

## 向かない場合
- 行と列の全交点を同じ尺度で比較したい場合
- 親子の因果分解や値の積み上げを枝として示したい場合

## 作り方
入力を JSON にまとめ、次を実行します。

```bash
node scripts/render.mjs business-capability-map <入力.json> --theme ink -o out.html
```

出力は 1 ファイルで完結し、外部から何も読み込みません。

## 原本
- https://design-vault.pages.dev/designs/business-capability-map/source/template.tsx
- https://design-vault.pages.dev/designs/business-capability-map/source/schema.ts
- https://design-vault.pages.dev/designs/business-capability-map/source/sample-data.json
- https://design-vault.pages.dev/designs/business-capability-map/sample.html

ファイル

テンプレート・入力スキーマ・サンプルデータ・メタ情報。この文書はこの 4 つから生成されています。 生成された文書

template.tsx

17.7 KB

/designs/business-capability-map/source/template.tsx

中身を見る
import { useId } from "react";
import type {
  BusinessCapability,
  BusinessCapabilityMapProps,
  CapabilityDomain,
} from "./schema";

export type FlatCapability = BusinessCapability & {
  domainName: string;
  domainIndex: number;
  capabilityIndex: number;
  originalIndex: number;
  identity: string;
  coordinate: string;
  gap: number;
  widthPercent: number;
};

export function capabilityGap(
  capability: Pick<BusinessCapability, "maturity" | "strategicPriority">,
) {
  return capability.strategicPriority * (6 - capability.maturity);
}

export function capabilityIdentity(domainIndex: number, capabilityIndex: number) {
  return `d${domainIndex}-c${capabilityIndex}`;
}

export function capabilityCoordinate(
  domainIndex: number,
  capabilityIndex: number,
) {
  return `D${String(domainIndex + 1).padStart(2, "0")} · C${String(
    capabilityIndex + 1,
  ).padStart(2, "0")}`;
}

export function capabilityWidthPercent(
  capability: Pick<BusinessCapability, "effort">,
  capabilities: readonly Pick<BusinessCapability, "effort">[],
) {
  const total = capabilities.reduce((sum, item) => sum + item.effort, 0);
  return total > 0 ? (capability.effort / total) * 100 : 0;
}

export function flattenCapabilities(
  domains: readonly CapabilityDomain[],
): FlatCapability[] {
  let originalIndex = 0;
  return domains.flatMap((domain, domainIndex) =>
    domain.capabilities.map((capability, capabilityIndex) => ({
      ...capability,
      domainName: domain.name,
      domainIndex,
      capabilityIndex,
      originalIndex: originalIndex++,
      identity: capabilityIdentity(domainIndex, capabilityIndex),
      coordinate: capabilityCoordinate(domainIndex, capabilityIndex),
      gap: capabilityGap(capability),
      widthPercent: capabilityWidthPercent(capability, domain.capabilities),
    })),
  );
}

export function rankedCapabilities(domains: readonly CapabilityDomain[]) {
  return flattenCapabilities(domains).sort(
    (a, b) => b.gap - a.gap || a.originalIndex - b.originalIndex,
  );
}

export function priorityCapability(domains: readonly CapabilityDomain[]) {
  return rankedCapabilities(domains)[0] ?? null;
}

const MATURITY_CLASSES = [
  "bg-surface-subtle",
  "bg-tertiary/10",
  "bg-tertiary/20",
  "bg-tertiary/30",
  "bg-tertiary/40",
] as const;

const PRIORITY_CLASSES = [
  "border-l-outline",
  "border-l-primary/30",
  "border-l-primary/50",
  "border-l-primary/70",
  "border-l-primary",
] as const;

function metricLabel(capability: BusinessCapability, effortUnit: string) {
  return `${capability.effort}${effortUnit} · M${capability.maturity} · P${capability.strategicPriority}`;
}

function capabilitySurfaceClass(capability: FlatCapability, priority: boolean) {
  if (priority) {
    return "border-tertiary bg-gradient-to-br from-tertiary to-accent-violet text-on-primary shadow-card";
  }
  return `border-outline ${MATURITY_CLASSES[capability.maturity - 1]} ${PRIORITY_CLASSES[capability.strategicPriority - 1]} text-on-surface`;
}

export default function BusinessCapabilityMap({
  title,
  subtitle,
  effortUnit,
  domains,
  instanceId,
}: BusinessCapabilityMapProps) {
  const autoId = useId();
  const uid =
    (instanceId ?? autoId).replace(
      // 捨てる操作は単射でないので、schema を通る別々の値が同じ id になる
      // (`sales:a` と `sales/a` がどちらも `salesa`)。同じ文書へ 2 つ置くと
      // id と radio の name が衝突して、片方の操作がもう片方に効く。
      // 逃がし文字(`_`)自身も逃がすので、この変換は単射。
      /[^a-zA-Z0-9-]/g,
      (c) => `_${c.charCodeAt(0).toString(16)}_`,
    ) || "capability-map";
  const radioName = `capability-view-${uid}`;
  const capabilities = flattenCapabilities(domains);
  const ranked = rankedCapabilities(domains);
  const priority = priorityCapability(domains);
  const notes = capabilities.filter((capability) => capability.note);
  const interactionCss = capabilities
    .map(
      (capability) => `
[data-capability-root="${uid}"]:has([data-capability-hotspot="${capability.identity}"]:is(:hover,:focus-visible)) [data-capability-surface="${capability.identity}"] {
  border-color: var(--color-primary);
  box-shadow: inset .2rem 0 0 var(--color-primary);
  filter: none;
}
[data-capability-root="${uid}"]:has([data-capability-hotspot="${capability.identity}"]:is(:hover,:focus-visible)) [data-capability-default-priority="true"]:not([data-capability-surface="${capability.identity}"]) {
  filter: saturate(.3) brightness(1.08);
}`,
    )
    .join("\n");

  return (
    <section
      data-capability-root={uid}
      className="group/capability mx-auto max-w-slide bg-surface p-12 font-sans text-on-surface"
    >
      <style>{interactionCss}</style>
      <header className="mb-6 flex flex-wrap items-end justify-between gap-4">
        <div className="max-w-4xl">
          <p className="mb-2 font-mono text-label text-tertiary">
            BUSINESS CAPABILITY PORTFOLIO
          </p>
          <h1 className="text-h1">{title}</h1>
          {subtitle && (
            <p className="mt-2 text-body-sm text-secondary">{subtitle}</p>
          )}
        </div>

        <div className="flex shrink-0 rounded-sm border border-outline bg-surface-subtle p-1 shadow-card">
          <input
            id={`${uid}-map`}
            type="radio"
            name={radioName}
            defaultChecked
            className="capability-view-map sr-only"
          />
          <label
            htmlFor={`${uid}-map`}
            className="cursor-pointer rounded-sm px-4 py-1.5 text-label text-secondary group-has-[.capability-view-map:checked]/capability:bg-primary group-has-[.capability-view-map:checked]/capability:text-on-primary group-has-[.capability-view-map:focus-visible]/capability:ring-2 group-has-[.capability-view-map:focus-visible]/capability:ring-tertiary"
          >
            能力マップ
          </label>
          <input
            id={`${uid}-gaps`}
            type="radio"
            name={radioName}
            className="capability-view-gaps sr-only"
          />
          <label
            htmlFor={`${uid}-gaps`}
            className="cursor-pointer rounded-sm px-4 py-1.5 text-label text-secondary group-has-[.capability-view-gaps:checked]/capability:bg-primary group-has-[.capability-view-gaps:checked]/capability:text-on-primary group-has-[.capability-view-gaps:focus-visible]/capability:ring-2 group-has-[.capability-view-gaps:focus-visible]/capability:ring-tertiary"
          >
            投資ギャップ
          </label>
        </div>
      </header>

      {priority && (
        <div className="mb-6 grid gap-3 border-y border-outline py-4 sm:grid-cols-[auto_minmax(0,1fr)_auto] sm:items-center sm:gap-6">
          <div>
            <p className="font-mono text-label text-tertiary">PRIORITY GAP</p>
            <p className="mt-0.5 font-mono text-h3">{priority.coordinate}</p>
          </div>
          <div className="min-w-0">
            <p className="text-label text-secondary">{priority.domainName}</p>
            <p className="font-semibold">{priority.name}</p>
          </div>
          <div className="sm:text-right">
            <p className="font-mono text-h2">{priority.gap}</p>
            <p className="font-mono text-label text-secondary">
              P{priority.strategicPriority} × (6 − M{priority.maturity})
            </p>
          </div>
        </div>
      )}

      <div className="block group-has-[.capability-view-gaps:checked]/capability:hidden">
        <div
          data-capability-view="map-desktop"
          className="hidden space-y-3 sm:block"
        >
          {domains.map((domain, domainIndex) => {
            const domainCapabilities = capabilities.filter(
              (capability) => capability.domainIndex === domainIndex,
            );
            const domainEffort = domain.capabilities.reduce(
              (sum, capability) => sum + capability.effort,
              0,
            );
            return (
              <div
                key={domain.name}
                data-capability-domain={domainIndex}
                className="grid grid-cols-[10rem_minmax(0,1fr)] border-y border-outline"
              >
                <div className="flex flex-col justify-between border-r border-outline bg-primary px-4 py-4 text-on-primary">
                  <div>
                    <p className="font-mono text-label text-on-primary/60">
                      D{String(domainIndex + 1).padStart(2, "0")}
                    </p>
                    <h2 className="mt-1 text-h3">{domain.name}</h2>
                  </div>
                  <p className="mt-4 font-mono text-label text-on-primary/70">
                    {domainEffort} {effortUnit}
                  </p>
                </div>
                <div className="flex min-w-0 gap-1 bg-outline p-1">
                  {domainCapabilities.map((capability) => {
                    const isPriority = capability.identity === priority?.identity;
                    return (
                      <article
                        key={capability.identity}
                        tabIndex={0}
                        data-capability-id={capability.identity}
                        data-capability-hotspot={capability.identity}
                        data-capability-surface={capability.identity}
                        data-capability-default-priority={
                          isPriority ? "true" : undefined
                        }
                        data-capability-gap={capability.gap}
                        data-capability-width={capability.widthPercent.toFixed(2)}
                        className={`min-w-0 border border-l-4 p-3 outline-none transition-[border-color,box-shadow,filter] duration-fast focus-visible:ring-2 focus-visible:ring-tertiary ${capabilitySurfaceClass(capability, isPriority)}`}
                        style={{
                          flexBasis: `${capability.widthPercent}%`,
                          flexGrow: capability.widthPercent,
                        }}
                        aria-label={`${domain.name}、${capability.name}、${metricLabel(capability, effortUnit)}`}
                      >
                        <p className="font-mono text-label opacity-70">
                          {capability.coordinate}
                        </p>
                        <p className="mt-2 break-words font-semibold leading-snug">
                          {capability.name}
                        </p>
                        <p className="mt-3 font-mono text-label opacity-80">
                          {metricLabel(capability, effortUnit)}
                        </p>
                      </article>
                    );
                  })}
                </div>
              </div>
            );
          })}
        </div>

        <div
          data-capability-view="map-mobile"
          className="space-y-5 sm:hidden"
        >
          {domains.map((domain, domainIndex) => (
            <section key={domain.name} data-capability-mobile-domain={domainIndex}>
              <div className="mb-2 flex items-baseline justify-between gap-3 border-b border-outline pb-2">
                <h2 className="text-h3">{domain.name}</h2>
                <span className="font-mono text-label text-secondary">
                  D{String(domainIndex + 1).padStart(2, "0")}
                </span>
              </div>
              <div className="space-y-1">
                {capabilities
                  .filter((capability) => capability.domainIndex === domainIndex)
                  .map((capability) => {
                    const isPriority = capability.identity === priority?.identity;
                    return (
                      <article
                        key={capability.identity}
                        tabIndex={0}
                        data-capability-id={capability.identity}
                        data-capability-hotspot={capability.identity}
                        data-capability-surface={capability.identity}
                        data-capability-default-priority={
                          isPriority ? "true" : undefined
                        }
                        data-capability-gap={capability.gap}
                        className={`grid min-w-0 grid-cols-[minmax(0,1fr)_auto] gap-3 border border-l-4 p-3 outline-none transition-[border-color,box-shadow,filter] duration-fast focus-visible:ring-2 focus-visible:ring-tertiary ${capabilitySurfaceClass(capability, isPriority)}`}
                      >
                        <div className="min-w-0">
                          <p className="break-words font-semibold">
                            {capability.name}
                          </p>
                          <div className="mt-2 h-1.5 overflow-hidden rounded-full bg-outline/60">
                            <span
                              className="block h-full bg-current opacity-50"
                              style={{ width: `${capability.widthPercent}%` }}
                            />
                          </div>
                        </div>
                        <div className="text-right font-mono text-label">
                          <p>{capability.effort}{effortUnit}</p>
                          <p className="mt-1 opacity-70">
                            M{capability.maturity} · P{capability.strategicPriority} · G{capability.gap}
                          </p>
                        </div>
                      </article>
                    );
                  })}
              </div>
            </section>
          ))}
        </div>
      </div>

      <div
        data-capability-view="gap-ledger"
        className="hidden group-has-[.capability-view-gaps:checked]/capability:block"
      >
        <div className="mb-3 grid grid-cols-[3rem_minmax(0,1fr)_auto] gap-3 border-b border-outline pb-2 font-mono text-label text-secondary">
          <span>RANK</span>
          <span>CAPABILITY / EVIDENCE</span>
          <span>GAP</span>
        </div>
        <div className="divide-y divide-outline border-b border-outline">
          {ranked.map((capability, index) => {
            const isPriority = capability.identity === priority?.identity;
            return (
              <article
                key={capability.identity}
                tabIndex={0}
                data-capability-id={capability.identity}
                data-capability-hotspot={capability.identity}
                data-capability-surface={capability.identity}
                data-capability-default-priority={isPriority ? "true" : undefined}
                data-capability-gap={capability.gap}
                className={`grid min-w-0 grid-cols-[3rem_minmax(0,1fr)_auto] items-center gap-3 border-l-4 px-2 py-3 outline-none transition-[border-color,box-shadow,filter] duration-fast focus-visible:ring-2 focus-visible:ring-tertiary ${isPriority ? "border-l-tertiary bg-gradient-to-r from-tertiary/20 to-transparent" : "border-l-transparent"}`}
              >
                <span className="font-mono text-label text-secondary">
                  {String(index + 1).padStart(2, "0")}
                </span>
                <div className="min-w-0">
                  <div className="flex flex-wrap items-baseline gap-x-3 gap-y-1">
                    <p className="font-semibold">{capability.name}</p>
                    <p className="text-label text-secondary">
                      {capability.domainName} · {capability.coordinate}
                    </p>
                  </div>
                  <div className="mt-2 h-1.5 overflow-hidden rounded-full bg-outline/60">
                    <span
                      className={isPriority ? "block h-full bg-gradient-to-r from-tertiary to-accent-violet" : "block h-full bg-primary"}
                      style={{ width: `${(capability.gap / 25) * 100}%` }}
                    />
                  </div>
                  <p className="mt-2 font-mono text-label text-secondary">
                    {capability.effort}{effortUnit} · 成熟度 M{capability.maturity} · 優先度 P{capability.strategicPriority}
                  </p>
                </div>
                <div className="text-right">
                  <p className="font-mono text-h3">{capability.gap}</p>
                  <p className="font-mono text-label text-secondary">/ 25</p>
                </div>
              </article>
            );
          })}
        </div>
      </div>

      <div className="mt-6 flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-outline pt-4 text-label text-secondary">
        <span className="font-mono">M = 成熟度</span>
        <span className="font-mono">P = 戦略優先度</span>
        <span className="font-mono">G = P × (6 − M)</span>
        <span>区画幅 = ドメイン内の{effortUnit}構成比</span>
      </div>

      {notes.length > 0 && (
        <details
          data-inline-disclosure="true"
          className="mt-6 border border-outline bg-surface-subtle"
        >
          <summary className="cursor-pointer px-4 py-3 font-semibold marker:text-tertiary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tertiary">
            補足を確認({notes.length}件)
          </summary>
          <div className="grid gap-3 border-t border-outline p-4 sm:grid-cols-2">
            {notes.map((capability) => (
              <article
                key={capability.identity}
                data-note-item="true"
                className="border-l-2 border-tertiary pl-3"
              >
                <p className="text-label text-secondary">
                  {capability.domainName} · {capability.coordinate}
                </p>
                <p className="mt-1 font-semibold">{capability.name}</p>
                <p className="mt-1 text-body-sm text-secondary">
                  {capability.note}
                </p>
              </article>
            ))}
          </div>
        </details>
      )}
    </section>
  );
}

schema.ts

1.8 KB

/designs/business-capability-map/source/schema.ts

中身を見る
import { z } from "zod";

export const businessCapabilitySchema = z
  .object({
    name: z.string().min(1).describe("能力名"),
    effort: z
      .number()
      .positive()
      .describe("同じドメイン内の能力区画幅へ反映する計画工数"),
    maturity: z
      .number()
      .int()
      .min(1)
      .max(5)
      .describe("現在の成熟度(1〜5。5が最も成熟)"),
    strategicPriority: z
      .number()
      .int()
      .min(1)
      .max(5)
      .describe("戦略優先度(1〜5。5が最優先)"),
    note: z
      .string()
      .optional()
      .describe("図の下の補足欄で明示的に展開する評価根拠"),
  })
  .strict();

export const capabilityDomainSchema = z
  .object({
    name: z.string().min(1).describe("事業・業務ドメイン名"),
    capabilities: z
      .array(businessCapabilitySchema)
      .min(2)
      .max(5)
      .describe("ドメインに含まれる能力(2〜5件)"),
  })
  .strict();

export const schema = z
  .object({
    title: z.string().min(1).describe("最大投資ギャップを結論として書くタイトル"),
    subtitle: z
      .string()
      .optional()
      .describe("評価時点、対象範囲、尺度、出典など"),
    effortUnit: z.string().min(1).describe("計画工数の単位(例: 人月、pt)"),
    domains: z
      .array(capabilityDomainSchema)
      .min(2)
      .max(5)
      .describe("能力を包含する事業・業務ドメイン(2〜5件)"),
    instanceId: z
      .string()
      .optional()
      .describe("同一ページに複数置く場合のビュー切替radio名の識別子"),
  })
  .strict();

export type BusinessCapability = z.infer<typeof businessCapabilitySchema>;
export type CapabilityDomain = z.infer<typeof capabilityDomainSchema>;
export type BusinessCapabilityMapProps = z.infer<typeof schema>;

meta.yaml

2.8 KB

/designs/business-capability-map/source/meta.yaml

中身を見る
id: business-capability-map
name:
  ja: "ビジネス能力マップ(投資ギャップ)"
  en: "Business Capability Map (Investment Gap)"
purpose:
  ja: "事業ドメインの内側へ能力を包含し、領域内工数比率を区画幅、成熟度を面、戦略優先度を境界へ写す。成熟度不足と優先度から最大投資ギャップを1件導出し、能力マップと根拠ledgerを同じidentityで切り替えて追える"
  en: "Capabilities nested inside business domains, with effort share as width, maturity as fill and strategic priority at the border. The largest investment gap follows from maturity against priority"
status: published
# 索引カードの図版。pnpm layout:render が原本から描く。
still: ./still.png
category: portfolio
catalogOrder: 140
jobs:
  - prioritize-diagnose
  - explain-structure
useCases:
  - org
layoutKinds:
  - grid
tags: [capability-map, enterprise-architecture, portfolio, maturity, investment, data-driven, interactive]
whenToUse:
  - ja: "全社・事業部の能力ポートフォリオと重点投資領域を一画面で合意したい場合"
    en: "Agreeing a capability portfolio and where to invest, on one screen"
  - ja: "現在成熟度と戦略重要度の差から、能力強化の着手順を説明したい場合"
    en: "Explaining the order to strengthen capabilities, from maturity against strategic weight"
  - ja: "EA・業務改革・中期IT投資でドメイン内の工数構成も同時に確認したい場合"
    en: "Seeing the effort mix inside a domain alongside an EA or investment discussion"
avoidWhen:
  - ja: "行と列の全交点を同じ尺度で比較したい場合"
    en: "Comparing every row-column intersection on one scale"
  - ja: "親子の因果分解や値の積み上げを枝として示したい場合"
    en: "Decomposing cause into parent and child, or stacking values on branches"
requiredInputs:
  - ja: "能力を包含する事業・業務ドメイン"
    en: "The domains the capabilities sit in"
  - ja: "各能力の計画工数"
    en: "The planned effort for each capability"
  - ja: "各能力の成熟度と戦略優先度(ともに1〜5)"
    en: "Its maturity and strategic priority, both 1-5"
relatedLayouts: [heatmap, logic-tree, kpi-cards]
dataSchema:
  title: "string — 最大投資ギャップを結論として書く"
  subtitle: "string(任意)— 評価時点・対象範囲・尺度・出典など"
  effortUnit: "string — 計画工数の単位(人月、ptなど)"
  domains: "{ name, capabilities }[] — 能力を包含する事業・業務ドメイン(2〜5件)"
  domains[].capabilities: "{ name, effort, maturity, strategicPriority, note? }[] — 各2〜5件。effortは正数、maturityとstrategicPriorityは1〜5整数"
sources: []

sample-data.json

2.3 KB

/designs/business-capability-map/source/sample-data.json

中身を見る
{
  "title": "能力投資の最優先は顧客データ統合 — 戦略重要度5・成熟度1の差を埋める",
  "subtitle": "次期中期計画に向けた能力仮説評価(成熟度・戦略優先度は5段階、工数は計画人月)",
  "effortUnit": "人月",
  "domains": [
    {
      "name": "顧客接点",
      "capabilities": [
        {
          "name": "顧客データ統合",
          "effort": 12,
          "maturity": 1,
          "strategicPriority": 5,
          "note": "顧客IDが販売・サポート・契約管理で分かれ、横断集計に月20時間を要する想定"
        },
        {
          "name": "マーケティング自動化",
          "effort": 8,
          "maturity": 3,
          "strategicPriority": 4
        },
        {
          "name": "提案・商談管理",
          "effort": 10,
          "maturity": 4,
          "strategicPriority": 4
        }
      ]
    },
    {
      "name": "供給・提供",
      "capabilities": [
        {
          "name": "需要予測",
          "effort": 9,
          "maturity": 2,
          "strategicPriority": 5,
          "note": "月次予測から週次予測へ短縮するため、販売実績と販促予定の統合が必要"
        },
        {
          "name": "在庫最適化",
          "effort": 12,
          "maturity": 3,
          "strategicPriority": 5
        },
        {
          "name": "仕入先連携",
          "effort": 9,
          "maturity": 4,
          "strategicPriority": 3
        }
      ]
    },
    {
      "name": "経営基盤",
      "capabilities": [
        {
          "name": "管理会計",
          "effort": 10,
          "maturity": 2,
          "strategicPriority": 4,
          "note": "製品別採算の確定を翌月第8営業日から第5営業日へ前倒しする想定"
        },
        {
          "name": "要員計画",
          "effort": 8,
          "maturity": 3,
          "strategicPriority": 3
        },
        {
          "name": "データガバナンス",
          "effort": 12,
          "maturity": 2,
          "strategicPriority": 5,
          "note": "重要データ項目のownerと品質基準を定義し、変更時の影響確認を標準化する想定"
        }
      ]
    }
  ],
  "instanceId": "enterprise-capability-portfolio"
}