kintone hack 2025「じゃあ、やってみよう」の舞台裏

本戦の会場に登場したときの写真。巨大なスクリーンに「シダックス」と表示され、登壇者である志太悠真の顔写真をAIでイラスト化したものが映っている。ステージには登壇者たちが並んでいる。

2025年10月27日に幕張メッセで開催された「kintone hack SHOW+CASE Unlimited」に、シダックス株式会社として出場させていただきました。 惜しくも優勝することはできませんでしたが、kintoneカスタマイズに精通する多くの方々と交流できたことや、あれほどの大舞台で発表できたことはとても貴重な経験となりました。 この記事では、応募から本番までの舞台裏や、開発したアプリの技術的な工夫などをご紹介します。 kintoneのカスタマイズや、kintone hackへの参加の参考になれば幸いです。

今回開発したアプリや発表資料、ドキュメント類は、GitHubのリポジトリ「shidax-corp/kintone-authenticator」で公開しています。 アプリテンプレートはすぐにダウンロードして使えるようにしてありますので、ぜひお手元の環境でも試してみてください。

この記事の目次:

発表概要

Google Authenticatorのようなワンタイムパスワード生成アプリをkintoneで実装したアプリを発表しました。 元ネタがスマホアプリだったので、発表タイトルは「kintoneで『アプリ』を作ってみた」としました。

このアイデアは、kintoneアプリを作成するときに社員に出してもらっている「アプリ作成申請」を「スマホアプリのインストール申請」と勘違いして出された申請が元になっています。 その申請には、「顧客と利用しているクラウドサービスで二段階認証が必要なのでGoogle Authenticatorが欲しい」というような内容が書かれていました。 一見すると馬鹿馬鹿しいだけの間違い申請に思われますが、よくよく考えてみるととても実用的……? じゃあ、やってみよう! ということでkintone hackに出してみることにしました。

ちなみに、懇親会などで何度か聞いていただいたのですが、この話はすべて実話です。 発表中の実例もすべて本物の申請です。頭が痛いですね。

キャッチコピー・コンセプト

表向きのキャッチコピーとして「じゃあ、やってみよう」を全面に押し出して発表しました。 「エンドユーザーからの馬鹿馬鹿しい要望にこそ革新的な業務改善のヒントが隠されているかもしれないので、一蹴せずに考えてほしい」という思いを込めています。

アプリや発表を作る上では、「知ってるけど知らない」というコンセプトを意識しました。 たとえば以下のような点にこのコンセプトが反映されています。

  • 標準のkintoneに似た"知ってる"UIで統一するが、その挙動はkintoneよりずっと速かったり、全く新しい機能が入っていたりと、"知らない"挙動をする。
  • 発表スライドについてもkintone風の"知ってる"デザインになっているが、画面全体がズレて落ちたり、フィールドが外れて背後が見えたりと、"知らない"デザインや動きが入る。
  • 発表の締めを冒頭と同じテイストの言葉から始めて"知ってる"ところに戻すが、結論は真逆の"知らない"内容にする。

また、私個人のいつものスタイルとして、コントラストを際立たせることも意識していました。 上記の"知っている"と"知らない"の対比もそうですし、発表中の大きくて高いポジティブな声と小さくて低いネガティブな声の対比、スライドの余白や色の使い方にそれらが反映されています。

演出上の効果がどこまで出たかは分かりませんが、少なくともコンセプトを決めておいたことでデザインやシナリオを迷わず設計することができました。

応募~本戦まで

まずは、応募から本戦までを時系列でふりかえってみます。 舞台裏よりも技術的な話にご興味がある方は、この下の「技術的な話」の節をお読みください。

2023年: kintone hackを知る

kintone hackのことを知ったのは2023年のことでした。 Cybozu Daysの中のガルーンのセッションで登壇させていただき、その流れでkintone hackの本戦を観覧しました。 このときに「業務用のツールなのにこんなふざけた面白いことをする大会があるのか!」と強く印象に残り、いつか出てみたいと思うようになりました。

ここからしばらくはネタを考えていたのですが、日々の業務に忙殺され、いつしかkintone hackのことは意識しなくなっていました。

6月初旬: 問題の申請が届く

それから1年半ほどが過ぎたとき、kintoneの運用担当者から件の「Google Authenticatorが欲しい」という申請の話を聞きました。 担当チームのメンバーと「また馬鹿な申請が来たよ」「申請フォームが分かりづらいんだろうか」「これだからエンドユーザーは……」なんて会話をする中、私はぼんやりとkintone hackのことを思い出していました。

これ、実現できるんじゃないだろうか? なんとはなしに呟いた「やってみましょうか」という言葉から、kintone hackへの挑戦が始まりました。

余談ですが、問題の申請はその場で却下されました。 会社支給のスマホには既にGoogle Authenticatorが入っているので、普通にそれを使ってください、ということで……。

6月12日: 応募

ネタが決まってからすぐにワンタイムパスワードの仕組みを調べて、どうやら実現可能そうだということが分かりました。 ブラウザ内で暗号を扱った経験はすでにありましたし、スマホ版kintoneもChrome拡張もWeb開発の技術で作れますから、技術的なハードルは高くありません。

そういうわけで、ネタが決まってすぐに書類審査に応募しました。

この時点で手元にあったのは基本的な概念と、ワンタイムパスワードのロジックを検証した短いスクリプト、それから応募のために必要だった構成図だけでした。 まあ、なんとかなるでしょう。

応募時の構成図。kintoneアプリにカスタマイズを施すこと、Chrome拡張機能でも同等の機能を提供すること、くらいしか書かれていない。

7月11日: 書類審査に通過

7月11日、書類審査を通過したという通知メールをいただきました。

このときは「やった!」という気持ちと、「通ってしまった」という気持ちが半々でした。 というのも、本業に追われており、例の検証スクリプトを書いてからは何もできていなかったのです。

ちなみに、応募があったのは38チームで、そのうち12チームが予選に進出したそうです。

7月12日以降: 開発第一段

通ったからにはベストを尽くすしかありません。 通知を受けた翌日から開発が始まりました。 ……そして、少ししてまた停滞しました。いや、本業が忙しくて……。

このときは、Claude Codeにすべてを書いてもらうバイブコーディングに挑戦しました。 要件定義のドキュメントを丁寧に用意して、それを元にkintoneアプリとChrome拡張機能の両方のコードをすべて書いてもらおうとしたのです。

しかし、これはうまくいきませんでした。 一番最初のプロトタイプはそれらしくできたのですが、kintone固有の実装や暗号の処理など、マイナーな部分でハルシネーションが多発してしまいました。 全体としての設計もイケていないものになっていたので、バグを直そうとして新たなバグを生むループから抜け出せなくなってしまいました。

完全なバイブコーディングは早々に諦めて、ほぼすべてのコードを書き直しました。 ここからしばらくは人力中心の開発が続きます。

7月28日: 発表概要提出&メンバー登録

書類審査通過の連絡から2週間後、発表概要とメンバー登録の締め切りが来ました。 この時点でもアプリはざっくりとしかできておらず、発表資料はまったくの未着手でした。

メンバーについては元々一人で出るつもりだったので問題ないのですが、発表概要は少し困りました。 なにせ、最終的にどんなものができるのか、どんな演出で発表するのか何も決まっていなかったのですから。 しかたがないので、雰囲気で発表概要を書いて提出しました。

このときの発表概要は以下のようにしました。

弊社では、kintoneアプリの作成には「kintoneアプリ申請」を貰うルールにしています。
ある日、アプリ名「Google Authenticator」を作ってほしいという申請が。
そんなものをkintoneで作っちゃったら、社用スマホがない社員でも使えちゃうし、特権アカウントの共有も簡単になっちゃうし、後任への引き継ぎも楽になっちゃうし、……あれ、これってもしかして……便利?

発表タイトルが「『アプリ』を作ってみた」なのに発表内でほとんど「アプリ」というワードに触れられていないのは、このときにタイトルだけ先に決めたからです。 とはいえ予選でそれなりに好評だったので、本戦もそのままのタイトルで行くことにしました。

8月: 開発第二段

私にとっての救いは、8月にはお盆休みがあったことでした。 一週間の休みを使って全力でアプリと発表資料を作り、なんとか形にすることができました。

このデスマーチのような開発期間中に、後述するClaude Codeとの分業制が確立されました。 ここで見付けた最適解は、1) kintoneアプリ、2) Chrome拡張機能、3) 共通パーツ、という3つの部分にわけて、1) kintoneアプリと3) 共通パーツを人力で作り、2) Chrome拡張機能はClaude Codeに任せる、というものでした。 こうすることでkintoneアプリの設計やUIがAIにとってのお手本となり、設計が破綻するリスクや想定しない挙動になるリスクを抑えることができました。

アプリと平行して、予選用の発表資料も作成しました。 予選の資料はGoogleスライドを使い、kintoneのスクリーンショットを背景として使うことでkintone風のデザインに仕上げました。 また、審査員がCybozuの社員であることを考えて、ITリテラシーがやや高い人をターゲットに置きました。

本当はこの時点でスマホ版も完成させたかったのですが、間に合いませんでした。 発表時間が本戦より1分短いことを利用して「スマホからも使いたい」→「じゃあ、やってみよう。」→「時間切れ」→「続きは本戦で」という演出にしました。 個人的には、これはこれで面白い演出だったのでは、と思っています。

予選発表資料から抜粋。

8月22日: 予選当日

ついに当日。Cybozuの日本橋オフィスの会場とオンライン配信のハイブリッド形式で予選会が開催されました。

予選会で発表している志太の様子。壇上で話しながらスクリーンを指差している。

当日は午前中に説明とリハーサル、午後に予選本番、というスケジュールでした。

午前中の説明の中で「終了1分前に効果音が鳴る」という説明がありました。しかもこの効果音が結構大きい。 私の発表では1分前くらいで一番盛り上がっている想定だったので、そのまま行くとスピードが削がれてしまう可能性がありました。

そこで、全体の長さを調整して、スマホ版の紹介が「時間切れ」で中断されるというネタスライドを1分前ジャストに来るようにしました。 こうすることで、効果音を逆手に取ってネタにできると考えたのです。

引き伸ばされることになったまとめパートがやや間延びしてしまいましたが、全体としてはこの機転はうまくいったのではないかと自画自賛しています。

次回があれば、発表全体の長さだけでなく、アナウンスのタイミングや、強制的な打ち切りがあるかどうかは確認しておこうと思います。

予想より長引いたという審査を経て、無事に予選通過の6チームのうちの1つに選んでいただけました。

予選通過チームとCybozuスタッフの集合写真。

この日は終了後に出場者とCybozuスタッフの懇親会があり、さまざまな方と交流することができました。 kintoneを"ローコード"だと思っていない方々(?)と交流できる機会はなかなか無いので、とても楽しい時間になりました。

8月~9月前半: 空白期間

予選通過後、溜め込んでしまった本業の仕事に注力する日々が続きました。 というわけでしばらく進捗が無い期間が続きます。

9月後半: 開発第三段

本戦の発表資料の提出が近付いてきたので、再び開発と資料作成に着手しました。

基本的な方針として、アプリは不足する機能の開発だけに留めて、発表資料の全面的な作り直しに注力することにしました。 というのも、予選の感触から、発表の見せ方が何よりも重要であると考えたからです。

……と、いいながら、実際はアプリのUX改善にもかなり時間を割いてしまいました。 挙動の改善、デザインの調整、安定性の強化、などなど、さまざまなUI/UX改善を行いました。 このあたりの時間配分は完全にUX好きの性分が出てしまった感じがしています。優勝を狙うなら発表に注力するべきだったかもしれません。

発表資料については、予選のものは使わずにすべて作り直しました。 より細かいアニメーションを入れたかったのでGoogleスライドをやめてPowerPointに変更し、発表の流れも変更しています。 結局アニメーションは使いませんでしたが、ローカルにしたことで後述するOBSからも扱いやすくなりました。

本戦では、導入パートの内容と全体の時間配分を大きく変えました。 理由は以下の通りです。

  • 審査員の違い

    • 予選は少数のCybozu社員が審査員なので、
      • 「エンドユーザーあるある」が刺さりやすいと予想して、そこに時間を割きたかった。
    • 本戦は多数の観客が審査員になるので、
      • エンドユーザー本人も多いと予想して、「あるある」は少し控えめにした。
      • 大人数だと挙手などのアクションが映えると判断した。
  • デモの違い

    • 予選資料作成中はまだデモの内容が完成しきっていなかったので、あまり長い時間を取るのはリスクが大きいと判断して短めにした。
    • 本戦ではモバイル版を含めてデモの内容が充実したので、デモに長めの時間を割きたかった。
  • コンテンツの違い

    • 予選ではモバイル版を入れられなかった。
    • 本戦ではモバイル版に加えて配布URLなどのコンテンツも増えた。

また、予選の教訓を元に、事前に時間制限のスタイルを確認させていただきました。 結局尺の調整がうまくできずに1分前のアナウンスを活用することはできませんでしたが、事前に把握できていたことで発表時の余裕は持てました。

10月10日: 発表資料提出

10月10日に発表資料を提出しました。

この時点で、6分の制限時間に対して6分20秒程度の長さになってしまっていました。 資料を削ることも考えたのですが、これ以上削れるところを見付けられなかったので、あとは喋り方で調整することにしました。

10月26日: リハーサル

本番前日に、幕張メッセの実際のステージでリハーサルが行われました。 想像していたより遥かに大きなステージで、2,800人も収容できるとのことでした。

リハーサル中のステージを後ろから写した写真。屏風状に折れ曲がった巨大なスクリーンと、どこまでも続くパイプ椅子が写っている。

会場の裏にある待機場所に着いて、最初に渡されたのはツルハシでした。 「これを持って登場して、ポーズしてください」とのこと。ツルハシで……? 今年のkintone hack SHOW+CASE Unlimitedのテーマがバイオテクノロジーだから、ということだそうなのですが、何故ツルハシなのかは結局わかりませんでした。ふしぎ。

おもちゃのツルハシと、発表者であることを示す「スピーカー」と書かれた名札。左にはACSHUさんの小道具である造花も置いてある。

このリハーサルの中で、1つの大きな問題が発覚しました。 それは、PC端末の設置から本番までが長いというものでした。

大会が始まる前にPCをステージの演台に設置しておいて、発表時には何もせずそのまま発表を始めるという形式だったのです。この設置から発表までの時間は1時間弱にも及びました。

モバイル版のデモを行うためにiPhoneを接続していたのですが、画面を共有しているとバッテリーの消耗が激しく、20分程度が限界でした。 これでは到底1時間の待機時間を乗り切れません。 実際、この日もバッテリー残量が持たなかったために実機を利用したリハーサルは叶いませんでした。

ホテルに戻ってから、ケーブルの繋ぎ方や機材の設定を変更しました。 待機中のiPhoneに電源を供給しておいて、直前につなぎ替えて発表できるようにしたのです。 その場ではなんとかなりましたが、これが連鎖的に後述するトラブルに繋がってしまいました。

この夜にホテルの部屋で行った最後のリハーサルのタイムは、5分59秒。ほぼ完璧な仕上がりでした。

10月27日: 本戦

本戦は翌日の10月27日に開催されました。 会場は満員で、緊張よりもテンションの高まりの方が勝っていました。

以下はPCを準備しているあいだにステージから撮影した写真です。 あまりにも会場が広いせいで観客がよく見えず、そのおかげで緊張が少なくて済みました。

開会前の準備中にステージから撮影した写真。

司会者から「準備はいいですか?」と声がかかり、大きく丸のサインをしてから発表を始めました。 本来ならここでスライドの映像がスクリーンに映し出されるはずだったのですが、映ったのは何故かデスクトップ画面でした。トラブルです。

このトラブルに対応している間は、スクリーンに何が映っているのかも、タイマーは進んでいるのか止まっているのかも、壇上からは確認することができませんでした。 演台から数メートル移動すれば確認できるのですが、PCを触っている状態だと演台や機材に隠れてしまって見られなかったのです。

なんとか手探りで復旧しましたがタイマーは依然として確認できず、自分の感覚を頼りに1分ほど削った短縮版で発表を行いました。 比較的PCから離れられる「まとめ」パートに入ってからタイマーを確認し、全体としては5分35秒程度にまとめることができました。

見所としたかったいくつかのネタやデモを省略してしまったことはとても悔しいですが、混乱なく収められてほっとしています。 次の機会があれば、よりトラブル耐性の高い機材構成やシナリオで挑みたいと思います。

このトラブルの原因については、この記事の後半にあるトラブルの原因の節で考察しています。

私を含めて計6チームの発表があり、観客投票による優勝は西道涼さんに決まりました。 時間制限がある中なのに観客に目を瞑らせたり、ロケットを持って壇上を歩きまわってみたり、あの余裕には勝てそうにありません。 しかもアプリの関連図は実用的に使えそうなのがまたずるい。

西道さんが発表されたカスタマイズについては、kintone芸人さんのYouTubeで解説されていますのでぜひご覧ください。

技術的な話

ここからは、今回のアプリ開発や発表に関する技術的なポイントをご紹介します。 登壇までの流れや苦労にご興味がある方は、この上の「応募~本戦まで」の節からお読みください。

アプリについて

ワンタイムパスワードの生成

今回のアプリのキモであるワンタイムパスワードの生成は、RFC 4226RFC 6238に基づいて実装しました。 これは、ワンタイムパスワードを生成するときのアルゴリズムを定義したRFCです。

細かい解説は省きますが、基本的には事前に共有したシークレットをキーとして、現在の時刻やカウンタなどの値のHMACを計算し、その一部を切り出して数字を生成する仕組みになっています。 かなりシンプルなアルゴリズムなので、Web Crypto APIだけを使って実装することができています。

事前に共有するシークレットや桁数などは、otpauth://というURLスキームで表現され、QRコードとして共有されます。 このURLスキームの標準化はされていないようなのですが、ほとんどのアプリではotpauth://totp/{issuer}:{account}?secret={secret}&issuer={issuer}&digits={digits}&period={period}&algorithm={algorithm}のような形式が使われているようです。 この形式については、Google AuthenticatorのKey Uri Formatというドキュメントが参考になります。

kintone Authenticatorでは、jsQRというライブラリを用いてQRコードを読み取って、OTP Auth URIを解析し、それを元にWeb Crypto APIでワンタイムパスワードを生成しています。 RFCに準拠した仕様なので、ほとんどすべてのWebサイトやアプリで利用できるはずです。

ワンタイムパスワードの生成について詳しく知りたい場合は、以下の記事が参考になります。今回の実装でも参考にさせていただきました。
JavaScript で HOTP および TOTP を計算する #GoogleAuthenticator - Qiita

セキュリティの考慮

今回のアプリのもう1つの大きなポイントは、セキュリティの考慮です。

ワンタイムパスワードのためのシークレットは非常に重要な情報なので、通常はend-to-endで暗号化して保存するべきだと考えられます。 しかし一方で、あまり強固に守りすぎてしまうと、使い勝手が悪くなることも考えられました。 具体的には、以下のようなトレードオフが存在します。

暗号化して保存する場合平文で保存する場合
保存するときユーザーに決めてもらったパスコードで暗号化して保存する。平文のまま保存する。
表示するときユーザーにパスコードを入力してもらい、復号してから表示する。そのまま表示する。
安全性の担保kintoneのアクセス権限管理
パスコードによる暗号化
kintoneのアクセス権限管理のみ
メリットkintoneのレコードが漏洩してもパスコードが分からなければ安全。kintoneの柔軟な共有範囲設定やCSVエクスポート・インポートを最大限に活用できる。
デメリット部内と課内など、共有範囲ごとにパスコードを管理する必要があり運用が煩雑。
異動や退職などがあると全レコードのパスコードを変えなくてはならない。
kintoneのアクセス権限設定を誤ったときやkintone自体が侵害されたときに無力。
管理者権限を持つユーザーからは常にすべてのレコードを見られてしまうリスクがある。

上記のトレードオフを考えていると、そもそものベストシナリオである「1人1つのアカウントとスマートフォンを持ち、それぞれが自分の端末でワンタイムパスワードを管理・利用する」から大きく外れてしまっていることに気付かされます。 それぞれが自分のアカウントを持って各自で管理すれば良いのに、なぜわざわざkintoneを使うのでしょうか?

私が今回のアプリで解決したかったのは、「どうしても共有のアカウントを管理しなくてはならない」場面です。 複数アカウントの発行に対応していないサービスや、共通のルートアカウントなどが存在するサービスなどがこれに該当します。

企業の情報システム部門ではこういったアカウントが多数になり、なおかつ複数のチームで共有されることも珍しくありません。 こういった場面ですべてのレコードにパスコードを設定して管理させると、せっかくのパスワード管理アプリの意味が無くなってしまいます。 リアルな運用の現場を考えると、結局全員が知っている共有のパスコードが設定されてしまい、暗号化の意味が無くなってしまうことも考えられます。

そういうわけで、今回は平文での保存を基本として、必要に応じて一部のレコードだけを暗号化して保存できるようにしました。

レコード保存時に表示される「暗号化パスコード」という欄にパスコードを入力してから保存すると、そのレコードのユーザー名/パスワード/ワンタイムパスワードの情報が暗号化されて保存されます。 表示するときには同じパスコードを入力する必要がありますが、パスコードはインメモリでキャッシュされるので使い勝手の低下は最小限に抑えられています。

Reactを使ったkintoneネイティブ要素の上書き

今回作ったカスタマイズは、基本的にはアップデートの影響を受けづらいように設計してありますが、いくつか例外があります。 レコード一覧画面で検索したときに「1 - 20 (XX件中)」といった表示が検索結果の数に応じて書き変わる機能や、モバイル版でレコードを作成するときに「キャンセル」ボタンを押したときの挙動などがそれに該当します。

これらはkintoneネイティブのUI要素であり、カスタマイズ用のスペースに表示されているReactのDOMツリーの外側に存在しています。 こういった外側の要素をReactの中から書き換えて制御するために、DOMを直接操作する方法と、ReactのcreatePortal機能を使う方法の2種類を使い分けています。

このタイプのカスタマイズはアップデートによって動作しなくなるリスクが高いので、対象要素が見つからなくても動作自体は継続できるようにしてあります。

リスクの大きなカスタマイズではありますが、カスタマイズ部分とそれ以外の部分での差を吸収してあげることで一貫したUXを提供できるので、必要に応じて活用すると良さそうです。

開発について

Claude Codeとの役割分担

前述の開発第二段でも書いた通り、今回の開発ではClaude Codeと分業するような形で開発を進めました。 具体的には、自分はkintoneアプリのカスタマイズに注力して、それをChrome拡張機能に移植する作業はAIに担当してもらうような形を取りました。

初期の開発の時点では、ドキュメントを用意してすべてをClaude Codeに書いてもらう形を試みましたが、これはうまくいきませんでした。 そもそもの一発目をあまりイケていない設計で作ってしまい、そこにあるバグを直させようとすると自分のコードに混乱して新たなバグを作ってしまう、というループに陥ってしまったのです。

今回作ったアプリはkintoneのPC版とモバイル版、そしてChrome拡張機能という3つの動作環境があります。 それぞれは同じ機能を似たようなUIで提供しているのですが、UXを最適化するためにそれぞれ少しずつ異なる仕様になっています。

そこで、人力で実装したPC版を見せて「これを参考に」とAIに指示して作らせる形にしました。 体感としては、PC版は90%が人力、モバイル版は50%、Chrome拡張機能は5%くらいが人力のイメージです。 こうすることで、AIが設計を破綻させるリスクを最小限に抑えつつ、ドキュメントを書く手間も無くしつつ、バグの少ないコードを生成してもらうことができました。

この体制を守るために、以下のようなディレクトリ構成を採用しています。

  • src/
    • lib/ kintone/Chrome共通で使うコード。50%くらい人力。
    • components/ 共通で使うReactコンポーネント。50%くらい人力。
    • kintone/
      • lib/ kintone内でしか使わないコード。90%人力。
      • desktop/ PC版のコード。90%人力。
      • mobile/ モバイル版のコード。50%人力。
    • chrome/ Chrome拡張機能のコード。ほぼ自動生成。

このディレクトリ構成ルールを無視されてしまうことも多かったのですが、これだけはマイクロマネジメントして徹底させるようにしました。 逆に、UI関連のコードなどsrc/chrome/以下に閉じたコードはほぼ任せきりにしましたが、大きなバグは発生しませんでした。 ロジックをやらせるとバグが多くなったのですが、UI関連は比較的安定するようです。あるいは、UIのバグは見つけやすくて直しやすいということもあるかもしれません。

もう1つの工夫として、ユニットテストの活用があります。 ユニットテストがあることでAIは自分が作ったバグを認識できるようになるので、何か書かせるときは必ずセットでテストを書くようにとCLAUDE.mdで指定してあります。 このテストは人力ではメンテしておらず、何なら中身を確認すらしていないのですが、それでもバグの検出にかなり役に立ちました。

GitHub Copilotの活用

Claude Codeのほかに、GitHub Copilotも活用しました。 コード補完としてのCopilotもそうなのですが、それ以上にGitHub上でPull Request (PR)を作成してもらったり、レビューしてもらったりする機能が非常に便利でした。

今回の場合は、とくに以下のような使い方が役に立ちました。

  • Claude CodeにコードとPRを書かせて、GitHub Copilotにレビューをさせる。
    AIが書いたコードを別のAIにレビューさせることで、バグを検知しやすくなりました。 また、単純にレビューの手間を削減することもできました。

    ClaudeとCopilot (GPT)は別のモデルなので、Claudeが見逃すバグをCopilotが見つけてくれることが多い、ような気がします。 単純にコンテキストが違うことも影響しているのかもしれません。

  • 仕事の合間にバグ修正や改善をやらせる。
    GitHub上で動作するCopilotは手元の環境を使わないので、ながら作業が非常にやりやすいです。 会議の前にIssueを立ててCopilotをアサインしておき、会議が終わったらレビューしてマージする、というような流れは忙しい中での開発に非常にマッチしていました。

  • Claude Code (+Codex)にバグを見つけてIssueを書かせて、GitHub Copilotに並列で対応させる。
    バグ修正のより高度な(?)使い方の例です。 本戦が近くなってきたときに、Claude CodeとCodexにコードを読ませて大量のIssueを書かせて、それらすべてにGitHub Copilotをアサインして修正させるという作業を行いました。 ほとんどが勘違いか軽微なバグだったのですが、一気にレビューと修正をこなせたのは安心感に繋がりました。

Claude CodeやCodexは手元で高度な作業ができる点が、GitHub Copilotはブラウザ1つで完結する点が、それぞれの強みになっています。 これらをうまく組み合わせることで、かなり効率的に開発を進めることができそうです。

kintone/customize-uploaderの活用

kintoneアプリを毎回ビルドして手動でデプロイするのは面倒なので、customize-uploaderを使ってnpm run build && npm run deploy:kintoneというコマンド1つでビルドからデプロイまでを完結できるようにしました。 このときのデプロイ先は開発者ライセンスをお借りして用意した開発専用のアプリになっています。 devブランチにpushしたら自動デプロイさせることも考えたのですが、手元で迅速にデプロイしたかったのでコマンドでデプロイする方式をメインで使うようにしました。

さらに、mainブランチにpushすると、GitHub Actionsが「本番環境」と呼んでいるアプリにデプロイしてくれるようにしました。 このアプリはシダックスのkintone本番環境に用意したアプリで、社内のメンバーに見てもらってフィードバックを貰うために作ったものです。 大会が終わったので、今後は本当に本番環境として実運用を始めようと思っています。

GitHub Actionsによる自動デプロイには、macrat/upload-kintone-customize-actionという自作のカスタムアクションを使いました。 このアクションの使い方については先日公開した「GitHub Actionsからkintoneカスタマイズのコードを自動アップロードする」という記事をご覧ください。

リリースの自動化

せっかくなので? リリース作業も自動化してみました。 発表に直接寄与するものではありませんが、大規模開発の事例を紹介されていたACSHUさんの発表に触発されて本格的なCI/CDをやってみたくなったのでやってみました。

具体的には、v1.0.0のようなタグをpushすると、GitHub Actionsが自動的にリリースを作成してくれるようになっています。 リリースの本文はタグのアノテーションから作り、添付ファイルにはビルド済みのJavaScriptファイルやChrome拡張機能のzipファイル、そしてkintoneアプリのテンプレートファイルなどを含めるようにしてあります。

この自動化には、macrat/download-kintone-template-actionというカスタムアクションを作って使用しました。 これについても「GitHub Actionsでkintoneアプリのテンプレートをダウンロードする」という記事を書いていますので、よろしければご覧ください。

発表について

本戦発表画面の構成

本戦の発表では、PCの画面だけでなくiPhoneの画面もスクリーンに投影しました。 PowerPointとブラウザ、そしてiPhoneの画面を投影するために、OBS Studioという配信用のソフトを利用しました。

スマホとPCの接続は、Lightning-HDMI変換アダプタと、HDMIの映像をWebカメラとしてPCに取り込むビデオキャプチャを利用しました。 最初の接続がやや不安定でしたが、一度繋がればあとは安定して取り込むことができていました。

OBSには以下のシーン(投影する画面)を用意して、それぞれを自動シーンスイッチャという機能で切り替えるようにしました。 この自動シーンスイッチャを使うことで、アクティブウィンドウを切り替えるだけでOBSのシーンを切り替えられるので、発表中にOBSに触れずに済みました。

シーン内容表示する条件
スライドPowerPointのウィンドウキャプチャPowerPointにフォーカスを移したとき
PCデモPC画面全体の画面キャプチャGoogle Chromeにフォーカスを移したとき
スマホデモiPhoneの映像 + Microsoft Edgeブラウザの画面キャプチャMicrosoft Edgeにフォーカスを移したとき

OBSを利用することで余計な要素を表示せず、クリーンな画面を投影できました。 しかし一方で、PC画面とスクリーンに投影される画面が別々になってしまい、トラブルの要因になってしまいました。 このあたりの画面の作り方は改善の余地がありそうです。

トラブルの原因

前述の通り、本戦ではスクリーンに映像が映らなくなるトラブルが発生してしまいました。 どうやら、このトラブルの原因は以下のようなものだったようです。

本戦の発表では、以下のような2つの仮想デスクトップを用意していました。

  • 仮想デスクトップ1: 発表に使うPowerPointやブラウザ、OBSなどを配置。
  • 仮想デスクトップ2: チェックリストや、トラブル対応用のバックアップ資料などを配置。

発表中は何ごともなければ仮想デスクトップ1のみを使うので、OBSからの映像を表示する全画面プロジェクター(OBSの出力映像が出るウィンドウ)も仮想デスクトップ1に配置されるはずでした。 ところが、何らかの理由で全画面プロジェクターが仮想デスクトップ2に移動してしまっていたようです。

本番前のPC接続中に確認できていれば良かったのですが、この時はHDMIから何が出力されているのかを確認する術が無かったので、「おそらくこれで大丈夫」という勘だけで設定を行いました。 そういうわけで、実際に出力映像を確認できたのは、発表が始まってスクリーンに表示されてからになってしまいました。

PC画面と投影画面を別々にする構成はトラブルの原因になりやすそうなので、会場の返しモニタだけに頼らず、手元でも確認できる術を用意しておくべきだったかもしれません。

まとめ

最初はまさに「じゃあ、やってみよう」という軽い気持ちで挑戦したkintone hackでしたが、気付けば本気でカスタマイズに取り組み、本気で発表に取り組んでいました。その結果としてあれだけの大舞台でお話しする機会をいただけたことはとても貴重な経験になりました。 もしも良いネタがあれば、来年以降も再び挑戦してみたいと思っています。

また、今回開発したアプリは社内の業務で実際に活用できそうなので、今後も開発を継続する予定です。 更新はGitHub上でも引き続き公開する予定なので、興味のある方はぜひブックマークやスターの登録をお願いします。

今回のkintone hackやこの記事を通じて、kintoneのカスタマイズや、kintone hackへの挑戦に興味を持っていただけたら幸いです。

kintone hack 2025 本戦の最後のワンシーン。「kintone hack」「SHIDAX」という大きな文字と、「じゃあ、やってみよう」というやや小さな文字が巨大なスクリーンいっぱいに映し出されており、その手前で志太がスライドを指している。

掲載していただいた記事