Givery教材トップシステムの歩き方事前セットアップ
DAY 1 2026年9月3日(木)

題材を掴む + Claude Code の3操作

受注管理システムが何をするものかを掴んだうえで、Claude Code の3操作(ターミナル対話・Planモード・スラッシュコマンド)を自分の手で一通り動かします。読みにくい JSON を自分の画面に変えるところまでを、この日のうちに通します。

この日の演習

演習は上から順に進みます。全員が終わるのを待ってから次へ進むので、詰まったら手を挙げてください。早く終わった方には各演習に発展課題があります。

D1-1起動確認とコードベース質問[15min]
ねらい

claude が起動して、CLAUDE.md の中身まで踏まえた答えを返す状態を自分の手で確かめます。

ここまで出たら完了
  • 1枚目のターミナルに Started OrderApplication、2枚目に Claude Code の入力欄が出ている
  • 遷移ルールを聞くと PENDING → CONFIRMED → SHIPPED → DELIVERED が返る
  • / を打つとスラッシュコマンドの一覧が出て、/help の結果が画面に出る
さわるファイル
読むCLAUDE.md何が書いてあるか目を通す
読むsrc/main/java/com/example/order/service/OrderServiceImpl.java説明と実物を突き合わせる
手を動かす
1
考える
controller から先はどの順に呼ばれるか、自分の答えを一言メモします。あとで返ってきた説明と突き合わせます。
2
実行
VSCode で handson フォルダを開き、Ctrl+@ でターミナルを出して mvn spring-boot:run を打ちます。Started OrderApplication が出たらそのまま放置し、ターミナル右上の+で2枚目を開いて claude と打ちます。
3
書く
2枚目のターミナルで「変更はせずに、このプロジェクトの層構造と OrderServiceImpl の役割を説明して」と送ります。続けて「CLAUDE.md に書かれている受注ステータスの遷移ルールを教えて」と聞きます。
4
答え合わせ
返ってきた遷移を、ページ上部の「システムの歩き方」を別タブで開いて図と見比べます。最後に / を打ち、一覧から /help を選んで Enter を押します。
考えること
同じ質問を CLAUDE.md が置かれていないプロジェクトで投げたら、答えのどこが変わるか。
AI の出方
説明の粒度は毎回変わります。controller / service / repository / model の4層がそろわないときは「controller から repository までの呼び出し順を、ファイル名つきで説明して」と聞き直してください。調べ始めて長くなったら Esc で止めて構いません。
D1-1+src/main/java/com/example/order/model/Order.java の STATUS_PENDING に、日本語の Javadoc を付けさせます。出てきた説明が「受注直後の、まだ確定前の状態」という実際の意味とずれていないかを自分で判定してください。STATUS_CONFIRMED から STATUS_CANCELLED までの残り4定数をまとめて生成させると、途中から意味のずれた説明が混じりやすくなります。1定数ずつ頼んだ場合と見比べると、依頼の粒度で提案の正確さが変わるのが分かります。
くわしく(背景・詰まったときの対処)

この演習の前に、講師と一緒に「システムの歩き方」で受注ステータスの遷移図と層構造を見て、ブラウザに出る生の JSON を一度眺めます。Eclipse からターミナルに移った初日にいちばん引っかかるのは、指示が届いているのか分からない状態です。ここで起動と応答を先に確かめておくと、あとの演習では提案の中身を読むことに時間を使えます。

ターミナルは2枚使います。1枚目はアプリを動かしっぱなしにする窓、2枚目は claude と話す窓です。1枚で兼ねると、アプリを止めるつもりで押した Ctrl+C で Claude Code のほうが終わります。2枚目はターミナル右上の+(新しいターミナル)で開きます。Ctrl+@ が効かないときは、表示メニューのターミナルからでも開けます。アプリの初回起動は依存関係の取得に時間がかかるので、D1-1 の頭で先に走らせておくと後が楽です。

claude を初めて起動すると、配色の選択とフォルダを信頼するかの確認が出ます。どちらも Enter で進めて構いません。入力欄が出れば起動できています。

handson フォルダの直下には CLAUDE.md が置いてあり、技術スタック、コーディング規約、受注の業務ルールが書かれています。claude を起動するとこの内容が読み込まれるので、前提を毎回打ち直す必要はありません。遷移ルールを聞いて正しく返ってくれば、読み込まれている証拠になります。

層の説明は毎回同じ形では返りません。4つの層の名前が一度でそろわなくても、聞き直せれば十分です。応答が返らない、そもそも claude というコマンドが見つからないというときは、ターミナルの現在地が handson になっているかを最初に確かめてください。

この演習ではファイルを作りません。コードにも手を入れないので、終わったらそのまま D1-2 に進めます。入力欄で @ を打つとファイル参照の候補が出ます。D1-2 以降で使うので、時間が余ったら一度眺めておいてください。/ の一覧にはこのプロジェクト用の /review も並んでいます。コードを直したあとに打つと、規約と業務ルールに照らして見てくれます。

D1-2検索の仕様を決めてから作らせる[20min]
ねらい

何を返す検索なのかを自分で決めてから、Claude Code に実装させます。

この演習で扱うもの

受注管理システムには、受注を探す窓口が3つあります。全件、ID指定、顧客名。ここに4つ目として、受注日の範囲で絞り込む窓口を足します。

受注データは10件で、受注日は 2026-04-01 から 2026-04-08 まで散らばっています。配布時点では窓口の入口だけがあり、中身が空です。実際に叩くと 400 が返ります。

扱う場所は2つです。業務の判断をする service と、外からの入口になる controller。検索そのものは service に、URL の受け口は controller に置きます。

なぜこれをやるのか

AI に「日付で検索できるようにして」とだけ頼むと、動くものは出てきます。ただ、範囲に両端を含むのか、該当なしのとき何を返すのか、逆順を渡されたらどうするのか。こういう判断は仕様であって、AI が決めることではありません。

決めずに頼むと、AI が勝手に決めた仕様で実装されます。動いているように見えるので気づきません。先に決めておけば、返ってきたものが合っているかを判定できます。

ここまで出たら完了
  • 決めた3つの仕様を、自分の言葉で説明できる
  • 4月1日から4月3日で5件返り、ORD-20260401-001 と ORD-20260403-005 が両方入っている
  • from と to を同じ日にすると、その日の2件が返る(両端を含んでいる)
  • 2026-05-01 から 2026-05-31 は空の配列 [] が返る(null ではない)
完了時。5件返り、両端の受注番号が含まれていれば達成です
完了時。5件返り、両端の受注番号が含まれていれば達成です
さわるファイル
書くsrc/main/java/com/example/order/service/OrderServiceImpl.javafindByDateRange の本体を埋める
書くsrc/main/java/com/example/order/controller/OrderController.java/date-range の窓口を足す
まず自分で考える [3min]

頼む前に、この検索の仕様を3つ決めてください。書き出さなくても、言葉にできれば構いません。

  • 4月1日から4月3日と指定したとき、4月1日と4月3日の受注は含まれるか
  • 該当する受注が1件もないとき、何を返すか(空のリストか、エラーか)
  • 開始日より前の終了日を渡されたら、どうするか
AI と詰める

決めた仕様を添えて頼みます。仕様を言葉にして渡すのがここでの練習です。

返ってきたら、決めた3つが実装に入っているかを確かめてください。入っていなければ、その1点だけを指摘して直させます。

@src/main/java/com/example/order/service/OrderServiceImpl.java
findByDateRange を実装してください。
受注日が from から to の範囲にある受注を返します。両端を含みます。
該当がないときは空のリストを返してください。null は返さないでください。
例外を投げている行は消してください。
手を動かす
1
考える
どのリポジトリメソッドを呼び、何の型に詰め替え、何を返すか。この3つを先に決めてから頼みます。
2
書く
2枚目のターミナルの Claude Code に、@ で OrderServiceImpl.java を渡して findByDateRange の実装を依頼します。例外を投げている行を消すことも伝えます。
3
書く
続けて OrderController.java に、クエリパラメータ from と to を受け取る GET /date-range を追加させます。既存の findByStatus と書き方をそろえてと添えます。
4
実行
Java を直したので、1枚目のターミナルで Ctrl+C を押し、mvn spring-boot:run で起動し直します。ブラウザで http://localhost:8080/api/orders/date-range?from=2026-04-01&to=2026-04-03 を開きます。
考えること
from に新しい日付、to に古い日付を渡したとき、空で返すのと入力ミスとして弾くのと、どちらが仕様として正しいか。
AI の出方
stream で詰め替える案と for ループの案のどちらも出ます。リポジトリを呼んで OrderDTO に変換していれば、書き方の違いは正解の範囲です。変更内容では @Transactional(readOnly = true) が付いているかだけ、すぐ上の findByStatus と見比べてください。
D1-2+OrderRepository の findByCustomerAndStatus は、顧客名とステータスの両方が一致する受注を返す検索です。これを呼ぶ薄いラッパーを OrderService と OrderServiceImpl の両方に足し、findByStatus と同じ形にそろえてください。似ているぶん引数の順番を取り違えた案が出やすいので、呼び先と引数だけは承認前に目で追ってください。findByDateRange には触らないので、後続の演習の前提を壊しません。
くわしく(背景・詰まったときの対処)

findByDateRange は、受注日が from から to の間に入る受注だけを取り出す検索です。配布時点では本体が例外を投げる一行だけになっていて、呼ぶと必ず止まります。

手がかりは2つあります。取り出す側はリポジトリにもう用意されていること、詰め替えのお手本が同じファイルの中にあることです。手順1で自分の答えを決めてから、OrderRepository と、すぐ上の findByStatus を開いて確かめてください。リポジトリのメソッドはメソッド名から SQL が組み立てられる仕組みなので、こちらで SQL を書く必要はありません。範囲の指定は両端を含むため、from と to に同じ日を入れてもその日の受注が取れます。

実装前に /api/orders/date-range を叩くと HTTP 400 が返ります。エンドポイントを足すと解消するので、400 が出ても手順どおり進めてください。

触るのは OrderServiceImpl の findByDateRange の本体と、OrderController に足す /date-range の2か所だけで、新しいファイルは作りません。Java の変更は動いているアプリには届かないので、確認の前に起動し直します。実装後に OrderController.java へ赤い波線が残ったら、java.time.LocalDate と org.springframework.format.annotation.DateTimeFormat の import を補ってください。OrderServiceImpl 側は LocalDate を最初から import しています。Claude Code に「足りない import を補って」と続けて頼んでも構いません。

動くところまで来たら、入力欄で /review と打ってみてください。このプロジェクト用のレビュー観点で、直したところを見てくれます。

D1-3見たい形を決めてから画面を作らせる[25min]
ねらい

何が見たいかを先に自分で決めて、それが出る画面を1枚つくらせます。

この演習で扱うもの

いま受注一覧は JSON でしか見られません。ブラウザで /api/orders を開くと、10件ぶんのデータが1行にびっしり並びます。読めないことはないですが、何件あるか数えるのも、金額を合計するのも手作業になります。

これを表にします。置き場所は src/main/resources/static で、いまは空です。ここに置いたファイルは http://localhost:8080/ファイル名 で見られます。Java には触らないので、ファイルを置き換えるだけで画面が変わります。

なぜこれをやるのか

「いい感じの画面を作って」と頼むと、いい感じの画面が返ってきます。問題は、返ってきたものを評価できないことです。何が出ていれば良いのかを決めていないので、良いとも悪いとも言えない。直しようがありません。

見たい形を先に決めておくと、出てきたものと突き合わせられます。足りなければ「これが出ていません」と言えます。AI に任せる範囲が広いほど、先に決めておく重要性が上がります。

ここまで出たら完了
  • 決めた3つのうち、2つ以上が画面に出ている
  • http://localhost:8080/dashboard.html に受注10件が表で並ぶ
  • 1行の依頼で見た目を直し、ブラウザの再読み込みだけで反映されるのを確かめた
  • 何を頼んだら何が変わったかを、1つ言える
完了の一例。ここまで作り込む必要はありません。表が出れば達成です
完了の一例。ここまで作り込む必要はありません。表が出れば達成です
さわるファイル
新規src/main/resources/static/dashboard.html自分の画面を1枚つくる
まず自分で考える [3min]

この画面で何が見たいかを3つ決めてください。凝らなくて構いません。自分が受注の担当者だったら何を知りたいか、で考えると出ます。

  • 一覧に出す列(受注番号・顧客名・金額・状態・受注日など、どれを出すか)
  • 件数や合計金額のような、まとめの数字を出すかどうか
  • 並び順(新しい順か、金額の大きい順か)
AI と詰める

Shift+Tab を「plan mode」と出るまで押してから頼みます。計画が先に出るので、決めた3つが入っているかを承認前に確かめられます。

長く書く必要はありません。決めた3つを短く添えるだけです。

@src/main/java/com/example/order/controller/OrderController.java
この API を叩いて受注一覧を表で見られる画面を作りたいです。
src/main/resources/static/dashboard.html に単一の HTML で作ってください。
(ここに決めた3つを書く。例:金額は3桁区切りで、上に件数と合計を出してください)
手を動かす
1
考える
画面に何が見えたら嬉しいかを3つ決めます。並べる列、金額の見せ方、日付範囲の検索の操作の3つです。
2
書く
Shift+Tab を、入力欄の下に plan mode と出るまで押します。押すたびに manual mode、accept edits、plan mode と切り替わるので、plan mode で止めます。@src/main/java/com/example/order/controller/OrderController.java を添えて「この API を叩いて受注一覧を表で見られる画面を作りたいです。src/main/resources/static/dashboard.html に単一の HTML で作ってください」と頼みます。長い指示は要りません。
3
実行
出てきた計画を読み、矢印キーで Yes を選んで Enter を押します。承認すると dashboard.html ができるので、アプリは1枚目のターミナルで動かしたまま、ブラウザで http://localhost:8080/dashboard.html を開きます。
4
答え合わせ
決めた3つと違うところを、1回に1つずつ短い日本語で直します。直すたびにブラウザを再読み込みして、変わった箇所を見ます。
考えること
一発で全部指示した場合と、一言から始めて1つずつ足した場合で、どちらが速く欲しい形に届いたか。
AI の出方
同じ依頼でも配色や列構成は毎回変わります。派手すぎたら「装飾を減らして、白背景に細い罫線だけの落ち着いた見た目にしてください」と言い直してください。一度に直しすぎて壊れたときは「さきほどの変更を取り消して」で戻せます。
D1-3+ステータスごとの件数と、受注金額の合計を一覧の上に出してください。「ステータスごとの件数と、受注金額の合計を一覧の上にまとめて出してください」の一言で足せます。集計を JavaScript 側でやるか、API を足してサーバ側でやるかは自分で決めてください。どちらを選んだかと理由を一言で言えるようにしておくと、Day3 のレビュー演習につながります。
くわしく(背景・詰まったときの対処)

src/main/resources/static は空です。フォルダごと見当たらないときは、Claude Code が作ってくれます。Spring Boot はこのフォルダに置いたファイルを http://localhost:8080/ファイル名 で配るので、dashboard.html を1枚置くだけで画面ができます。Java には触らない演習です。Planモードは計画を出すところで一度止まるので、Yes を選んで承認するまで dashboard.html は作られません。

アプリは起動したままで構いません。この配布物は動いているアプリが src/main/resources を直接読むので、dashboard.html を新しく置いてもブラウザを再読み込みするだけで出ます。中身を直したときも同じで、再読み込みだけで変わります。起動し直しが要るのは Java を直したときだけです。頼む、見る、直すを止めずに回してください。

この演習の軸になる API は、GET /api/orders と GET /api/orders/{id}、D1-2 で足した GET /api/orders/date-range の3本です。ほかに顧客名検索の /api/orders/search?customerName= とステータス検索の /api/orders/status/{status} も動いているので、余力があれば使ってください。D1-5 でステータス変更ボタンを足すときは、PATCH /api/orders/{id}/status を使います。

何が見たいかを決めずに「いい感じの画面を作って」と頼むと、返ってきたものを評価できません。評価できないものは直せないので、先に見たい形を決めておきます。この画面は D1-4 以降でも手を入れ続ける前提です。明細を返せるようにしたら明細欄、ステータス遷移を実装したら変更ボタンを、自分で足していってください。

完成度は問いません。表が出れば達成です。手が止まる人はプロンプトが長すぎることが多いので、短く言い直してください。ファイル名を変えると URL も変わるため、dashboard.html の名前のまま以降の演習でも使います。

休憩

[10min] ここで一度手を止めます。詰まっている方はこの間に声をかけてください。

D1-4返す項目を選んでから作らせる[25min]
ねらい

外に出す項目と出さない項目を自分で決めてから、明細を返せるようにします。

この演習で扱うもの

受注1件を取ると、受注番号も顧客名も合計金額も返ってきます。ところが、何をいくつ買ったかという明細だけが返りません。

データベースには明細が13件入っていて、受注のデータも明細を持っています。足りないのは外に出す側です。API のかたちを決めている入れ物に、明細の項目がありません。

明細が持っているのは7つです。ID、親の受注への参照、商品コード、商品名、数量、単価、小計。このうち何を外に出すかを選びます。

なぜこれをやるのか

データベースの持ち方と、API で返すかたちは別物です。内部の持ち方をそのまま外に出すと、内部を変えたときに API まで壊れます。だから間に入れ物を1枚挟んで、出す項目だけを詰め替えます。

AI は、頼まなければ全部入れてきます。特に親への参照は要注意で、受注が明細を持ち、明細が受注を持つ形になると、変換のときに無限に往復して落ちます。「入れないでほしいもの」を言葉にするのが、ここでの練習です。

ここまで出たら完了
  • 返す項目を自分で選び、親への参照を外した理由を言える
  • /api/orders/1 に items が現れ、RACK-42U-BK の明細1件が入っている
  • 明細の小計 540,000 に 1.10 を掛けた 594,000 が、上の totalAmount と一致する
  • /api/orders/2 では明細が2件並ぶ
完了時。items が出て、小計と税込金額が対応していれば達成です
完了時。items が出て、小計と税込金額が対応していれば達成です
さわるファイル
新規src/main/java/com/example/order/dto/OrderItemDTO.java明細を返すための入れ物
書くsrc/main/java/com/example/order/dto/OrderDTO.javaitems を足して変換する
まず自分で考える [3min]

明細の7項目のうち、API で返すものを選んでください。受注の画面に明細を並べるとしたら何が要るか、で考えます。

  • 商品コード / 商品名 / 数量 / 単価 / 小計 — このあたりは要りそうか
  • 内部の ID — 外に出す意味はあるか
  • 親の受注への参照 — 入れるとどうなるか。受注が明細を持ち、明細が受注を持つ形になる
AI と詰める

Planモードで頼みます。計画に「親への参照」が入っていたら、承認せずに No, keep planning を選んで外させてください。ここが今日いちばんの分かれ目です。

承認してしまうと、見た目は動くのに変換で落ちるものができます。

@src/main/java/com/example/order/model/OrderItem.java
@src/main/java/com/example/order/dto/OrderDTO.java
受注の中身(何をいくつ、いくらで買ったか)も一緒に返るようにしてください。
返すのは商品コード、商品名、数量、単価、小計の5つです。
元の受注に戻る参照は入れないでください。
/api/orders/1 に items が出れば完了です。
手を動かす
1
考える
OrderItem が持つ7つのフィールドのうち、API に返すものと返さないものを決めます。親への参照 order を含めるとどうなるかも考えます。
2
書く
Shift+Tab を plan mode と出るまで押し、@OrderItem.java と @OrderDTO.java を渡します。OrderItemDTO の新規作成と、OrderDTO への items 追加を依頼します。
3
書く
出てきた計画に親への参照 order が入っていたら、矢印キーで No, keep planning を選び「order は含めないでください」と伝えます。直った計画を Yes で承認します。
4
答え合わせ
Java を直したので、1枚目のターミナルで Ctrl+C を押し、mvn spring-boot:run で起動し直します。ブラウザで http://localhost:8080/api/orders/1 と /api/orders/2 を開き、items 配列と小計を読みます。
考えること
一覧の /api/orders も同じ変換を通る。10件返すとき、明細を取りにいく SELECT は何回走るか。
AI の出方
生成された OrderItemDTO に親への参照 order が紛れることがあります。明細が無い受注で items が null になる案も出るので、空リストになっているかを変更内容で確かめてください。赤い波線が残ったら、そのまま「足りない import を補って」と続けて頼めます。
D1-4+src/main/java/com/example/order/model/Customer.java を手本に、配送先を表す ShippingInfo エンティティを同じフォルダに新規作成してください。@Table のテーブル名、shippingCode の unique = true、@Column のカラム名がスネークケースになっているかを、承認する前に点検します。余力があれば schema.sql に CREATE TABLE shipping_info も追記してください。Java を足したので、確かめる前に1枚目のターミナルで Ctrl+C を押し、mvn spring-boot:run で起動し直します。受注 API の本筋には触らないので、後続の演習に影響しません。
くわしく(背景・詰まったときの対処)

GET /api/orders/1 を叩くと、受注番号も顧客名も合計金額も返るのに、明細の配列だけが返りません。データベースの order_items には13件の明細が入っていて、エンティティの Order も items を持っています。足りないのは外に出る側です。OrderDTO に明細のフィールドが無く、変換メソッドの fromEntity が明細に触れていません。

DTO は、返したい項目だけを詰め替えて外に出すための入れ物です。エンティティの OrderItem をそのまま返すと、データベースの持ち方がそのまま API の形になります。いまは親参照の order に @JsonIgnore が付いているので JSON の循環こそ止まりますが、LAZY の親参照や内部項目に外向きの形が引きずられます。だから明細専用の OrderItemDTO を新しく起こします。

D1-2 は既存メソッドの穴を埋める作業でした。ここはクラスを一枚まるごと新設して、関連ファイルも一緒に直す場面です。Planモードで計画を先に見てから承認してください。承認せずに直したい点を伝える操作も、ここで一度やっておきます。

作るのは src/main/java/com/example/order/dto/OrderItemDTO.java の1本、直すのは同じフォルダの OrderDTO.java です。どちらも Java なので、確認の前にアプリを起動し直します。返すフィールドは productCode、productName、quantity、unitPrice、subtotal の5つが目安になります。id=2 は L3スイッチと L2スイッチの明細を2件持つので、複数明細も合わせて確かめておくと安心です。

時間が余ったら、@src/main/resources/static/dashboard.html を対象に「行を開いたら明細を表示してください」と1行で頼み、自分の画面にも明細を出してください。こちらは HTML だけの変更なので、ブラウザの再読み込みだけで反映されます。

D1-5業務ルールを決めてから直させる[25min]
ねらい

変えてよい遷移と残すべき遷移を自分で整理してから、ルールを直します。

この演習で扱うもの

受注の状態は5つあり、進む順番が決まっています。受付前から確定へ、確定から発送済へ、発送済から納品済へ。キャンセルはいま、受付前からしかできません。

実際の業務では、確定したあとでもキャンセルは起きます。取引先の都合、在庫切れ、発注ミス。発送してしまえば取り消せませんが、その手前なら取り消せるはずです。ここを直します。

直す場所は1か所、遷移の可否を判定しているところです。そのあと、自分の画面から実際に操作できるようにします。

なぜこれをやるのか

業務ルールの修正は、足すより「壊さない」ほうが難しい作業です。確定からキャンセルできるようにするだけなら簡単ですが、そのとき確定から発送済へ進む道が消えていないか。ここを見落とすと、動いているように見えて業務が止まります。

AI は頼まれた1点に集中するので、周りを巻き込むことがあります。残すべきものを先に言葉にしておくのが、ここでの練習です。

ここまで出たら完了
  • 確定から進める先が2つになり、消してはいけないものを言える
  • 画面のボタンから id=2 を CANCELLED にでき、再読み込みで一覧が変わる
  • CONFIRMED の id=3 を SHIPPED に変える操作は、今までどおり通る
  • SHIPPED の id=4 をキャンセルしようとすると通らない(500 が返る)
さわるファイル
書くsrc/main/java/com/example/order/service/OrderServiceImpl.javaCONFIRMED の遷移を直す
書くsrc/main/resources/static/dashboard.htmlステータス変更ボタンを足す
まず自分で考える [3min]

確定(CONFIRMED)の状態から進める先を、いまと直したあとで書き出してください。

  • いま、確定から進める先はどこか(1つある)
  • 直したあと、確定から進める先はどこか(2つになるはず)
  • この修正で、絶対に消してはいけないのはどれか
AI と詰める

「残すもの」を必ず書いて送ってください。書かないと、確定の分岐ごと書き換えて発送済への道を消した案が返ることがあります。

画面側は別の依頼にします。1回に1つです。

@src/main/java/com/example/order/service/OrderServiceImpl.java
validateStatusTransition で、確定済み(CONFIRMED)から
キャンセル(CANCELLED)にもできるようにしてください。
発送済み(SHIPPED)に進める動きは今までどおり残してください。
手を動かす
1
考える
case Order.STATUS_CONFIRMED に CANCELLED を足すとき、いまある SHIPPED への遷移をどう残すかを先に決めます。
2
書く
claude で validateStatusTransition の case Order.STATUS_CONFIRMED を対象に指定し、CANCELLED への遷移も許可するよう依頼します。SHIPPED は今までどおり残すと添えます。
3
書く
@src/main/resources/static/dashboard.html を対象に「行から PATCH /api/orders/{id}/status を叩いてステータスを変更できるボタンを足してください」と頼みます。叩き先が /cancel ではなく /status であることを、必ず言葉で指定します。
4
答え合わせ
Java を直したので、1枚目のターミナルで Ctrl+C を押し、mvn spring-boot:run で起動し直します。画面のボタンから id=2 を CANCELLED にし、続けて id=3 と id=4 でも試します。
考えること
InvalidOrderStateException は業務エラーなのに 500 で返る。本来はどの HTTP ステータスが正しいか。
AI の出方
文字列の "CANCELLED" を直に埋め込む案が出ます。Order.STATUS_CANCELLED の定数に直っているかを変更内容で確かめてください。case ブロックごと書き換えて SHIPPED への遷移を消してしまう案も出るので、そこも見ます。画面側では PATCH /api/orders/{id}/cancel を叩くボタンが出ることがあります。cancelOrder は遷移ルールを通らず、直す前でも 200 を返してしまうので、fetch のパスが /status になっているかを確かめてください。
D1-5+@RestControllerAdvice の共通エラーハンドラを足し、OrderNotFoundException を 404、InvalidOrderStateException を 400 に対応づけてください。実装後に1枚目のターミナルで Ctrl+C を押し、mvn spring-boot:run で起動し直してから SHIPPED の受注を叩くと、500 だったものが 400 に変わります。余力があれば updateOrder と deleteOrder に、PENDING 以外を弾くステータスチェックも足してみてください。
くわしく(背景・詰まったときの対処)

OrderServiceImpl の validateStatusTransition は、受注ステータスをある値から別の値へ変えてよいかを判定するメソッドです。配布時点では case Order.STATUS_CONFIRMED が SHIPPED への遷移しか許していないため、確定済みの受注をキャンセルできません。業務ルールでは PENDING と CONFIRMED からのキャンセルを認めます。出荷済み以降は認めません。モノが動いたのに帳簿だけ消える状態になるためです。

確認は PATCH /api/orders/{id}/status で行います。内部で validateStatusTransition が呼ばれるからです。PATCH /api/orders/{id}/cancel は cancelOrder という別のメソッドを呼ぶので、遷移ルールの確認には使いません。手順3で作るボタンも、押したときに叩くのは /status のほうです。

ステータス値は文字列の直書きではなく Order の定数を使います。綴り間違いをコンパイルの時点で見つけられるからです。

画面のボタンがうまく動かないときは、ターミナルから直接叩いても確かめられます。

打つのは次の1行です。curl -X PATCH http://localhost:8080/api/orders/2/status -H "Content-Type: application/json" -d '{"status":"CANCELLED"}'

返ってきた status が CANCELLED になっていれば通っています。

配布データでは id=2 と id=3 が CONFIRMED、id=4 が SHIPPED で入っています。id=2 を一度 CANCELLED にすると遷移元が変わるので、やり直すときはアプリを起動し直してください。H2 はメモリ上で動くので、起動のたびに配布時の10件へ戻ります。

新しいファイルは作りません。編集は OrderServiceImpl.java の中と、自分のダッシュボードだけです。手順4で起動し直すのは OrderServiceImpl を直したためで、ボタンを足した HTML のほうは再読み込みだけで反映されます。ボタンの見た目や文言をあとから直すときは、起動したまま再読み込みで確かめてください。

到達チェック

この日の終わりに、自分で確かめてください。全部埋まっていなくても構いません。

つまずいたとき

よく出る詰まりどころです。当てはまるものがなければ、その場で声をかけてください。

生成されたコードが正しいか判断できません。
判断の材料を先に持ってから頼むと変わります。D1-2 なら、呼ぶリポジトリメソッド・詰め替える型・返すものの3つを自分で決めてから依頼し、変更内容がその3つと合っているかだけを見てください。全部を読もうとすると手が止まります。この日の合否は、叩いた結果で決めるものだと思ってください。コードを読み切れなくても、ブラウザに出た結果が合っていれば正解の範囲です。
起動し直したらエラーが出て立ち上がりません。
ターミナルに出た [ERROR] で始まる行を、上から3行か4行そのままコピーしてください。2枚目のターミナルの Claude Code に貼り、「これが出ています。直してください」と伝えます。多くは import の不足です。起動に失敗した時点でプロセスは終わり、プロンプトが戻っています。直ったら1枚目のターミナルでそのまま mvn spring-boot:run を打ち直してください。
どこを直したらアプリを起動し直すのですか。
Java のファイルを直したときだけです。動いているアプリは起動時のクラスファイルを掴んだままなので、1枚目のターミナルで Ctrl+C を押し、mvn spring-boot:run で入れ直します。HTML と CSS と JavaScript は src/main/resources を直接読んでいるので、ブラウザの再読み込みだけで反映されます。コンパイルだけ先に通したいときは、ターミナル右上の+でもう1枚開き、そこで mvn compile を打ってください。2枚目は claude と話す窓なので、そこに打つとプロンプトとして送られます。
dashboard.html を開くと 404 か真っ白になります。
404 のときは保存先とファイル名を確かめてください。src/main/resources/static/dashboard.html に保存されていれば、アプリを動かしたままブラウザを再読み込みするだけで出ます。真っ白のときは F12 を押して Console タブを開き、赤い文字が出ていたらそのまま Claude Code に貼って「これが出ています」と伝えるのが最短です。fetch のパス違いか、レスポンスの構造の取り違えがほとんどです。
ダッシュボードを直したのに画面が変わりません。
まずブラウザを再読み込みしてください。それでも変わらないときは Ctrl+Shift+R で読み直します。保存できていない、あるいは別のファイルを直しているのが次に多い原因なので、パスが src/main/resources/static/dashboard.html になっているかを確かめてください。
/api/orders/date-range を叩いたら HTTP 400 が返ります。
D1-2 でエンドポイントを足す前は 400 になります。date-range という文字列が /api/orders/{id} の窓口に吸い込まれ、数値に変換できないためです。OrderController に /date-range を足して起動し直すと解消します。
id=2 のステータスを変えたあと、やり直したいです。
1枚目のターミナルで Ctrl+C を押し、mvn spring-boot:run で起動し直してください。データベースはメモリ上にあるので、起動のたびに配布時の10件へ戻ります。壊しても戻るので、気にせず試してください。