業務の隙間を埋める技術メモ。

「それ、作れるか?」より 「それ、作って大丈夫か?」を考えたい。 業務で“ちゃんと使える”かどうかを、 実際に手を動かして確かめたログを残しています。

Claude CodeでSuiteScriptのデバッグ環境を組んでみたら、初日に「事故の芽」を発見した話

対象:NetSuite開発者でAIコーディング支援の導入を検討している方/SDFを社内で初めて使う方/共用NetSuite環境でのGit運用に悩んでいる方

SuiteCloud Development Framework(以下SDF)を導入してみました。手元のClaude Codeと組み合わせてSuiteScriptのデバッグサイクルを回せるようにしたかった、というのが今回の動機です。

結論から言うと、初日のテストで「運用ルールがなければそのまま事故になっていた案件」を1件発見しました。ルールを先に決めてから動いたのが功を奏した形で、これがこの記事で一番書きたかった話です。

認証方式で詰まったり、プロジェクト構造で詰まったりもしたので、自分と似た立ち位置の方のために、詰まった順に書いていきます。


セクション1:前提――SuiteScriptは「ローカルで動かない」言語

結論

本題に入る前に、SuiteScript開発特有の事情をひとつ書いておきます。SuiteScriptはローカル環境で実行できません。これが今回の環境設計の前提を決めています。

なぜローカルで動かないのか

SuiteScriptは、NetSuiteのサーバー上でしか動かないスクリプト言語です。構文はJavaScriptですが、ランタイムとしてN/recordN/searchN/taskといったNetSuite固有モジュールに依存しており、これらはNetSuiteのサーバー環境にしか存在しません。

一般的なWeb開発であれば、ローカルでnodeなりnpm run devなりを叩けば手元で動かせます。Claude Codeもローカルでコードを実行して挙動を確認し、失敗したら修正して再実行、というサイクルを自律的に回せます。SuiteScriptではこれができません。

[一般的なWeb開発]
  Claude Code ──> ローカル実行 ──> エラー確認 ──> 修正
       ↑________________自律的ループ________________↓

[SuiteScript開発]
  Claude Code ──> コード修正 ──> ❓(ローカルで動かせない)
                                    │
                                    ↓
                             NetSuiteにアップ
                                    │
                                    ↓
                             人間が実行・ログ確認
                                    │
                                    ↓
                             結果をClaude Codeに戻す

これが環境設計にどう効いてくるか

ローカル実行ができないということは、コードの検証は必ずNetSuiteにアップロードしてから行うことになります。つまりアップロード経路の整備は避けて通れません。

さらに厄介なのは、Claude Codeに任せる範囲の設計です。普通のWeb開発なら「コードを直して、テストを走らせて、通ったらコミット」までClaude Codeに丸投げできますが、SuiteScriptではアップロードの前段で必ず人間の判断を挟む必要があります。共用環境だとなおさらです(後述)。

この「ローカルで検証できない」という制約が、後半で出てくる「Claude Codeにはアップロードさせない」という設計判断に直結しています。


セクション2:何をやろうとしたのか

結論

「Claude CodeでSuiteScriptのデバッグを効率化する」というのが最初のモチベーションでした。

NetSuite画面でポチポチ動かして、気になる挙動をリスト化して、ローカルに落としてきたSuiteScriptをClaude Codeに直してもらい、またNetSuiteに戻す。このサイクルを素早く回したい、というだけの話です。

プロジェクトの状況

扱っているのは財務会計のカスタマイズで、UIを強化するためスクリプト(特にsuitelet)を多用。SuiteScripts配下にざっと100ファイル以上あります。社内でSDFを本格運用している人はまだ誰もおらず、今回が第1号の導入になりました。

使用環境は下記の通り。

  • OS:Windows 11 + PowerShell 7.5.5
  • Claude Code:導入済み(ローカルCLI)
  • Node.js:18以上
  • SuiteCloud CLI for Node.js:3.1.2
  • NetSuite SB(サンドボックス)
  • SuiteScriptバージョン:2.1

当初の方針の「正しかった部分」と「甘かった部分」

最初に考えていたのは、単純にこのフローでした。

1. NetSuiteを動かして気になる部分をリスト化
2. Claude Codeにローカルで一式を見せる
3. 修正してもらう
4. NetSuiteに反映

正しかった部分は、ローカルにコードを置いてClaude Codeに触らせる方針そのものです。複数ファイルにまたがる影響調査や、似たパターンの一括修正はClaude Codeの得意分野なので、方向性としては王道だと思います。

甘かった部分は3つありました。ひとつめはデバッグログの扱いを設計していなかったこと。ふたつめは修正後のアップロードループが重いままだったこと(SDFを整備していなかった)。そしてみっつめが一番大きくて、共用環境での他者との衝突を十分考慮できていなかったことです。この3つ目があとで効いてきます。


セクション3:つまずきポイント①――AIがTBAを勧めてきた(鵜呑み厳禁の例)

結論(先に言う)

これは「詰まった」というより「AIを鵜呑みにしてはいけない例」として書いておきます。Claude CodeはTBA(トークンベース認証)での手順を最初に提示してきましたが、実際にはOAuth 2.0を使う必要があることは事前にわかっていたので、方針を変えさせる必要がありました。

事前にわかっていたこと

OAuth 2.0を使う必要があることは、作業開始前から把握していました。

時期 TBA(OAuth 1.0)の扱い
現在(2026.1) 既存・新規ともに利用可能
2027.1 新規インテグレーションでの使用不可になる
2027.2以降 既存TBAは継続サポートだが、新機能はOAuth 2.0のみ

加えて、SuiteCloud SDK 24.2以降はOAuth 2.0のみサポートです。最新CLIを使っている以上、TBAを選ぶ理由がありません。

それでもAIはTBAを勧めてくる

にもかかわらず、Claude Codeに「NetSuite CLIの認証をセットアップしたい」と雑に聞くと、Integration作成→Consumer Key/Secret取得→アクセストークン発行→Token ID/Secret取得、というTBAの手順を最初に提示してきました。

これは、AIの学習データに「NetSuite CLI 認証」の情報として古い手順が多く残っているためだと思われます。ネット上の日本語記事も、TBAを前提にしたものが圧倒的に多いので、仕方がない面はあります。

「TBAは廃止予定だから、OAuth 2.0の手順に変えて」と指示し直して、ようやく正しい方向に軌道修正しました

教訓:AIの提案を鵜呑みにしない領域を把握しておく

今回の場合、事前に最新動向を知っていたので軌道修正できましたが、もし知らないまま進めていたらTBAで環境を組んでしまい、2027.1以降に作り直すハメになっていたはずです。

特にクラウドサービス系の認証・APIまわりは廃止タイムラインが頻繁に動くので、AIの学習データが追いついていない領域です。この手のテーマでAIに聞くときは、公式ドキュメントの最新版で必ずクロスチェックすることにしています。

「AIに聞いて時短する」と「AIの提案を鵜呑みにする」は別物だと、改めて認識させられた件でした。

採用したのはブラウザ認証

OAuth 2.0と決まったあとも、M2M(Client Credentials/証明書ベース)とブラウザ認証の2択がありました。

個人のローカル用途ではM2Mはオーバースペックなので、suitecloud account:setupのブラウザ認証に落ち着いています。

suitecloud account:setup
  • Integration作成不要(組み込みの"SuiteCloud Development Integration"を使ってくれる)
  • 証明書生成不要
  • ブラウザで承認するだけ

将来CIに載せるときにM2Mを追加すればいいので、最初からM2Mを頑張る必要はありませんでした。

ちなみに:Integration作成で「無効なリダイレクトURI」に遭遇したら

軌道修正後、Integration作成画面で「無効なリダイレクトURI」エラーに遭遇することがあります。OAuth 2.0の「承認コード付与」がデフォルトONになっていて、リダイレクトURIが必須になっているためです。ローカルCLI用途では不要なので、OFFにすればエラーは消えます。


セクション4:つまずきポイント②――プロジェクト構造の罠

結論(先に言う)

suitecloud.config.jsを忘れると、CLIは何も動いてくれません。

自力で組んだら怒られた

最初にこんな構造を作りました。いかにもSDFっぽい、src/配下に全部入れる形です。

<プロジェクトルート>/
├── src/
│   ├── FileCabinet/SuiteScripts/<機能名>/
│   ├── Objects/
│   ├── manifest.xml
│   └── deploy.xml
├── project.json
└── package.json

suitecloud account:setupを走らせると怒られます。

No manifest.xml file was found in <プロジェクトルート>.
Run "account:setup" in a valid project folder.

manifest.xmlはsrc/配下にあるのに「見つからない」と言われて、しばらく意味がわかりませんでした。

原因はsuitecloud.config.jsの欠如

CLIは、プロジェクトルート直下にsuitecloud.config.jsがないと「どこがプロジェクトフォルダなのか」を判断できません。src/配下にファイルを置く構造にする場合は、この設定ファイルで明示する必要があります。

// suitecloud.config.js
module.exports = {
    defaultProjectFolder: 'src',
    commands: {},
};

これ1ファイル追加するだけで動くようになりました。

最終的に落ち着いた構造

<プロジェクトルート>/
├── src/
│   ├── AccountConfiguration/
│   ├── FileCabinet/
│   │   └── SuiteScripts/
│   ├── Objects/
│   ├── Translations/
│   ├── deploy.xml
│   └── manifest.xml
├── project.json
├── package.json
└── suitecloud.config.js     ← これを忘れがち

教訓

エラーメッセージが「manifest.xmlが見つからない」としか言ってくれないのが不親切でした。「suitecloud.config.jsが無いのでsrc/を見に行けていません」と書いてくれれば1秒で気づけたのに、と思います。

最短ルートは、自力で組まずsuitecloud project:create -iで雛形を作ることです。そこから削っていく方が、一つひとつの役割を踏んでいけます。自分は先に組んでしまったので、結果として雛形を参考にファイルを足していく形になりました。


セクション5:つまずきポイント③――共用環境という最大の盲点

結論(先に言う)

ここが今回のヤマです。

「NetSuite SBは、Gitを使わない他メンバーも含めて複数人で共用している」という事実に、環境を組み上げたあとに気づきました。これが判明した瞬間、最初に考えていたフローがいきなり破綻します。

想定される事故シナリオ

共用環境でGit管理してるのが自分だけ、という状況で起きうる事故はこれです。

1. 自分がローカルでファイルAを修正開始
2. 同時に同僚がNetSuite UI上で同じファイルAを直接編集・保存
3. 自分が修正完了して npm run upload でアップ
4. 同僚の変更が気づかないうちに巻き戻る

SBの業務処理に影響する可能性がある、重大な事故です。しかもエラーが出ないので気づきません。先日書いたSuiteScriptスクリプトタイプ完全ガイドでも触れましたが、NetSuite系の事故は「エラーが出ない」タイプが一番厄介です。

検討したけど却下した方針

いくつか方針を検討しました。

領域分離(自分専用フォルダ):構造としては理想ですが、社内調整が必要で、1人で今日立ち上げたい状況には合いません。断念。

アップ禁止モード(Claude Codeは分析だけ):これなら事故は起きませんが、自動化の意味が半減します。却下。

時間帯分離(夜間のみ作業):持続不可能。却下。

採用した「アップ前同期」運用

結局、修正サイクルごとに毎回同期を取る運用にしました。

1. npm run import -- /対象ファイル で SB 最新を取得
2. git diff で他者変更の有無を確認
3. 他者変更があれば先にコミット(sync: ...)
4. その後に自分の修正を実施
5. アップ直前にもう一度 import で再確認
6. 問題なければ npm run upload

手間は増えますが、事故のダメージと比較すれば軽微です。何よりこのルールが初日で早速役に立ちました


セクション6:初回テストで発見した「事故の芽」

結論(先に言う)

「何もないはず」のテスト対象で、ローカルとSBで値が完全に違っていました。このままアップしていたら業務処理が止まっていた案件です。

テスト対象の選定

最初のfile:importテストなので、リスクゼロの対象を選んだつもりでした。Git的には100%同一(過去にrenameしただけ)の定数定義ファイルです。「取り込んでもアップしてもSBは変わらないはず」という前提で選びました。

予想外の差分

ところがgit diffを見たら、こうなっていました。

// ローカル(Git管理下)        SB 実値
FOLDER_A : 11111,    →    FOLDER_A : 41837,
FOLDER_B : 22222,    →    FOLDER_B : 41836,
FOLDER_C : 33333,    →    FOLDER_C : 41839,
FOLDER_D : 44444,    →    FOLDER_D : 41840,
FOLDER_E : 55555,    →    FOLDER_E : 41841,

左のローカル側はプレースホルダー(仮の値)で、右のSB側が実際のフォルダIDです。ソースコメントには「スクリプトパラメータで上書きすること」と書いてあるのですが、実装は未完で、運用ではSB上で直接ハードコード修正している状態でした。

もし「アップ前同期」ルールがなかったら

このファイルはGit的には「変更なし」なので、普通ならローカルからそのままアップしてもおかしくありません。しかしそれをやると、こうなります。

  • ローカルのプレースホルダー値がSBに反映される
  • MapReduceのテンポラリファイル生成先フォルダが存在しないIDを指す
  • 関連する業務処理がエラーで止まる
  • SBの業務処理が壊れる

想像するだけで青ざめます。

運用ルールが初日に実証された

設定した運用ルールの価値が、初回テストで早速事故を防いだ形で証明されました。正直これは偶然の発見ですが、逆に言えばルールを先に決めていなかったら、初日から事故を起こしていた可能性が高いということです。

技術的負債としてもdocs/debug-list.mdTECH-001として登録しました。対応案は「スクリプトパラメータ化」「環境分岐」「設定ファイル外出し」の3つを記載。優先度は中で、当面は「アップ前同期」で回避します。

教訓

「Git的に同一」であっても、実環境とは乖離している可能性があります。環境依存値(フォルダID、ユーザーID、日付しきい値など)は特に注意が必要です。

そしてClaude Codeが「プレースホルダーっぽい値」を勝手に整理・リファクタするのは危険ということも、このタイミングで痛感しました。AIは「11111, 22222, 33333」を見ると「仮の値だから実装を完了させましょう」と提案してきがちです。


セクション7:CLAUDE.mdに仕込んだガードレール

結論(先に言う)

共用環境でClaude Codeを使う場合、「やっていいことリスト」より「やってはいけないことリスト」の方が重要です。

自動実行させないコマンド群

CLAUDE.mdに、Claude Codeが自動実行してはいけないコマンドを明示しました。

  • npm run import / suitecloud file:import
  • npm run upload / suitecloud file:upload
  • suitecloud project:deploy
  • suitecloud project:validate

これらは全部、人間が実行します。Claude Codeは「次に実行すべきコマンド」を文字列で提示するだけです。意図しないアップロードによる事故を防ぐため、特に共用環境では必須と考えています。

環境依存値の改造禁止

TECH-001の発見を受けて、環境依存値に関する禁止事項も明記しました。Claudeがやってはいけない改造はこれです。

  • プレースホルダーっぽい値の環境変数化
  • スクリプトパラメータへの置き換え
  • runtime.envTypeでの分岐ロジック追加
  • 環境別設定ファイルへの外出し
  • デフォルト値の変更
  • 「より適切そうな値」への書き換え

どれもAIの発想としては自然な提案なので、明示的に止める必要がありました。

技術的負債の記録ルール

デバッグ中に負債を発見したらdocs/debug-list.mdTECH-XXX形式で記録します。重要なのは、Claudeは発見時にユーザーへ追記を提案する(勝手に追記しない)、そしてClaudeは負債そのものを勝手に修正しないという2点です。

その他

改行コードはLF統一、.gitattributesは将来導入予定、Claudeは改行コード変換だけの一括書き換えをしない、といった地味だけど効くルールも書いています。


セクション8:完成したデバッグサイクル

典型的な1サイクルの流れ

# 1. NetSuite SB で不具合を再現、症状を観察
# 2. docs/debug-list.md に BUG-XXX として記録

# 3. Claude Code 起動
claude

# 4. 「BUG-XXX 対応して」と指示

# 5. Claude Code が修正案と「次に実行すべきコマンド」を提示

# 6. SB 最新を取り込み
npm run import -- /SuiteScripts/<対象ファイルパス>.js

# 7. 他者変更の有無を確認
git diff src/FileCabinet/SuiteScripts/<対象ファイルパス>.js

# 8. 他者変更があれば先にコミット
git add 対象.js
git commit -m "sync: 他者のSB編集を取り込み"

# 9. 問題なければアップロード
npm run upload -- /SuiteScripts/<対象ファイルパス>.js

# 10. NetSuite SB で動作確認、ログ確認

# 11. debug-list.md のケースを「検証中」→「完了」に更新

# 12. コミット
git add 対象.js docs/debug-list.md
git commit -m "fix(BUG-XXX): 問題の修正"

package.jsonのscripts

{
  "scripts": {
    "upload": "suitecloud file:upload --paths",
    "import": "suitecloud file:import --paths",
    "list:sb": "suitecloud file:list --folder",
    "validate": "suitecloud project:validate --accountspecificvalues WARNING",
    "auth:list": "suitecloud account:manageauth --list",
    "auth:current": "suitecloud account:manageauth --info"
  }
}

以前(手動アップ)との比較

以前はFileCabinetを開いてファイルを右クリック→編集→貼り付け→保存、という流れでした。1ファイル1~2分、10ファイル修正すると10~20分の単純作業です。

今の構成なら10ファイルでも数十秒で終わります。圧倒的に速い。ただし速い分、事故のスピードも速いので、「アップ前同期」で安全弁を挟んでいます。


セクション9:ハマりどころ逆引き表

症状 原因 対処
suitecloud -v でエラー オプション名が違う suitecloud --version または npm list -g @oracle/suitecloud-cli
Integration作成で「無効なリダイレクトURI」 OAuth 2.0の「承認コード付与」がON OFFにする。ローカルCLI用途なら不要
account:setup で「No manifest.xml file was found」 suitecloud.config.jsがない プロジェクトルートに作成(defaultProjectFolder: 'src'指定)
TBAを使おうとしたら将来廃止と言われた 2027.1で新規不可 OAuth 2.0に切り替え。ローカル用途ならaccount:setup(ブラウザ認証)
「The authorization credentials are no longer valid」 トークン期限切れ 自動でブラウザ認証がリフレッシュされる。そのまま進めてOK
Git for Windowsで「LF will be replaced by CRLF」警告 改行コード変換警告 実害なし。気になるなら.gitattributesでLF統一
file:import で意外な差分が出た SBで誰かが編集していた 先にコミットして「他者変更のベースライン」として記録
file:import.attributes/ フォルダが自動生成された SDFのメタデータ Git管理に入れてOK

セクション10:この記事で一番伝えたかったこと

「エラーが出ない事故」は先回りでしか防げない

今回のTECH-001は、エラーが出ないタイプの事故でした。ローカルのプレースホルダー値をアップしても、SuiteScriptの構文的には何も問題ありません。実際に業務処理を動かしたときに、存在しないフォルダIDを参照してMapReduceが落ちて、はじめて「何かがおかしい」と気づく類の事故です。

SuiteScript開発では、こういう「エラーが出ないまま数日後に発覚する」タイプの事故が一番怖いと思っています。「アップ前同期」のような予防的ルールは手間ですが、事後対応のコストと比較すれば圧倒的に軽いです。

Claude Codeを使うなら「やらないことリスト」が命

Claude Codeは優秀で、言えば大抵のことをやってくれます。だからこそ、やってほしくないことを明示的に書く必要があります。

特にSuiteScriptの場合、環境依存値や共用環境という前提はAIには見えません。CLAUDE.mdでそれを文字にしておかないと、AIにとっては「プレースホルダーっぽい値を整理する」のは善意のリファクタです。

社内展開はゆっくり

この環境を他の人に広げるのはまだ早いと判断しています。本人が1~2週間運用して効果を体感してから、CLAUDE.mdを社内向けに一般化し、「アップ前同期」ルールをチーム合意にして、1~2人に段階的に広げる流れが無難です。

SDF化は開発プロセスそのものを変えるので、いきなり全員に導入するのはリスクが大きすぎます。1人がパイロット運用して実績を積んでからの方が、安全に広げられそうです。


まとめ――やってみて良かったこと

  • Claude Code × SuiteCloud CLI × SDFの組み合わせは、デバッグサイクルを10倍以上速くします(手動アップと比較して)
  • SuiteScriptはローカルで動かないので、アップロード経路の整備と、Claude Codeに任せる範囲の線引きが必須
  • 共用環境では「アップ前同期」ルールが必須。手間はかかるが、初日で実際に事故を防ぎました
  • 認証はOAuth 2.0ブラウザ認証が最短。ただしAIは古い情報(TBA)を勧めてくるので鵜呑み厳禁
  • CLAUDE.mdでガードレールを先に作る。特に環境依存値まわりはAIに触らせないルールを明示

次は「ガバナンスポイントで詰まったときの逃げ方」か、「Claude CodeにCLAUDE.mdでどこまで制約を書くべきか」あたりを書こうと思っています。何か質問があればブックマークコメントかXで教えてください。

参考リンク