コンテンツにスキップ

ER 図@RDB

データモデルパターン

汎用的なパターン

▼ Things, Thing Types, and Categories パターン

モノと、モノの種類と、種類を「車体の形」「動力」などの複数の分類体系で分類する分類を、それぞれ別のテーブルで表す。

「Type and Instance」と「Relationships」を組み合わせたパターンである。

erDiagram
  category_scheme["category_scheme テーブル"] {
    string id PK
    string name
  }

  category["category テーブル"] {
    string id PK
    string category_scheme_id FK
    string name
  }

  thing_type["thing_type テーブル"] {
    string id PK
    string name
  }

  thing_type_category["thing_type_category テーブル"] {
    string thing_type_id PK,FK
    string category_id PK,FK
  }

  thing["thing テーブル"] {
    string id PK
    string thing_type_id FK
    string name
  }

  category_scheme ||--o{ category : "持つ(1対多)"
  category ||--o{ thing_type_category : "分類する(1対多)"
  thing_type ||--o{ thing_type_category : "分類される(1対多)"
  thing_type ||--o{ thing : "種類である(1対多)"

▼ Type and Instance パターン

種類(型)と実際の個々のモノ(実体)を、種類に共通する情報を記録する種類テーブルと、個々のモノを記録する実体テーブルで表す。

erDiagram
  product_type["product_type テーブル"] {
    string id PK
    string name
    decimal list_price
  }

  product["product テーブル"] {
    string id PK
    string product_type_id FK
    string serial_number
  }

  product_type ||--o{ product : "実体になる(1対多)"

▼ Structure パターン

同じテーブルの行同士の親子関係(部品表や階層)を、親と子の組を記録する中間テーブルで表す。

erDiagram
  part["part テーブル"] {
    string id PK
    string name
  }

  part_structure["part_structure テーブル"] {
    string assembly_part_id PK,FK
    string component_part_id PK,FK
    int quantity
  }

  part ||--o{ part_structure : "親部品である(1対多)"
  part ||--o{ part_structure : "子部品である(1対多)"

▼ Heterogeneous Entities パターン

種類ごとに項目が異なるデータを、共通の項目を記録する親テーブルと、種類ごとの項目を記録する子テーブルで表す。

erDiagram
  asset["asset テーブル"] {
    string id PK
    string asset_kind
    string name
  }

  asset_equipment["asset_equipment テーブル"] {
    string asset_id PK,FK
    string model_number
  }

  asset_building["asset_building テーブル"] {
    string asset_id PK,FK
    decimal floor_area
  }

  asset_vehicle["asset_vehicle テーブル"] {
    string asset_id PK,FK
    string license_plate
  }

  asset ||--o| asset_equipment : "設備である(1対1)"
  asset ||--o| asset_building : "建物である(1対1)"
  asset ||--o| asset_vehicle : "車両である(1対1)"

▼ Roles パターン

誰が何にどの立場で関わるかを、当事者とモノと役割の種類をつなぐ役割テーブルで表す。

「Type and Instance」を応用したパターンである。

erDiagram
  party["party テーブル"] {
    string id PK
    string name
  }

  thing["thing テーブル"] {
    string id PK
    string name
  }

  role_type["role_type テーブル"] {
    string id PK
    string name
  }

  role["role テーブル"] {
    string id PK
    string party_id FK
    string thing_id FK
    string role_type_id FK
  }

  party ||--o{ role : "担う(1対多)"
  thing ||--o{ role : "対象になる(1対多)"
  role_type ||--o{ role : "種類である(1対多)"

▼ Addresses パターン

持ち主と住所を、別々のテーブルと、「自宅」「請求先」などの住所の使い道を記録する中間テーブルで表す。

erDiagram
  party["party テーブル"] {
    string id PK
    string name
  }

  address["address テーブル"] {
    string id PK
    string postal_code
    string street
  }

  party_address["party_address テーブル"] {
    string party_id PK,FK
    string address_id PK,FK
    string purpose
  }

  party ||--o{ party_address : "所在する(1対多)"
  address ||--o{ party_address : "使われる(1対多)"

▼ Resources パターン

人や資産などの資源を、共通の親テーブルと、どの活動でどの資源をどれだけ使ったかを記録する使用実績テーブルで表す。

「Heterogeneous Entities」を応用したパターンである。

erDiagram
  activity["activity テーブル"] {
    string id PK
    string name
  }

  resource["resource テーブル"] {
    string id PK
    string resource_kind
  }

  resource_person["resource_person テーブル"] {
    string resource_id PK,FK
    string name
  }

  resource_asset["resource_asset テーブル"] {
    string resource_id PK,FK
    string name
  }

  resource_usage["resource_usage テーブル"] {
    string id PK
    string activity_id FK
    string resource_id FK
    decimal quantity
  }

  activity ||--o{ resource_usage : "使う(1対多)"
  resource ||--o{ resource_usage : "使われる(1対多)"
  resource ||--o| resource_person : "人である(1対1)"
  resource ||--o| resource_asset : "資産である(1対1)"

▼ Relationships パターン

モノ同士のつながりを、つながりの元と先と種類を記録するテーブルで表す。

「Type and Instance」を応用したパターンである。

erDiagram
  thing["thing テーブル"] {
    string id PK
    string name
  }

  relationship_type["relationship_type テーブル"] {
    string id PK
    string name
  }

  thing_relationship["thing_relationship テーブル"] {
    string id PK
    string from_thing_id FK
    string to_thing_id FK
    string relationship_type_id FK
  }

  thing ||--o{ thing_relationship : "関係元である(1対多)"
  thing ||--o{ thing_relationship : "関係先である(1対多)"
  relationship_type ||--o{ thing_relationship : "種類である(1対多)"

▼ Variable Length Records パターン

項目の数や種類が決まっていないデータを、列ではなく、項目の定義と値をそれぞれ1行ずつ記録するテーブルで表す。

「Type and Instance」を応用したパターンである。

erDiagram
  record_type["record_type テーブル"] {
    string id PK
    string name
  }

  attribute_definition["attribute_definition テーブル"] {
    string id PK
    string record_type_id FK
    string name
    string data_type
  }

  record["record テーブル"] {
    string id PK
    string record_type_id FK
  }

  attribute_value["attribute_value テーブル"] {
    string record_id PK,FK
    string attribute_definition_id PK,FK
    string value
  }

  record_type ||--o{ attribute_definition : "定義する(1対多)"
  record_type ||--o{ record : "種類である(1対多)"
  record ||--o{ attribute_value : "持つ(1対多)"
  attribute_definition ||--o{ attribute_value : "定義する(1対多)"

▼ Usually One, Sometimes Many パターン

普通は1つだがまれに複数になるつながり(例:勤務先)を、主となるものを示すフラグの列を持つ中間テーブルで表す。

erDiagram
  person["person テーブル"] {
    string id PK
    string name
  }

  organization["organization テーブル"] {
    string id PK
    string name
  }

  employment["employment テーブル"] {
    string person_id PK,FK
    string organization_id PK,FK
    boolean is_primary
  }

  person ||--o{ employment : "雇用される(1対多)"
  organization ||--o{ employment : "雇用する(1対多)"

▼ Mathematical Expressions in the Data Model パターン

変数を計算する式を、演算子と順序を持つ項を1行ずつ記録するテーブルで表す。

erDiagram
  variable["variable テーブル"] {
    string id PK
    string name
  }

  formula_term["formula_term テーブル"] {
    string id PK
    string calculated_variable_id FK
    string operand_variable_id FK
    int sequence
    string operator
  }

  variable ||--o{ formula_term : "計算される(1対多)"
  variable ||--o{ formula_term : "被演算子になる(1対多)"

▼ The Universal Data Model パターン

あらゆるモノを、種類・項目・つながりのテーブルの組み合わせだけで表す。

「Things, Thing Types, and Categories」と「Variable Length Records」と「Relationships」を組み合わせたパターンである。

erDiagram
  thing_type["thing_type テーブル"] {
    string id PK
    string name
  }

  thing["thing テーブル"] {
    string id PK
    string thing_type_id FK
    string name
  }

  attribute_type["attribute_type テーブル"] {
    string id PK
    string thing_type_id FK
    string name
  }

  attribute_value["attribute_value テーブル"] {
    string thing_id PK,FK
    string attribute_type_id PK,FK
    string value
  }

  thing_relationship["thing_relationship テーブル"] {
    string id PK
    string from_thing_id FK
    string to_thing_id FK
  }

  thing_type ||--o{ thing : "種類である(1対多)"
  thing_type ||--o{ attribute_type : "定義する(1対多)"
  thing ||--o{ attribute_value : "持つ(1対多)"
  attribute_type ||--o{ attribute_value : "定義する(1対多)"
  thing ||--o{ thing_relationship : "関係元である(1対多)"
  thing ||--o{ thing_relationship : "関係先である(1対多)"


ドメイン領域に特化したパターン

▼ Parties パターン

人と組織を、契約や住所などの相手として同じ形で紐づけられる「当事者(Party)」という共通の親テーブルで表す。

「Heterogeneous Entities」を応用したパターンである。

erDiagram
  party["party テーブル"] {
    string id PK
    string party_kind
  }

  party_person["party_person テーブル"] {
    string party_id PK,FK
    string first_name
    string last_name
  }

  party_organization["party_organization テーブル"] {
    string party_id PK,FK
    string name
  }

  party ||--o| party_person : "人である(1対1)"
  party ||--o| party_organization : "組織である(1対1)"

▼ Employee Assignments パターン

組織の職位と人を、別々のテーブルと、誰がどの職位にいつからいつまで就いていたかを記録する配属テーブルで表す。

「Relationships」を応用したパターンである。

erDiagram
  organization["organization テーブル"] {
    string id PK
    string name
  }

  position["position テーブル"] {
    string id PK
    string organization_id FK
    string title
  }

  person["person テーブル"] {
    string id PK
    string name
  }

  position_assignment["position_assignment テーブル"] {
    string id PK
    string position_id FK
    string person_id FK
    date start_date
    date end_date
  }

  organization ||--o{ position : "持つ(1対多)"
  position ||--o{ position_assignment : "就任される(1対多)"
  person ||--o{ position_assignment : "配属される(1対多)"

▼ Reporting Relationships パターン

上司と部下などの報告関係を、上位と下位の当事者と関係の種類を記録するテーブルで表す。

「Relationships」を応用したパターンである。

erDiagram
  party["party テーブル"] {
    string id PK
    string name
  }

  reporting_relationship_type["reporting_relationship_type テーブル"] {
    string id PK
    string name
  }

  reporting_relationship["reporting_relationship テーブル"] {
    string id PK
    string superior_party_id FK
    string subordinate_party_id FK
    string reporting_relationship_type_id FK
  }

  party ||--o{ reporting_relationship : "上位である(1対多)"
  party ||--o{ reporting_relationship : "下位である(1対多)"
  reporting_relationship_type ||--o{ reporting_relationship : "種類である(1対多)"

▼ Geographic Locations パターン

国や都市などの地域の階層を、親の地域を指す列を持つ地域テーブルと、いずれかの地域に属する拠点テーブルで表す。

「Structure」を応用したパターンである。

erDiagram
  geographic_area["geographic_area テーブル"] {
    string id PK
    string parent_geographic_area_id FK
    string name
    string area_kind
  }

  site["site テーブル"] {
    string id PK
    string geographic_area_id FK
    string name
  }

  geographic_area ||--o{ geographic_area : "含む(1対多)"
  geographic_area ||--o{ site : "含む(1対多)"

▼ Products and Product Types パターン

製品の種類と個々の製品を、別々のテーブルと、製品の種類同士の構成(どの部品が何個必要か)を記録するテーブルで表す。

「Type and Instance」と「Structure」を組み合わせたパターンである。

erDiagram
  product_type["product_type テーブル"] {
    string id PK
    string name
  }

  discrete_item["discrete_item テーブル"] {
    string id PK
    string product_type_id FK
    string serial_number
  }

  product_type_structure["product_type_structure テーブル"] {
    string assembly_product_type_id PK,FK
    string component_product_type_id PK,FK
    int quantity
  }

  product_type ||--o{ discrete_item : "具現化される(1対多)"
  product_type ||--o{ product_type_structure : "親部品である(1対多)"
  product_type ||--o{ product_type_structure : "子部品である(1対多)"

▼ Inventory パターン

どの製品の種類がどの拠点にいくつあるかを、在庫テーブルで表す。

erDiagram
  product_type["product_type テーブル"] {
    string id PK
    string name
  }

  site["site テーブル"] {
    string id PK
    string name
  }

  inventory["inventory テーブル"] {
    string product_type_id PK,FK
    string site_id PK,FK
    decimal quantity
  }

  product_type ||--o{ inventory : "在庫になる(1対多)"
  site ||--o{ inventory : "保管する(1対多)"

▼ Work Orders パターン

作業指示を、複数の作業のテーブルと、作業ごとに誰が何時間働き、どの資産を何時間使ったかを記録するテーブルで表す。

「Resources」を応用したパターンである。

erDiagram
  work_order["work_order テーブル"] {
    string id PK
    string description
  }

  work_order_task["work_order_task テーブル"] {
    string id PK
    string work_order_id FK
    string name
  }

  person["person テーブル"] {
    string id PK
    string name
  }

  labor_usage["labor_usage テーブル"] {
    string id PK
    string work_order_task_id FK
    string person_id FK
    decimal hours
  }

  asset["asset テーブル"] {
    string id PK
    string name
  }

  asset_usage["asset_usage テーブル"] {
    string id PK
    string work_order_task_id FK
    string asset_id FK
    decimal hours
  }

  work_order ||--o{ work_order_task : "構成される(1対多)"
  work_order_task ||--o{ labor_usage : "使う(1対多)"
  person ||--o{ labor_usage : "作業する(1対多)"
  work_order_task ||--o{ asset_usage : "使う(1対多)"
  asset ||--o{ asset_usage : "使われる(1対多)"

▼ Purchase Orders and Sales Orders パターン

発注と受注を、買い手と売り手を記録する注文テーブルと、製品ごとの数量と単価を記録する明細テーブルで表す。

「Parties」を応用したパターンである。

erDiagram
  party["party テーブル"] {
    string id PK
    string name
  }

  purchase_order["purchase_order テーブル"] {
    string id PK
    string buyer_party_id FK
    string seller_party_id FK
    datetime ordered_at
  }

  product_type["product_type テーブル"] {
    string id PK
    string name
  }

  line_item["line_item テーブル"] {
    string id PK
    string purchase_order_id FK
    string product_type_id FK
    int quantity
    decimal unit_price
  }

  party ||--o{ purchase_order : "買い手になる(1対多)"
  party ||--o{ purchase_order : "売り手になる(1対多)"
  purchase_order ||--o{ line_item : "構成される(1対多)"
  product_type ||--o{ line_item : "注文される(1対多)"

▼ Contract Roles パターン

契約にどの当事者がどの立場(売り手、保証人など)で関わるかを、契約の役割テーブルで表す。

「Roles」を応用したパターンである。

erDiagram
  contract["contract テーブル"] {
    string id PK
    date signed_on
  }

  party["party テーブル"] {
    string id PK
    string name
  }

  contract_role_type["contract_role_type テーブル"] {
    string id PK
    string name
  }

  contract_role["contract_role テーブル"] {
    string contract_id PK,FK
    string party_id PK,FK
    string contract_role_type_id FK
  }

  contract ||--o{ contract_role : "関わる(1対多)"
  party ||--o{ contract_role : "担う(1対多)"
  contract_role_type ||--o{ contract_role : "種類である(1対多)"

▼ Basic Bookkeeping パターン

1つの取引を、取引テーブルと、勘定ごとの借方と貸方を記録する仕訳テーブルで表す。

erDiagram
  accounting_transaction["accounting_transaction テーブル"] {
    string id PK
    date transaction_date
    string description
  }

  account["account テーブル"] {
    string id PK
    string name
    string account_kind
  }

  accounting_entry["accounting_entry テーブル"] {
    string id PK
    string accounting_transaction_id FK
    string account_id FK
    decimal amount
    string debit_or_credit
  }

  accounting_transaction ||--o{ accounting_entry : "構成される(1対多)"
  account ||--o{ accounting_entry : "記帳される(1対多)"

▼ Samples, Tests, and Observations パターン

サンプルに対する検査と、検査で測った項目ごとの値(観測値)を、別々のテーブルで表す。

「Type and Instance」を応用したパターンである。

erDiagram
  sample["sample テーブル"] {
    string id PK
    datetime collected_at
  }

  test_type["test_type テーブル"] {
    string id PK
    string name
  }

  test["test テーブル"] {
    string id PK
    string sample_id FK
    string test_type_id FK
    datetime tested_at
  }

  variable["variable テーブル"] {
    string id PK
    string name
    string unit
  }

  observation["observation テーブル"] {
    string id PK
    string test_id FK
    string variable_id FK
    decimal value
  }

  sample ||--o{ test : "検査される(1対多)"
  test_type ||--o{ test : "種類である(1対多)"
  test ||--o{ observation : "生み出す(1対多)"
  variable ||--o{ observation : "測定される(1対多)"

▼ Material Requirements Planning パターン

完成品の生産計画と、部品表と、部品がいつ何個必要かを計算した発注の計画を、それぞれ別のテーブルで表す。

「Products and Product Types」を応用したパターンである。

erDiagram
  product_type["product_type テーブル"] {
    string id PK
    string name
  }

  product_type_structure["product_type_structure テーブル"] {
    string assembly_product_type_id PK,FK
    string component_product_type_id PK,FK
    int quantity
  }

  master_schedule_item["master_schedule_item テーブル"] {
    string id PK
    string product_type_id FK
    date due_date
    int quantity
  }

  firm_planned_order["firm_planned_order テーブル"] {
    string id PK
    string product_type_id FK
    date due_date
    int quantity
  }

  product_type ||--o{ master_schedule_item : "計画される(1対多)"
  product_type ||--o{ product_type_structure : "親部品である(1対多)"
  product_type ||--o{ product_type_structure : "子部品である(1対多)"
  product_type ||--o{ firm_planned_order : "注文される(1対多)"

▼ Monitoring Processes パターン

資産に付けた測定点(タグ)と、測定点ごとに測定した時刻と値を記録するテーブルで表す。

「Samples, Tests, and Observations」を応用したパターンである。

erDiagram
  asset["asset テーブル"] {
    string id PK
    string name
  }

  variable["variable テーブル"] {
    string id PK
    string name
    string unit
  }

  tag["tag テーブル"] {
    string id PK
    string asset_id FK
    string variable_id FK
    string name
  }

  tag_value["tag_value テーブル"] {
    string tag_id PK,FK
    datetime time PK
    decimal value
  }

  asset ||--o{ tag : "監視される(1対多)"
  variable ||--o{ tag : "測定される(1対多)"
  tag ||--o{ tag_value : "記録する(1対多)"

▼ The Document パターン

文書の種類、文書同士の構成(章や添付など)、文書に誰がどの立場(作成者、受領者など)で関わるかを、それぞれ別のテーブルで表す。

「Type and Instance」と「Structure」と「Roles」を組み合わせたパターンである。

erDiagram
  document_type["document_type テーブル"] {
    string id PK
    string name
  }

  document["document テーブル"] {
    string id PK
    string document_type_id FK
    string title
  }

  document_structure["document_structure テーブル"] {
    string parent_document_id PK,FK
    string child_document_id PK,FK
    int sequence
  }

  party["party テーブル"] {
    string id PK
    string name
  }

  document_role["document_role テーブル"] {
    string document_id PK,FK
    string party_id PK,FK
    string role_name
  }

  document_type ||--o{ document : "種類である(1対多)"
  document ||--o{ document_structure : "含む(1対多)"
  document ||--o{ document_structure : "一部である(1対多)"
  document ||--o{ document_role : "関わる(1対多)"
  party ||--o{ document_role : "担う(1対多)"

▼ Versions パターン

文書の版を、文書とは別のテーブルで表し、どの版がどの版を置き換えたかを、前の版を指す列で表す。

「Structure」を応用したパターンである。

erDiagram
  document["document テーブル"] {
    string id PK
    string title
  }

  document_version["document_version テーブル"] {
    string id PK
    string document_id FK
    string superseded_document_version_id FK
    int version_number
  }

  document ||--o{ document_version : "持つ(1対多)"
  document_version ||--o| document_version : "置き換える(1対1)"


事例

マルチテナントの場合

マルチテナントでは、tenant テーブルをデータ分離の境界として扱う。

flowchart TB
  subgraph tenant["tenant"]
    user["user"]
    tenant_token["tenant_token"]
    quota["quota"]

    subgraph workspace["workspace"]
      foo["foo"]
      bar["bar"]
    end
  end

  role["role"]
  policy["policy"]

  user --> role
  tenant_token --> role
  role --> policy

ここでは「Roles パターン」を使用する。

tenant テーブルを境界として見ると、workspace テーブルや foo テーブル、bar テーブルは tenant テーブルの内側にある。

user テーブルや workspace テーブルなどのテナント配下のテーブルは tenant_id を持つ。

これにより、認可後の Read 処理を tenant 単位で絞り込める。

workspace テーブル配下のデータも tenant_id を含むキーで親子関係を表す。

role テーブルと policy テーブルは user テーブルや tenant_token テーブルに紐づけ、画面操作や API 操作の権限を表現する(Roles パターン)。

role_policy のような中間テーブルを用意すると、テーブル間を多対多で紐付けられる。

テーブル 役割
tenant マルチテナントにおけるデータ分離の単位
user tenant に所属する利用者。role を通じて操作権限を持つ
tenant_token tenant に紐づく API アクセス用のトークン。user と同様に role を持つ
role user や tenant_token に割り当てる権限のまとまり
policy 画面や API に対する操作可否を表すルール
role_policy role と policy を多対多で紐づける中間テーブル
workspace tenant 配下で業務データをまとめる作業領域
quota tenant ごとの利用上限
foo workspace 配下に作成される業務データの例 1
bar workspace 配下に作成される業務データの例 2
erDiagram
  tenant ||--o{ user : "持つ(1対多)"
  tenant ||--o{ tenant_token : "持つ(1対多)"
  tenant ||--o{ workspace : "所有する(1対多)"
  tenant ||--o{ quota : "持つ(1対多)"

  user }o--|| role : "割り当てられる(多対1)"
  tenant_token }o--|| role : "割り当てられる(多対1)"
  role ||--o{ role_policy : "持つ(1対多)"
  policy ||--o{ role_policy : "使われる(1対多)"

  workspace ||--o{ foo : "持つ(1対多)"
  workspace ||--o{ bar : "持つ(1対多)"

  tenant["tenant テーブル"] {
    string id PK
    string name UK
    string default_role
  }

  user["user テーブル"] {
    string id PK
    string tenant_id FK
    string email
    string role_name FK
  }

  tenant_token["tenant_token テーブル"] {
    string tenant_id PK,FK
    string name PK
    string token UK
    string role_name FK
  }

  role["role テーブル"] {
    string name PK
    string scope
  }

  policy["policy テーブル"] {
    string name PK
    string context
  }

  role_policy["role_policy テーブル"] {
    string role_name PK,FK
    string policy_name PK,FK
  }

  workspace["workspace テーブル"] {
    string tenant_id PK,FK
    string name PK
  }

  quota["quota テーブル"] {
    string tenant_id PK,FK
    string resource PK
  }

  foo["foo テーブル"] {
    string tenant_id PK,FK
    string workspace_name PK,FK
    string name PK
  }

  bar["bar テーブル"] {
    string tenant_id PK,FK
    string workspace_name PK,FK
    string name PK
  }


監視ドメインの場合

監視ドメインでは、監視の設定(monitor テーブル)と監視の結果(check_result テーブル)を分けて扱う。

ここでは「Heterogeneous Entities パターン」「Monitoring Processes パターン」「Relationships パターン」を使用する。

monitor テーブルは監視の種類に共通する設定を記録し、種類ごとの設定は monitor_http テーブルや monitor_tls テーブルに記録する(Heterogeneous Entities パターン)。

check_result テーブルは、監視の設定とリージョンごとに、実行した時刻と結果を記録する(Monitoring Processes パターン)。

incident テーブルは、インシデントの根拠になった監視の結果を incident_check_result テーブルで紐づける(Relationships パターン)。

erDiagram
  project["project テーブル"] {
    string id PK
    string name
  }

  monitor["monitor テーブル"] {
    string id PK
    string project_id FK
    string name
    string monitor_kind
    string schedule
  }

  monitor_http["monitor_http テーブル"] {
    string monitor_id PK,FK
    string url
    int expected_status_code
  }

  monitor_tls["monitor_tls テーブル"] {
    string monitor_id PK,FK
    string hostname
    int port
  }

  region["region テーブル"] {
    string id PK
    string name
  }

  monitor_region["monitor_region テーブル"] {
    string monitor_id PK,FK
    string region_id PK,FK
    boolean enabled
  }

  check_result["check_result テーブル"] {
    string id PK
    string monitor_id FK
    string region_id FK
    datetime checked_at
    string status
    int response_time_ms
  }

  incident["incident テーブル"] {
    string id PK
    string monitor_id FK
    string status
    datetime opened_at
    datetime resolved_at
  }

  incident_check_result["incident_check_result テーブル"] {
    string incident_id PK,FK
    string check_result_id PK,FK
  }

  project ||--o{ monitor : "持つ(1対多)"
  monitor ||--o| monitor_http : "HTTP監視である(1対1)"
  monitor ||--o| monitor_tls : "TLS監視である(1対1)"
  monitor ||--o{ monitor_region : "実行される(1対多)"
  region ||--o{ monitor_region : "実行する(1対多)"
  monitor ||--o{ check_result : "記録する(1対多)"
  region ||--o{ check_result : "記録する(1対多)"
  monitor ||--o{ incident : "起票される(1対多)"
  incident ||--o{ incident_check_result : "根拠にする(1対多)"
  check_result ||--o{ incident_check_result : "根拠になる(1対多)"