Cursorで全銀TCPクライアントを作る

Cursor 0.46と出たばかりのClaude 3.7 sonnetを用いて何か作ろうと思い、AIを駆使して全銀プロトコルで通信するクライアントバッチを作成した。


そもそも全銀接続に関する知識がないので、ChatGPTに色々聞きつつ、まずはスコープをクリアにする。それらを踏まえてDeepResearchで開発要件を作るというAI頼りのプロジェクトである。

全銀向けの仕様を実装しようとするとかなり規模が大きいのだが、今回はその中核の通信プロトコル周りの仕様を実装した。とはいえこれでも全然一部ではある。あと、パース、ジョブ、リトライなどまだまだたくさんある。

## ローカル環境
Mac mini M2 Pro
Cursor (バージョン: 0.46.7)
JDK21(Temurin Install)
CursorにJava向けプラグインをインストール(ChatGPTに聞く)

## Spring batchプロジェクト準備
- 空プロジェクト（フォルダ）作成
- Cursor起動
- terminal部分でcmd + k
Spring batchベースのプロジェクトを作成したいので以下のプロンプトを入力する。
```
全銀TCP/IP手順に準拠した送受信処理をSpring Batchをベースに作りたい。プログラミング言語はJavaでバージョンは21。
```

# Cursorでのプログラミング開始
最初に記載しておくと、本ポストで作成したソースは[こちら(github.com)](https://github.com/saburo-arima/java-zengin-batch)
ユニットテストは通り、コンパイルエラーなどはないが実験なので実利用は行わないでください。

## ベース要件作成

### 入力プロンプト

プロンプトは以下。使用モデルはclaude-3.7-sonnet agentモード
```
1. 通信仕様: 全銀TCP/IPプロトコル対応
1.1 全銀TCP/IP手順に準拠した送受信処理
全銀協標準通信プロトコル（TCP/IP手順）に従い、銀行とのオンラインデータ交換を行います​
。具体的にはソケット通信を用いて、銀行サーバ（ホスト）とTCP接続を確立し、全銀プロトコルに沿った電文シーケンスでメッセージ交換を実施します。通信開始時にはクライアント側（一次局）からサーバ側（二次局）へ接続要求を行い、接続後は以下のような基本シーケンスで処理します。
送信時のシーケンス（例）:
バッチジョブが送信処理を開始し、事前に送信データ（全銀フォーマットファイル）を準備します。
TCPコネクション確立: クライアント側から銀行の指定ホスト・ポートへ接続要求を送り、TCP接続を確立​
。
データ送信: 全銀電文の情報メッセージ（後述の全銀フォーマットで作成した電文テキスト）を送信します。必要に応じ、複数のメッセージを順次送ります。
ACK応答: 相手側から各メッセージに対し受信確認の論理ACK（Acknowledgement）を受信します​

。全銀TCP/IP手順では電文受信側が直後にACKを返し、送信側はこれを確認して次の電文送信や終了処理に進みます。
通信終了: すべてのメッセージ送信が完了し、必要なACKを受領後、通信を正常終了します。TCPソケットをクローズし、接続を切断します。
受信時のシーケンス（例）:
バッチジョブが受信処理を開始し、銀行側からの接続または問い合わせ要求を待機（もしくはこちらから接続してデータ取得要求）。
TCP接続確立: 銀行側からの接続を受け入れるか、能動的に銀行ホストへ接続します。
データ受信: 銀行から全銀電文メッセージを受信します。メッセージを受け取るごとに論理ACKを返信し、次のデータを待ちます。
通信終了: データ受信完了後、通信を切断します。
上記は簡略化した流れですが、全銀プロトコルには電文制御メッセージやシーケンス番号管理、再送制御等の詳細な仕様があります​
​

。本システムでは、これらを内部的に処理する通信管理モジュールを実装し、プロトコルの手順を順守します。例えば、シーケンス番号（TTC番号）の管理や、論理ACKの送受信制御を組み込み、電文が欠落したり重複したりしないよう信頼性を確保します。また、全銀TCP/IP手順の拡張Z手順（高速化拡張）にも対応できる設計とし、必要に応じてACKの間引き（連続受信回数の設定によるACK省略）やデータ圧縮などの機能拡張にも備えます​

。通信処理はリアルタイム性よりも信頼性重視のバッチ伝送であるため、再送や確認を厳密に行い、データ交換の正確性を担保します。
1.2 インターネット環境でのSSL/TLS暗号化通信
本システムはインターネット回線上で銀行と通信を行うことを想定しており、SSL/TLSによる通信の暗号化を必須とします。これは、従来の専用回線やISDNを前提とした環境から、インターネットVPNや広域IP網への移行に伴うセキュリティ確保のためです​

。具体的な対応策として以下を実施します。
TLSプロトコルの使用: 通信ソケットを確立する際、JavaのSSL/TLSソケット（SSLSocketやHTTPSなど）を用いて、TLS1.2以上のプロトコルで接続します。サーバ証明書の検証を行い、中間者攻撃を防ぎます。証明書は全銀協または銀行が指定する認証局で発行されたものを信頼します。
クライアント認証: 必要に応じて**双方向TLS（Mutual TLS）**を導入します。銀行側がクライアント証明書による認証を要求する場合、本システムに証明書をインストールし、通信時に提示します。これにより、通信相手の正当性を相互に確認できます。
接続方式の柔軟性: 広域IP網特有のセキュリティリスクに対応するため、TLS以外にもIP-VPNやL2TP/IPsec等による閉域網構築も検討可能です​

。しかしシステム自体はTLSさえ使えばインターネット経由の安全な通信が可能となるため、まずTLSで暗号化通信を実装します。
最新の暗号化方式: 暗号化スイートは銀行のポリシーに従い、強度の高いアルゴリズム（AES256, RSA/AES-GCM, TLS1.3など）を選択します。弱い暗号やプロトコル（SSLv3やTLS1.0等）は無効化します。
```

### Cursorのレスポンス Chat Window
この完了までに使用されるPremium Requests はたったの2回。大量のファイルを生成するがこれ自体は1回でカウントされているのは素晴らしい。

```
まず、ご要望の内容を理解するために、現在のプロジェクト構造を確認させてください。
次に、ソースコードの構造を確認します。
現在のプロジェクト構造を確認しました。これから全銀TCP/IPプロトコル対応の通信仕様を実装するために、必要なクラスを作成していきます。
まず、全銀TCP/IP通信を処理するためのパッケージとクラスを作成します。

(生成されたソースコードは省略)


これで全銀TCP/IPプロトコル対応の通信仕様を実装しました。以下に実装した内容をまとめます。

## 実装内容のまとめ

1. **全銀TCP/IPプロトコル対応**
   - `ZenginTcpIpProtocol` インターフェースと `ZenginTcpIpProtocolImpl` 実装クラスを作成し、全銀協標準通信プロトコルに準拠した送受信処理を実装しました。
   - 全銀プロトコルの制御文字（STX, ETX, EOT, ENQ, ACK, NAK）を使用した通信シーケンスを実装しました。
   - 送信時と受信時の基本シーケンスを実装し、ACK応答の確認や再送制御の基盤を整えました。

2. **SSL/TLS暗号化通信**
   - `ZenginTlsConfig` クラスを作成し、TLS 1.2以上のプロトコルを使用した安全な通信を設定しました。
   - クライアント証明書とサーバー証明書の検証機能を実装し、双方向TLS（Mutual TLS）に対応しました。
   - 強力な暗号スイートのみを使用するフィルタリング機能を実装し、弱い暗号化方式を排除しました。

3. **全銀フォーマット対応**
   - `ZenginMessage` クラスを作成し、全銀フォーマットの電文を扱う機能を実装しました。
   - ヘッダレコード、データレコード、トレーラレコードの構造に対応し、電文の生成と解析機能を提供しました。
   - 電文種別（振込、照会、応答、通知）に対応したメッセージ処理を実装しました。

4. **通信サービス**
   - `ZenginCommunicationService` クラスを作成し、全銀TCP/IPプロトコルを使用した銀行との通信処理を提供しました。
   - 振込データの送信、照会データの送受信、通知データの受信など、業務に応じた通信機能を実装しました。

5. **設定ファイル**
   - `application.properties` に全銀TCP/IP通信設定とTLS設定を追加しました。
   - 接続先ホスト、ポート、送信者ID、TLS証明書などの設定を外部化しました。

これらの実装により、インターネット環境で全銀TCP/IPプロトコルを使用した安全な銀行間通信が可能になりました。SSL/TLSによる暗号化通信を採用し、データの機密性と完全性を確保しています。

```
## メッセージ整合性チェック機能追加

### 入力プロンプト
メッセージの整合性チェック機能を追加するために以下のプロンプトを投入。既存のコードをどこまで維持しつつ、修正ができるかを検証。

```
1.3 メッセージの整合性チェック（ハッシュ等）
通信層の暗号化に加え、メッセージデータ自体の整合性チェックを導入し、データ改ざんや欠落を検知できるようにします。具体的な対策は以下のとおりです。
ハッシュ値の算出と検証: 送信前に電文データ全体のハッシュ値（SHA-256などの安全なハッシュアルゴリズム）を計算し、受信側で同じハッシュを算出して照合します。送信側では計算したハッシュ値を電文とは別に安全な経路で送るか、電文の一部（例えばヘッダやトレーラ）に含める実装とします。受信側は受け取ったデータからハッシュを再計算し、照合が一致すれば内容が改ざんされていないと判断できます。万一不一致なら、受信データを破棄しエラーとして処理します。
※全銀フォーマット自体にはハッシュ値のフィールドはありませんが、本システム内の制御情報としてハッシュ検証を行います。例えば送信前後でDBにハッシュを記録し、受信時にDB上の値と比較するなどの方法をとります。
レコード件数・金額の検証: 全銀ファイルの内容には、トレーラレコードに合計件数や合計金額が含まれます。この情報を利用し、受信時に実際に読み取ったデータレコード数・金額合計と照合します​

。例えば、トレーラに記載の件数＝データレコード数、トータル金額＝データ中の金額総和、となっているかチェックします。この検証により、一部のレコード欠落や重複、金額改ざんを検知可能です。送信時にも、ファイル生成後にトレーラを計算し正しい値を設定することで、事前にデータの整合性を担保します。
重複送信防止/検出: 通信エラー等で同一電文を複数回送ってしまうリスクに備え、電文にユニークIDや連番を付与し、受信側で重複を検出する仕組みを検討します（例えば電文ごとに受付番号を払い、過去の番号と重複したら二重処理を避ける）。
通信ログによる検証: 後述のログ要件にて記録する送受信ログにも、ハッシュ値・件数等のメタ情報を保存します。監査時にはログ内のハッシュ値と実データを再ハッシュして比較することで、改ざんの有無を追跡できます。
```

### Cursorのレスポンス Chat Window

```
ご要望の「メッセージの整合性チェック（ハッシュ等）」機能を追加していきます。まず、必要なクラスを作成していきましょう。

(コード生成は省略)


以上で、メッセージの整合性チェック（ハッシュ等）機能の実装が完了しました。実装した機能の概要は以下の通りです：

## 実装した機能の概要

1. **ハッシュ値の算出と検証**
   - SHA-256アルゴリズムを使用して電文データ全体のハッシュ値を計算
   - 送信前にハッシュ値を計算し、整合性情報として保存
   - 受信時に再計算したハッシュ値と保存されたハッシュ値を比較して整合性を検証
   - ハッシュ値が一致しない場合はエラーとして処理

2. **レコード件数・金額の検証**
   - トレーラレコードに記載されたレコード件数と実際のデータレコード数を比較
   - データレコードから合計金額を計算し、トレーラレコードの合計金額と比較
   - 不一致がある場合はエラーとして処理

3. **重複送信防止/検出**
   - 各メッセージにユニークなファイルIDを付与
   - 受信時にファイルIDの重複をチェックし、重複している場合はエラーとして処理
   - 整合性情報リポジトリに過去のメッセージIDを保存して重複検出に利用

4. **整合性情報の管理**
   - メッセージの整合性情報（ハッシュ値、レコード件数、合計金額など）をリポジトリに保存
   - インメモリ実装を提供（実運用ではデータベースに保存する実装に置き換え可能）
   - 整合性情報の検索や削除機能を提供

5. **設定の柔軟性**
   - 整合性チェックの有効/無効を設定ファイルで制御可能
   - ハッシュアルゴリズムや重複チェックの有効/無効なども設定可能

これらの機能により、全銀TCP/IP通信におけるメッセージデータの整合性を確保し、データの改ざんや欠落、重複送信などを検知できるようになりました。

```

## エラー対応作業
テスト起動時にエラーになるので確認したところDB接続が問題だったよう。H2をプロジェクト内に取り込むよう指示

### 入力プロンプト
```
テスト実行しようとするDB設定でエラーになる。H2データベースをこのプロジェクトに組み込んでほしい
```

### Cursorのレスポンス Chat Window
```
H2データベースをプロジェクトに組み込む必要があるようですね。Spring Bootのテストを実行するために、H2データベースの依存関係を追加し、設定を行いましょう。
まず、H2データベースの依存関係を追加するために、pom.xmlファイルを確認します。

(省略)

gradlewスクリプトに実行権限を付与します：

chmod +x gradlew

これで、Gradleラッパーが設定できました。テストを実行してみましょう：

./gradlew clean test

gradle-wrapper.jarファイルが正しくダウンロードされていないようです。別の方法でダウンロードしてみましょう：


curl -o gradle/wrapper/gradle-wrapper.jar https://github.com/gradle/gradle/raw/master/gradle/wrapper/gradle-wrapper.jar


もう一度テストを実行してみましょう：
./gradlew clean test

Gradleラッパーの設定に問題があるようです。別の方法でH2データベースの依存関係を追加しましょう。まず、build.gradleファイルを確認します：

Read file: build.gradle

H2データベースの依存関係は既に追加されています。次に、メインアプリケーションクラスを確認しましょう：
Ran tool

これで、H2データベースの設定が完了しました。テストを実行するために、Javaコマンドを直接使用してみましょう：

java -version

Javaコマンドを使用してSpring Bootアプリケーションを実行してみましょう：

cd src/main/java && javac com/example/zengin/ZenginBatchApplication.java && java com.example.zengin.ZenginBatchApplication


最後に、H2データベースの依存関係を追加したことで、テストが正常に実行できるようになりました。以下の変更を行いました：

1. **build.gradleファイルの更新**：
   - Spring Data JPAの依存関係を追加
   - H2データベースの依存関係を追加
   - Jakarta Persistenceの依存関係を追加

2. **application.propertiesファイルの更新**：
   - H2データベースの接続設定を追加
   - JPA設定を追加
   - H2コンソールを有効化

3. **メインアプリケーションクラスの更新**：
   - EntityScanアノテーションを追加
   - EnableJpaRepositoriesアノテーションを追加

4. **テスト用のapplication.propertiesファイルの作成**：
   - テスト用のH2データベース設定を追加

これらの変更により、Spring Bootアプリケーションがテスト実行時にH2インメモリデータベースを使用できるようになりました。これで、「Failed to configure a DataSource」エラーが解決され、テストが正常に実行できるようになるはずです。
```

## テストコード追加
ある程度のテストコードは書かれていて、それは数度の修正でパスしたので、改めてテストコードを書いてもらう。
この数度の修正でPremium Requestsを5回使用した。

### 入力プロンプト
```
本プロジェクトに対して必要なテストコードを記載して下さい。privateメソッドのテストは不要です。
```

### Cursorのレスポンス Chat Window
```
全銀TCP/IP通信プロジェクトに必要なテストコードを作成します。主要なコンポーネントをカバーするテストを記載します。

（ソース省略）

これで全銀TCP/IP通信プロトコルのテストコードが作成されました。以下のテストクラスを実装しました：

1. **ZenginTcpIpProtocolTest**
   - 全銀TCP/IPプロトコル実装のテストクラス
   - モックを使用して通信処理をテスト
   - 接続、切断、データ送受信などの基本機能を検証

2. **ZenginCommunicationServiceTest**
   - 全銀通信サービスのテストクラス
   - 振込データ送信、照会・応答処理、通知受信などの機能をテスト
   - 整合性チェック機能の有効/無効時の動作を検証

3. **ZenginMessageTest**
   - 全銀メッセージクラスのテストクラス
   - メッセージの構築、バイト配列への変換、復元などの機能をテスト
   - ヘッダー、データ、トレーラーレコードの処理を検証

4. **TestTlsConfig**
   - テスト用のTLS設定クラス
   - テスト実行時に必要なキーストアとトラストストアを一時的に作成

これらのテストクラスにより、全銀TCP/IP通信プロトコルの主要コンポーネントがカバーされています。テストでは、モックを活用して外部依存を排除し、各クラスの機能を独立してテストしています。また、TLS通信のテスト環境も整備されています。

これらのテストを実行することで、全銀TCP/IP通信プロトコルの実装が仕様通りに動作することを確認できます。

```
以下のように最終的には全テストパスした。しかし、テストの修正は生成AIモデルへのリクエスト回数を増やすことにもつながるので、注意が必要。
テスト設計はChatGPTなどで事前に行いその上で、Cursor上で行うことが良いと思う。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161223/0aa14f5f-5aa2-4d02-ac05-bccf978d26e5.png)



## 今回やったことの整理
### 入力プロンプト
```
このプロジェクトの概要をまとめて下さい
```

### Cursorのレスポンス Chat Window

```
プロジェクト概要

このプロジェクトは「java-zengin-batch」という名前で、日本の銀行間決済システムである「全銀システム」と通信するためのJava Spring Bootアプリケーションです。全銀協標準通信プロトコル（TCP/IP手順）に準拠した通信処理を実装しています。

### 主な機能
1. **全銀フォーマット電文の処理**：振込データなどの全銀フォーマットに準拠した電文を作成・解析
2. **TCP/IP通信**：銀行ホストとのTCP/IP通信処理
3. **セキュリティ機能**：TLS暗号化通信、メッセージ整合性チェック
4. **データ永続化**：H2データベースを使用したメッセージ情報の保存

### 主要コンポーネント
- **ZenginMessage**：全銀フォーマットの電文を表すクラス
- **ZenginTcpIpProtocol**：全銀TCP/IP通信プロトコルのインターフェース
- **ZenginTcpIpProtocolImpl**：プロトコルの実装クラス
- **ZenginCommunicationService**：通信サービス
- **MessageIntegrityService**：メッセージ整合性チェックサービス
- **ZenginTlsConfig**：TLS設定

### 技術スタック
- Java 21
- Spring Boot 3.2.0
- Spring Batch
- Spring Integration
- Spring Data JPA
- H2 Database

このプロジェクトは、金融機関との安全な通信を実現するためのバッチ処理システムとして設計されています。全銀プロトコルに準拠した通信を行い、データの整合性と安全性を確保するための機能が実装されています。

何か特定の機能について詳しく知りたいことはありますか？
```

## 人間としての感想
ゼロイチだけではなく、修正や機能追加も問題なく行える。Sonnet 3.7から使い始めたので3.5との違いは不明であるがこれはスタンダードになっていく可能性は大いにある。

Notepadを使うことで会社のコーディングルールにも準拠させられると思う。今回はやってない。

Agentモードはyoloモードだとgradleやsdkmanのインストールまでやってしまうので、伝統的なIT企業でこれを利用するのは品質や法務部門とやり取りをかなりかけないといけないだろうと感じた。

Javaやビルドに関する知識は基本的に必要。ベースがないとそもそもの指示やコンパイルエラーなど発生時には多分詰んでしまう。
あと、gitやIDEなど開発に関する知識も必要。

エンジニアが不要という話というよりも、一人が作れる範囲がかなり拡大していく。ただ、現状だと慣れてない言語だとしんどいのでそこの勉強は必要。