背景・目的
前回は、AWS Diagram MCP Server を使用して AWS ダイアグラムを自動生成しました。
この方法では画像を自動的に生成できますが、コードとしての管理ができません。
そこで今回は、コードで管理できる形式を採用するため、draw.io を使用して出力します。
また、E-R 図は PlantUML を用いて生成してみます。
実践
Drawio形式でAWSアーキテクチャを生成する
下記と同内容をDrawio形式で出力します
事前準備
Drawioを事前にインストールします
Drawio形式で生成する
-
下記のプロンプトを入力します
VPCとPublic サブネット、Private サブネット、NATGW、IGWを配置した図をDrawioで表示できるようにXML形式で出力して -
生成されました
Creating: /XXXXX/XXXXX/XXXXX/diagram-test/vpc-architecture.drawio ⋮ ● Completed in 0.2s > VPCアーキテクチャのDraw.io XMLファイルを vpc-architecture.drawio として生成しました。 このファイルには以下の要素が含まれています: • **VPC** (10.0.0.0/16) - 紫色のコンテナ • **Internet Gateway** - 緑色 • **Public Subnet** (10.0.1.0/24) - 青色、Bastionサーバー付き • **Private Subnet** (10.0.2.0/24) - 黄色、アプリケーションサーバー付き • **NAT Gateway** - 赤色、Public Subnet内に配置 • **Route Tables** - Public/Private用 • **接続線** - 各コンポーネント間のネットワーク接続 使用方法: 1. Draw.ioを開く(https://app.diagrams.net/) 2. 「File」→「Open from」→「Device」 3. 生成された vpc-architecture.drawio ファイルを選択 これでDraw.ioで編集可能なVPCアーキテクチャ図が表示されます。 -
下記のように出力されました
<?xml version="1.0" encoding="UTF-8"?> <mxfile host="app.diagrams.net" modified="2024-10-19T00:21:00.000Z" agent="5.0" etag="xxx" version="22.0.0" type="device"> <diagram name="VPC Architecture" id="vpc-arch"> <mxGraphModel dx="1422" dy="794" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0"> <root> <mxCell id="0" /> <mxCell id="1" parent="0" /> <!-- VPC Container --> <mxCell id="vpc" value="VPC
10.0.0.0/16" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;verticalAlign=top;fontSize=14;fontStyle=1;" vertex="1" parent="1"> <mxGeometry x="100" y="150" width="600" height="400" as="geometry" /> </mxCell> <!-- Internet Gateway --> <mxCell id="igw" value="Internet Gateway" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"> <mxGeometry x="350" y="80" width="100" height="40" as="geometry" /> </mxCell> <!-- Public Subnet --> <mxCell id="public-subnet" value="Public Subnet
10.0.1.0/24" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;verticalAlign=top;fontSize=12;" vertex="1" parent="1"> <mxGeometry x="130" y="200" width="250" height="120" as="geometry" /> </mxCell> <!-- Private Subnet --> <mxCell id="private-subnet" value="Private Subnet
10.0.2.0/24" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;verticalAlign=top;fontSize=12;" vertex="1" parent="1"> <mxGeometry x="420" y="200" width="250" height="120" as="geometry" /> </mxCell> <!-- NAT Gateway --> <mxCell id="natgw" value="NAT Gateway" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1"> <mxGeometry x="200" y="250" width="100" height="40" as="geometry" /> </mxCell> <!-- EC2 in Public Subnet --> <mxCell id="ec2-public" value="EC2
(Bastion)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#000000;" vertex="1" parent="1"> <mxGeometry x="150" y="280" width="60" height="30" as="geometry" /> </mxCell> <!-- EC2 in Private Subnet --> <mxCell id="ec2-private" value="EC2
(App Server)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#000000;" vertex="1" parent="1"> <mxGeometry x="500" y="250" width="80" height="40" as="geometry" /> </mxCell> <!-- Route Table Public --> <mxCell id="rt-public" value="Route Table
(Public)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e6f3ff;strokeColor=#4d79a4;fontSize=10;" vertex="1" parent="1"> <mxGeometry x="140" y="350" width="80" height="40" as="geometry" /> </mxCell> <!-- Route Table Private --> <mxCell id="rt-private" value="Route Table
(Private)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff9e6;strokeColor=#cc9900;fontSize=10;" vertex="1" parent="1"> <mxGeometry x="580" y="350" width="80" height="40" as="geometry" /> </mxCell> <!-- Internet --> <mxCell id="internet" value="Internet" style="ellipse;whiteSpace=wrap;html=1;fillColor=#f0f0f0;strokeColor=#666666;" vertex="1" parent="1"> <mxGeometry x="360" y="20" width="80" height="40" as="geometry" /> </mxCell> <!-- Connections --> <!-- Internet to IGW --> <mxCell id="conn1" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="internet" target="igw"> <mxGeometry width="50" height="50" relative="1" as="geometry"> <mxPoint x="390" y="200" as="sourcePoint" /> <mxPoint x="440" y="150" as="targetPoint" /> </mxGeometry> </mxCell> <!-- IGW to VPC --> <mxCell id="conn2" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="igw" target="vpc"> <mxGeometry width="50" height="50" relative="1" as="geometry"> <mxPoint x="390" y="200" as="sourcePoint" /> <mxPoint x="440" y="150" as="targetPoint" /> </mxGeometry> </mxCell> <!-- Public Subnet to NAT Gateway --> <mxCell id="conn3" value="" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="ec2-public" target="natgw"> <mxGeometry width="50" height="50" relative="1" as="geometry"> <mxPoint x="390" y="300" as="sourcePoint" /> <mxPoint x="440" y="250" as="targetPoint" /> </mxGeometry> </mxCell> <!-- NAT Gateway to Private Subnet --> <mxCell id="conn4" value="" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="natgw" target="ec2-private"> <mxGeometry width="50" height="50" relative="1" as="geometry"> <mxPoint x="390" y="300" as="sourcePoint" /> <mxPoint x="440" y="250" as="targetPoint" /> </mxGeometry> </mxCell> <!-- Route Table connections --> <mxCell id="conn5" value="" style="endArrow=none;html=1;rounded=0;strokeColor=#999999;strokeWidth=1;dashed=1;" edge="1" parent="1" source="rt-public" target="public-subnet"> <mxGeometry width="50" height="50" relative="1" as="geometry"> <mxPoint x="390" y="400" as="sourcePoint" /> <mxPoint x="440" y="350" as="targetPoint" /> </mxGeometry> </mxCell> <mxCell id="conn6" value="" style="endArrow=none;html=1;rounded=0;strokeColor=#999999;strokeWidth=1;dashed=1;" edge="1" parent="1" source="rt-private" target="private-subnet"> <mxGeometry width="50" height="50" relative="1" as="geometry"> <mxPoint x="390" y="400" as="sourcePoint" /> <mxPoint x="440" y="350" as="targetPoint" /> </mxGeometry> </mxCell> </root> </mxGraphModel> </diagram> </mxfile> -
Drawioで上記のファイルを開きます
-
AWSアイコンを使って再出力してください。と入力し、再生成します> AWSアイコンを使って再出力してください。 > AWSの公式アイコンを使用したDraw.io XMLファイルを再生成します: > XMLファイルが大きすぎるため、分割して作成します。まず基本構造を作成: ● Completed in 0.1s > AWS公式アイコンを使用したVPCアーキテクチャ図を vpc-architecture-aws.drawio として生成しました。 この図には以下のAWS公式アイコンが含まれています: ネットワークコンポーネント: • Internet(インターネット) • Internet Gateway(インターネットゲートウェイ) • NAT Gateway(NATゲートウェイ)× 2 • Application Load Balancer(アプリケーションロードバランサー) コンピューティング: • EC2 Instance(EC2インスタンス)× 2 構造: • VPC(10.0.0.0/16) • 2つのAvailability Zone • Public Subnet × 2(10.0.1.0/24, 10.0.3.0/24) • Private Subnet × 2(10.0.2.0/24, 10.0.4.0/24) 接続: • インターネットからIGW経由でALBへの接続 • ALBから各AZのプライベートサブネット内のEC2への負荷分散 • プライベートサブネットからNAT Gateway経由でのアウトバウンド接続 Draw.ioで開くと、AWS公式のアイコンスタイルで表示される本格的なアーキテクチャ図になります。 > -
確認します
<?xml version="1.0" encoding="UTF-8"?> <mxfile host="app.diagrams.net" modified="2024-10-19T00:27:00.000Z" agent="5.0" etag="xxx" version="22.0.0" type="device"> <diagram name="VPC Architecture with AWS Icons" id="vpc-arch-aws"> <mxGraphModel dx="1422" dy="794" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0"> <root> <mxCell id="0" /> <mxCell id="1" parent="0" /> <!-- VPC Container --> <mxCell id="vpc" value="VPC
10.0.0.0/16" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;strokeColor=#FF9900;strokeWidth=2;verticalAlign=top;fontSize=14;fontStyle=1;dashed=1;" vertex="1" parent="1"> <mxGeometry x="80" y="120" width="640" height="450" as="geometry" /> </mxCell> <!-- Internet --> <mxCell id="internet" value="" style="sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#232F3D;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.internet;" vertex="1" parent="1"> <mxGeometry x="370" y="30" width="60" height="60" as="geometry" /> </mxCell> <!-- Internet Gateway --> <mxCell id="igw" value="Internet Gateway" style="sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#8C4FFF;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.internet_gateway;" vertex="1" parent="1"> <mxGeometry x="370" y="100" width="60" height="60" as="geometry" /> </mxCell> <!-- Availability Zone 1 --> <mxCell id="az1" value="Availability Zone 1a" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;strokeColor=#147EBA;strokeWidth=1;verticalAlign=top;fontSize=12;fontStyle=1;dashed=1;" vertex="1" parent="1"> <mxGeometry x="100" y="180" width="280" height="360" as="geometry" /> </mxCell> <!-- Availability Zone 2 --> <mxCell id="az2" value="Availability Zone 1b" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;strokeColor=#147EBA;strokeWidth=1;verticalAlign=top;fontSize=12;fontStyle=1;dashed=1;" vertex="1" parent="1"> <mxGeometry x="420" y="180" width="280" height="360" as="geometry" /> </mxCell> <!-- Public Subnet AZ1 --> <mxCell id="public-subnet-1" value="Public Subnet
10.0.1.0/24" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#E6F3FF;strokeColor=#147EBA;verticalAlign=top;fontSize=11;" vertex="1" parent="1"> <mxGeometry x="120" y="210" width="240" height="120" as="geometry" /> </mxCell> <!-- Private Subnet AZ1 --> <mxCell id="private-subnet-1" value="Private Subnet
10.0.2.0/24" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#FFF2E6;strokeColor=#FF9900;verticalAlign=top;fontSize=11;" vertex="1" parent="1"> <mxGeometry x="120" y="350" width="240" height="120" as="geometry" /> </mxCell> <!-- Public Subnet AZ2 --> <mxCell id="public-subnet-2" value="Public Subnet
10.0.3.0/24" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#E6F3FF;strokeColor=#147EBA;verticalAlign=top;fontSize=11;" vertex="1" parent="1"> <mxGeometry x="440" y="210" width="240" height="120" as="geometry" /> </mxCell> <!-- Private Subnet AZ2 --> <mxCell id="private-subnet-2" value="Private Subnet
10.0.4.0/24" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#FFF2E6;strokeColor=#FF9900;verticalAlign=top;fontSize=11;" vertex="1" parent="1"> <mxGeometry x="440" y="350" width="240" height="120" as="geometry" /> </mxCell> <!-- NAT Gateway AZ1 --> <mxCell id="natgw-1" value="NAT Gateway" style="sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#8C4FFF;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.nat_gateway;" vertex="1" parent="1"> <mxGeometry x="200" y="260" width="50" height="50" as="geometry" /> </mxCell> <!-- NAT Gateway AZ2 --> <mxCell id="natgw-2" value="NAT Gateway" style="sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#8C4FFF;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.nat_gateway;" vertex="1" parent="1"> <mxGeometry x="520" y="260" width="50" height="50" as="geometry" /> </mxCell> <!-- EC2 in Private Subnet AZ1 --> <mxCell id="ec2-private-1" value="Web Server" style="sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#ED7100;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.ec2_instance;" vertex="1" parent="1"> <mxGeometry x="180" y="390" width="50" height="50" as="geometry" /> </mxCell> <!-- EC2 in Private Subnet AZ2 --> <mxCell id="ec2-private-2" value="Web Server" style="sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#ED7100;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.ec2_instance;" vertex="1" parent="1"> <mxGeometry x="500" y="390" width="50" height="50" as="geometry" /> </mxCell> <!-- Application Load Balancer --> <mxCell id="alb" value="Application
Load Balancer" style="sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#8C4FFF;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.application_load_balancer;" vertex="1" parent="1"> <mxGeometry x="370" y="240" width="60" height="60" as="geometry" /> </mxCell> <!-- Connections --> <!-- Internet to IGW --> <mxCell id="conn1" value="" style="endArrow=classic;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;" edge="1" parent="1" source="internet" target="igw"> <mxGeometry width="50" height="50" relative="1" as="geometry"> <mxPoint x="390" y="200" as="sourcePoint" /> <mxPoint x="440" y="150" as="targetPoint" /> </mxGeometry> </mxCell> <!-- IGW to ALB --> <mxCell id="conn2" value="" style="endArrow=classic;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;" edge="1" parent="1" source="igw" target="alb"> <mxGeometry width="50" height="50" relative="1" as="geometry"> <mxPoint x="390" y="200" as="sourcePoint" /> <mxPoint x="440" y="150" as="targetPoint" /> </mxGeometry> </mxCell> <!-- ALB to EC2 instances --> <mxCell id="conn3" value="" style="endArrow=classic;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;" edge="1" parent="1" source="alb" target="ec2-private-1"> <mxGeometry width="50" height="50" relative="1" as="geometry"> <mxPoint x="390" y="300" as="sourcePoint" /> <mxPoint x="440" y="250" as="targetPoint" /> </mxGeometry> </mxCell> <mxCell id="conn4" value="" style="endArrow=classic;html=1;rounded=0;strokeColor=#232F3E;strokeWidth=2;" edge="1" parent="1" source="alb" target="ec2-private-2"> <mxGeometry width="50" height="50" relative="1" as="geometry"> <mxPoint x="390" y="300" as="sourcePoint" /> <mxPoint x="440" y="250" as="targetPoint" /> </mxGeometry> </mxCell> <!-- NAT Gateway outbound connections --> <mxCell id="conn5" value="" style="endArrow=classic;html=1;rounded=0;strokeColor=#FF9900;strokeWidth=1;dashed=1;" edge="1" parent="1" source="ec2-private-1" target="natgw-1"> <mxGeometry width="50" height="50" relative="1" as="geometry"> <mxPoint x="390" y="400" as="sourcePoint" /> <mxPoint x="440" y="350" as="targetPoint" /> </mxGeometry> </mxCell> <mxCell id="conn6" value="" style="endArrow=classic;html=1;rounded=0;strokeColor=#FF9900;strokeWidth=1;dashed=1;" edge="1" parent="1" source="ec2-private-2" target="natgw-2"> <mxGeometry width="50" height="50" relative="1" as="geometry"> <mxPoint x="390" y="400" as="sourcePoint" /> <mxPoint x="440" y="350" as="targetPoint" /> </mxGeometry> </mxCell> </root> </mxGraphModel> </diagram> </mxfile> -
再読み込みを行ったところ、IGW・ALB・NATGW がアイコンとして表示されました。ただし、まだ一部が中途半端な状態です。この点は、プロンプトを工夫することで改善できそうです

E-R図とDDLを生成
事前準備
下記の環境が必要です。
- Java
- Graphviz
- PlantUML
JDKのセットアップ
-
JDKをインストールします
% brew update ==> Updating Homebrew... Already up-to-date. % brew install --cask corretto@25 -
PATHを通します
-
バージョンを確認します
% java --version openjdk 25 2025-09-16 LTS
Graphvizのセットアップ
-
graphvizをインストールします
brew install graphviz -
バージョンを確認します
% dot -V dot - graphviz version 14.0.1 (20251006.0113) %
PlantUMLのセットアップ
- PlantUMLをインストールします
-
バージョンを確認します
% plantuml -version PlantUML version 1.2025.9 (Tue Sep 09 00:56:38 JST 2025) (GPL source distribution) Java Runtime: OpenJDK Runtime Environment JVM: OpenJDK 64-Bit Server VM Default Encoding: UTF-8 Language: ja Country: JP PLANTUML_LIMIT_SIZE: 4096 Dot version: dot - graphviz version 14.0.1 (20251006.0113) Installation seems OK. File generation OK % -
動作確認のためテストデータを作ります
% cat > test.puml <<'EOF' @startuml Alice -> Bob : Hello @enduml EOF -
出力します
plantuml -tpng test.puml open test.png
VSCodeのプラグインをセットアップ
インストール
設定
ローカルで完結するように設定します
PlantUML 形式でE-R図を生成する
- 下記を入力しPlantUML形式でコードを生成します
書籍データをモデル化し、PlantUML 形式(.puml)で E-R 図を出力してください。 - 生成されました
↳ Purpose: 書籍データのE-R図をPlantUML形式で作成 Creating: /XXXXX/XXXXX/XXXXX/diagram-test/book-er-diagram.puml ⋮ ● Completed in 0.1s > 書籍データのE-R図を book-er-diagram.puml として生成しました。 このE-R図には以下のエンティティが含まれています: 主要エンティティ: • **Book(書籍)**: ISBN、タイトル、価格、在庫数など • **Author(著者)**: 名前、生年月日、国籍、経歴など • **Publisher(出版社)**: 名前、住所、連絡先など • **Category(カテゴリ)**: 階層構造対応のカテゴリ分類 関連エンティティ: • **BookAuthor(書籍著者)**: 多対多の関連を解決する中間テーブル • **BookCategory(書籍カテゴリ)**: 書籍とカテゴリの多対多関連 • **Review(レビュー)**: 書籍に対する評価・コメント • **Order(注文)**: 顧客の注文情報 • **OrderItem(注文明細)**: 注文の詳細項目 主要な関係: • 書籍と著者:多対多(共著対応) • 書籍と出版社:多対一 • 書籍とカテゴリ:多対多 • カテゴリの階層構造:自己参照 • 注文システム:注文と注文明細の一対多 PlantUMLツールやVSCodeのPlantUML拡張機能で開くと、視覚的なE-R図として表示されます。 > - VSCodeで「Cmd」+「Shift」+「P」を入力します
- 「PlantUML:Preview Current Diagram」を指定します
- 描画されました
DDLを生成
上記の内容を基に、DDLを生成します。
- 下記のプロンプトを入力し、DDLを生成します
> 生成済みの book-er-diagram.puml を基に、Amazon Aurora PostgreSQL 向けの DDL を作成し、ddlフォルダに配置してください。 - 生成されました
> Amazon Aurora PostgreSQL向けの書籍データベースDDLを作成しました。ddlフォルダに以下のファイルが生成されていま す: 作成されたDDLファイル: 1. 01_create_tables.sql - テーブル作成 • 9つの主要テーブル(books, authors, publishers, categories, etc.) • 外部キー制約、チェック制約 • CASCADE削除設定 2. 02_create_indexes.sql - インデックス作成 • パフォーマンス最適化用インデックス • 全文検索用GINインデックス • 複合インデックス 3. 03_create_triggers.sql - トリガーとファンクション • updated_at自動更新 • 在庫数自動管理 • 注文金額自動計算 4. 04_insert_sample_data.sql - サンプルデータ • 実際の書籍データ例 • 著者、出版社、カテゴリ情報 • 注文とレビューデータ 5. 05_create_views.sql - ビューとユーティリティ • 書籍詳細ビュー • 売上統計、在庫アラート • 検索ファンクション、在庫補充推奨 主な特徴: • Aurora PostgreSQL最適化 • 日本語対応(全文検索含む) • 自動在庫管理 • 階層カテゴリ対応 • 包括的な統計・分析機能 実行順序:01 → 02 → 03 → 04 → 05 の順でSQLファイルを実行してください。 >
生成されたオブジェクトを確認
Viewやテストデータなども生成されていますが、ここではテーブルを確認してみます。
-
01_create_tables.sqlを確認します。それぽいです
-- Amazon Aurora PostgreSQL 書籍データベース DDL -- 作成日: 2024-10-19 -- データベース作成(必要に応じて) -- CREATE DATABASE bookstore; -- 拡張機能の有効化 CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- 出版社テーブル CREATE TABLE publishers ( publisher_id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, address VARCHAR(500), phone VARCHAR(20), email VARCHAR(255), website VARCHAR(255), established_date DATE, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); -- 著者テーブル CREATE TABLE authors ( author_id SERIAL PRIMARY KEY, first_name VARCHAR(100) NOT NULL, last_name VARCHAR(100) NOT NULL, birth_date DATE, nationality VARCHAR(50), biography TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); -- カテゴリテーブル(階層構造対応) CREATE TABLE categories ( category_id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, description TEXT, parent_category_id INTEGER REFERENCES categories(category_id), created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); -- 書籍テーブル CREATE TABLE books ( book_id SERIAL PRIMARY KEY, title VARCHAR(255) NOT NULL, isbn VARCHAR(13) UNIQUE NOT NULL, publication_date DATE, price DECIMAL(10,2) CHECK (price >= 0), page_count INTEGER CHECK (page_count > 0), description TEXT, stock_quantity INTEGER DEFAULT 0 CHECK (stock_quantity >= 0), publisher_id INTEGER NOT NULL REFERENCES publishers(publisher_id), created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); -- 書籍著者関連テーブル(多対多) CREATE TABLE book_authors ( book_id INTEGER REFERENCES books(book_id) ON DELETE CASCADE, author_id INTEGER REFERENCES authors(author_id) ON DELETE CASCADE, role VARCHAR(50) DEFAULT '著者', order_index INTEGER DEFAULT 1, PRIMARY KEY (book_id, author_id) ); -- 書籍カテゴリ関連テーブル(多対多) CREATE TABLE book_categories ( book_id INTEGER REFERENCES books(book_id) ON DELETE CASCADE, category_id INTEGER REFERENCES categories(category_id) ON DELETE CASCADE, is_primary BOOLEAN DEFAULT FALSE, PRIMARY KEY (book_id, category_id) ); -- レビューテーブル CREATE TABLE reviews ( review_id SERIAL PRIMARY KEY, book_id INTEGER NOT NULL REFERENCES books(book_id) ON DELETE CASCADE, reviewer_name VARCHAR(100) NOT NULL, rating INTEGER CHECK (rating >= 1 AND rating <= 5), comment TEXT, review_date DATE DEFAULT CURRENT_DATE, is_verified BOOLEAN DEFAULT FALSE, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); -- 注文テーブル CREATE TABLE orders ( order_id SERIAL PRIMARY KEY, customer_name VARCHAR(255) NOT NULL, customer_email VARCHAR(255) NOT NULL, customer_phone VARCHAR(20), shipping_address VARCHAR(500) NOT NULL, order_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, total_amount DECIMAL(10,2) NOT NULL CHECK (total_amount >= 0), status VARCHAR(20) DEFAULT 'pending' CHECK (status IN ('pending', 'confirmed', 'shipped', 'delivered', 'cancelled')), created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); -- 注文明細テーブル CREATE TABLE order_items ( order_item_id SERIAL PRIMARY KEY, order_id INTEGER NOT NULL REFERENCES orders(order_id) ON DELETE CASCADE, book_id INTEGER NOT NULL REFERENCES books(book_id), quantity INTEGER NOT NULL CHECK (quantity > 0), unit_price DECIMAL(10,2) NOT NULL CHECK (unit_price >= 0), subtotal DECIMAL(10,2) NOT NULL CHECK (subtotal >= 0) ); -
Q Devにチェックさせます
> puml形式とDDLファイルの内容を突合し、すべての項目が揃っているか、データ型、サイズ、Not nullに矛盾がないか確認してほしい\ リレーションに矛盾がないか確認してほしい -
いくつか見つかりました
> PlantUMLファイルとDDLファイルの内容を突合して確認します。 ● Completed in 0.0s > PlantUMLとDDLの突合結果を報告します: ## **矛盾点・不整合** ### **1. NOT NULL制約の不一致** PlantUML側で必須(*)だがDDL側でNULLABLE: • books.publication_date - PlantUMLでは必須、DDLではNULLABLE • books.price - PlantUMLでは必須、DDLではNULLABLE • books.page_count - PlantUMLでは必須、DDLではNULLABLE • books.description - PlantUMLでは必須、DDLではNULLABLE • books.stock_quantity - PlantUMLでは必須、DDLではNULLABLE • authors.birth_date - PlantUMLでは必須、DDLではNULLABLE • authors.nationality - PlantUMLでは必須、DDLではNULLABLE • authors.biography - PlantUMLでは必須、DDLではNULLABLE • categories.description - PlantUMLでは必須、DDLではNULLABLE • reviews.rating - PlantUMLでは必須、DDLではNULLABLE • reviews.comment - PlantUMLでは必須、DDLではNULLABLE • reviews.review_date - PlantUMLでは必須、DDLではNULLABLE • reviews.is_verified - PlantUMLでは必須、DDLではNULLABLE ### **2. 外部キー制約の不一致** PlantUMLで必須だがDDLで欠落: • books.publisher_id - PlantUMLでは必須外部キーだが、DDLでは定義されていない ### **3. データ型・サイズの不整合** TIMESTAMP vs TIMESTAMP WITH TIME ZONE: • PlantUMLではTIMESTAMP、DDLではTIMESTAMP WITH TIME ZONE(これは改善) ## **整合している項目** ✅ テーブル名・カラム名: 全て一致 ✅ 主キー定義: 全て一致 ✅ データ型・サイズ: 基本的に一致 ✅ リレーション構造: 全て一致 ✅ 複合主キー: book_authors, book_categoriesで一致 ## **推奨修正** PlantUMLの設計意図に合わせてDDLを修正するか、PlantUMLを実装に合わせて更新することをお勧めします。特に、必須項 目(NOT NULL制約)とbooks.publisher_idの外部キー制約の整合性を取る必要があります。 -
修正します
> PlantUMLの設計意図に合わせてDDLを修正してほしい -
修正されました
> PlantUMLの設計意図に合わせてDDLを修正します: ・・・ > PlantUMLの設計意図に合わせてDDLを修正しました。 ## **修正内容** ### **NOT NULL制約を追加した項目:** books テーブル: • publication_date, price, page_count, description, stock_quantity • created_at, updated_at authors テーブル: • birth_date, nationality, biography • created_at, updated_at publishers テーブル: • address, phone, email, website, established_date • created_at, updated_at categories テーブル: • description • created_at, updated_at book_authors テーブル: • book_id, author_id, role, order_index book_categories テーブル: • book_id, category_id, is_primary reviews テーブル: • rating, comment, review_date, is_verified • created_at, updated_at orders テーブル: • customer_phone, order_date, status • created_at, updated_at これでPlantUMLの設計(*マークで必須指定)とDDLの制約が完全に一致しました。すべての必須項目にNOT NULL制約が適用 され、データ整合性が保たれます。 >
考察
今回、生成AIとDraw.io、PlantUMLを組み合わせることで、図面をコードとして管理しながら自動生成する仕組みを構築し、設計と実装の連携をよりスムーズにしてみました。
次回は、CI/CDと組み合わせてみたいと思います。
参考





