【コピペで10分】プログラミング知識ゼロでもAIで「社内専用Webアプリ」を自作する方法

Gemini

こんにちは!『クロブロ』運営者のクロウル(藤井貴司)です。

「会社の備品管理、スプレッドシートに直接入力してもらうと、数式を壊されたりデータがズレたりしてイライラする…」
「専用の入力画面(Webアプリ)が欲しいけれど、開発を外注する予算もプログラミングの知識もない…」

このような悩みを抱えていませんか?

結論から言うと、無料のAI(Gemini)Googleスプレッドシートを組み合わせれば、プログラミング知識ゼロでも、たった10分で社内専用の「備品登録Webアプリ」を自作できます!

今回の自動化は、よくある「手動でスプレッドシートを準備する」ような面倒な手順は使いません。

「スプレッドシートファイル自体の自動生成」もAI(プログラム)に丸投げする、一歩進んだ本格的な自動化ツールを作ります。

この記事を読めば、AIと対話しながら実用的なシステムを作り上げ、業務自動化の大きな一歩を踏み出すことができます。ぜひ最後まで一緒に進めてみましょう!

【重要】Geminiを使うときの大原則(セキュリティ上の注意)

今回使用する無料のWeb版Geminiをはじめ、多くの生成AIでは、入力したデータがAIの学習データとして使用される可能性があります。

そのため、社外秘の機密情報や、顧客・社員の個人情報(氏名、メールアドレス、住所など)は絶対にプロンプトに入力しないでください。

※今回の備品管理アプリのように、一般的な項目名(「管理番号」や「保管場所」など)で開発を進めたり、テスト用のダミーデータを使用したりする分にはセキュリティ上の問題は一切ありません。

今回作成する「簡易備品登録システム」の完成イメージ

今回の記事では、最初から完成されたコードをただコピペするのではなく、「AI(Gemini)と対話しながらツールを組み立てるプロセス」を体験していただきます。

同じプロンプトを入力しても、AIの出力(回答)は確率的にその都度変動(ゆらぎ)します。もし手元のAIが違うコードを出して動かなかった場合は、記事にある「動作確認済みの完成コード」をそのままコピペして使用してください。

準備するもの

  • Googleアカウント(普段お使いの無料アカウントでOK)
  • Googleドライブの保存用フォルダ
    • スプレッドシートを保存したいフォルダ(フォルダ名:備品管理など)をGoogleドライブ上に1つ作成しておいてください。

AIと対話して「備品管理」を設計しよう(2ステップ)

今回の記事では、最初から完成されたコードをただコピペするのではなく、「AI(Gemini)と対話しながらツールを組み立てるプロセス」を体験していただきます。

同じプロンプトを入力しても、AIの出力(回答)は確率的にその都度変動(ゆらぎ)します。もし手元のAIが違うコードを出して動かなかった場合は、記事の後半にある「動作確認済みの完成コード」をそのままコピペして使用してください。

【ステップ1】スプレッドシートの項目(列名)をAIに提案してもらう

まずは、無料のWeb版Geminiを開き、以下のプロンプトを送信して、備品管理に必要な項目(列名)をAIに考えてもらいましょう。

送信するプロンプト(ステップ1)

Googleスプレッドシートを使って、社内の「簡易的な備品登録・管理」を始めたいです。
スプレッドシートの1行目に項目(列名)として並べるべき、おすすめの項目を5つ程度提案してください。
各項目について、なぜそれが必要なのかの簡単な理由も添えてください。

Geminiからの回答(要約)

プロンプトを入力すると、Geminiは以下の5つの項目を提案してくれました。

  1. 管理番号(備品ID)(個体を一意に特定するため)
  2. 備品名(メーカーや型番などを分かりやすく記載するため)
  3. 保管場所(どこにあるかの迷子をなくすため)
  4. ステータス(保管中、使用中、故障中などを把握するため)
  5. 使用者(今誰が持っているかを明確にするため)

さらに、Geminiはワンポイントアドバイスとして、「6つ目の項目として『最終更新日』を入れておくと情報の信頼性が高まりますよ」という提案もしてくれました。

このAIからの素敵な提案(最終更新日の自動記録)を採用して、次のステップでアプリのコードを作ってもらいましょう!

【ステップ2】AIのアドバイスを取り入れて、Webアプリを作ってもらう(Canvasの活用)

ステップ1の回答画面から、コードを生成させます。
Web版Geminiでは、プロンプト入力欄の左側にある「+」ボタンをクリックし、メニューから「Canvas(キャンバス)」を選択して新規チャットを開始することで、コード専用の表示画面(エディタ)で綺麗にファイルを出力してくれます。

※上記の画像を参考に、Googleドライブの保存先フォルダのURLから「フォルダID(folders/の後ろの英数字)」をあらかじめコピーしておいてください。

チャットでCanvas選択したら、以下のプロンプトを送信します。

送信するプロンプト(ステップ2)

もし皆さんのステップ1の回答で、AIが「購入日」や「価格」など別の項目を提案してきた場合は、以下のプロンプトの [管理番号、備品名、保管場所、ステータス、使用者] の部分を、ご自身の項目名に書き換えてから送信してください。

ご提案いただいた「最終更新日(タイムスタンプ)」の自動記録機能、とても素晴らしいのでぜひ追加したいです!

では、先ほどの5項目[管理番号、備品名、保管場所、ステータス、使用者]に自動で記録する[最終更新日]を加えた計6項目で、HTMLフォームとGoogle Apps Script (GAS) のコードを作成してください。

### 要件
1. Web UI(HTML)の入力項目は、ユーザーの手間を減らすため以下の5項目のみとする:
   - 管理番号(テキスト入力、必須)
   - 備品名(テキスト入力、必須)
   - 保管場所(テキスト入力、必須)
   - ステータス(ドロップダウン、「保管中(貸出可)」「使用中」「故障中(修理待ち)」「廃棄済」から選択、必須)
   - 使用者(テキスト入力、必須)
2. 登録ボタンを押すと、GAS側で送信時の日時(現在時刻)を「最終更新日」として自動取得し、データに追加する。
3. 登録されたデータは、Googleドライブ内の「指定したフォルダ」に保存されたスプレッドシート(ファイル名:簡易備品管理シート)の末尾の行に書き込まれるようにする。
   - スプレッドシートが存在しない場合:GAS側で新規にスプレッドシートファイルを作成し、1行目にヘッダーとして「A: 最終更新日」「B: 管理番号」「C: 備品名」「D: 保管場所」「E: ステータス」「F: 使用者」を自動構築した上で、データを2行目に書き込む。
   - すでに同名のスプレッドシートが存在する場合:そのファイルを開き、末尾の行にデータを追記する。
   - 保存先となる「GoogleドライブのフォルダID」は、GASコード内の定数(例:`const FOLDER_ID = 'xxxx';`)で読者が簡単に書き換えられるように設計する。
4. HTMLのデザインは、スマートで洗練されたモダンなデザイン(グラデーションやカード風のレイアウト、ボタンのホバーエフェクトなど)にしてください。Google Fontsなどを使用してフォントも綺麗に整えてください。
5. 登録が完了したら「登録が完了しました!」と表示し、フォームをリセットしてください。エラーが発生した場合はエラーメッセージを表示してください。
6. GAS側の関数は `addNewItem(item)` とし、HTML側からは `google.script.run` を使って呼び出すようにしてください。

この要件を満たす `Code.gs` と `index.html` のコードを、Canvas上にそれぞれファイル(またはタブ)を分けて出力してください。

これで、GeminiのCanvas上にシステムを動かすための2つのファイル(HTMLファイルとJavaScriptファイル)が生成されます。

動作確認済みの完成コード(コピペ用)

もしGeminiの出力が崩れてしまったり、うまく動かなかったりした場合は、以下の検証済みのコードをそのまま使用してください。

① Code.gs (Google Apps Script側)

【コピペ用】GASコード全文はこちら(クリックで展開)
/**
 * 簡易備品管理シート 保存用GASスクリプト
 */

// 保存先となるGoogleドライブのフォルダIDを指定してください。
// Googleドライブで対象フォルダを開いた際のURLの最後(例: .../folders/1a2b3c4d5e... の部分)を設定します。
const FOLDER_ID = 'YOUR_FOLDER_ID_HERE';

/**
 * Webアプリケーションとしてアクセスされた際に、HTMLフォームを表示する関数
 */
function doGet() {
  return HtmlService.createTemplateFromFile('index')
    .evaluate()
    .setTitle('簡易備品管理システム')
    .addMetaTag('viewport', 'width=device-width, initial-scale=1.0')
    .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}

/**
 * フォームから送信された備品データをスプレッドシートに追記する関数
 * @param {Object} item フォームから送信された備品データ
 * @return {Object} 処理結果ステータス
 */
function addNewItem(item) {
  try {
    if (!FOLDER_ID || FOLDER_ID === 'YOUR_FOLDER_ID_HERE') {
      throw new Error('Google Apps Script内の FOLDER_ID が正しく設定されていません。');
    }

    const folder = DriveApp.getFolderById(FOLDER_ID);
    const fileName = '簡易備品管理シート';
    const files = folder.getFilesByName(fileName);
    
    let ss;
    let isNew = false;

    // 同名スプレッドシートの存在チェック
    if (files.hasNext()) {
      const file = files.next();
      ss = SpreadsheetApp.open(file);
    } else {
      // 存在しない場合は新規作成して指定フォルダへ移動
      ss = SpreadsheetApp.create(fileName);
      const file = DriveApp.getFileById(ss.getId());
      file.moveTo(folder);
      isNew = true;
    }

    const sheet = ss.getSheets()[0];

    // 新規作成時は1行目にヘッダーを書き込む
    if (isNew) {
      sheet.appendRow([
        '最終更新日',
        '管理番号',
        '備品名',
        '保管場所',
        'ステータス',
        '使用者'
      ]);
      // ヘッダー行を太字にし、背景に薄いグレーを設定
      const headerRange = sheet.getRange('A1:F1');
      headerRange.setFontWeight('bold');
      headerRange.setBackground('#f3f4f6');
      sheet.setFrozenRows(1); // 1行目を固定
    }

    // 日本標準時 (JST) での現在時刻のフォーマット
    const timestamp = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy-MM-dd HH:mm:ss');

    // データの書き込み(末尾に追記)
    sheet.appendRow([
      timestamp,
      item.id,
      item.name,
      item.location,
      item.status,
      item.user
    ]);

    return {
      success: true,
      message: 'スプレッドシートに正常に登録されました。',
      spreadsheetUrl: ss.getUrl()
    };

  } catch (error) {
    Logger.log('Error: ' + error.toString());
    return {
      success: false,
      message: error.toString()
    };
  }
}

② index.html (Web画面 UI側)

【コピー用】index.htmlのコード全文はこちら
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>簡易備品登録システム</title>
  <!-- Tailwind CSS CDN -->
  <script src="https://cdn.tailwindcss.com"></script>
  <!-- Google Fonts (Inter & Noto Sans JP) -->
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Noto+Sans+JP:wght@400;500;700&display=swap" rel="stylesheet">
  <style>
    body {
      font-family: 'Inter', 'Noto Sans JP', sans-serif;
    }
  </style>
</head>
<body class="bg-slate-50 min-h-screen flex items-center justify-center p-4 sm:p-6 md:p-8">

  <!-- メインカードコンテナ -->
  <div class="w-full max-w-lg bg-white rounded-2xl shadow-xl border border-slate-100 overflow-hidden transform transition-all duration-300 hover:shadow-2xl">
    
    <!-- ヘッダーデザイン -->
    <div class="bg-gradient-to-r from-indigo-600 to-violet-600 px-6 py-8 text-white relative overflow-hidden">
      <div class="absolute -right-10 -top-10 w-36 h-36 bg-white opacity-10 rounded-full"></div>
      <div class="absolute -left-10 -bottom-10 w-28 h-28 bg-white opacity-10 rounded-full"></div>
      
      <div class="relative z-10">
        <span class="inline-block px-3 py-1 bg-white/20 rounded-full text-xs font-semibold tracking-wider uppercase mb-2">Internal Tool</span>
        <h1 class="text-2xl font-bold tracking-tight">簡易備品登録・管理</h1>
        <p class="text-indigo-100 text-sm mt-1">フォームから入力したデータがスプレッドシートに即時追加されます。</p>
      </div>
    </div>

    <!-- フォーム本体 -->
    <form id="itemForm" onsubmit="submitForm(event)" class="p-6 space-y-5">
      
      <!-- 管理番号 -->
      <div>
        <label for="id" class="block text-sm font-semibold text-slate-700 mb-1">
          管理番号 <span class="text-rose-500">*</span>
        </label>
        <input 
          type="text" 
          id="id" 
          name="id" 
          required 
          placeholder="例: A-001, PC-105"
          class="w-full px-4 py-2.5 border border-slate-200 rounded-lg text-slate-800 placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition duration-150"
        >
      </div>

      <!-- 備品名 -->
      <div>
        <label for="name" class="block text-sm font-semibold text-slate-700 mb-1">
          備品名 <span class="text-rose-500">*</span>
        </label>
        <input 
          type="text" 
          id="name" 
          name="name" 
          required 
          placeholder="例: 液晶モニター 24インチ"
          class="w-full px-4 py-2.5 border border-slate-200 rounded-lg text-slate-800 placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition duration-150"
        >
      </div>

      <!-- 保管場所 -->
      <div>
        <label for="location" class="block text-sm font-semibold text-slate-700 mb-1">
          保管場所 <span class="text-rose-500">*</span>
        </label>
        <input 
          type="text" 
          id="location" 
          name="location" 
          required 
          placeholder="例: 会議室A キャビネット2段目"
          class="w-full px-4 py-2.5 border border-slate-200 rounded-lg text-slate-800 placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition duration-150"
        >
      </div>

      <!-- ステータス -->
      <div>
        <label for="status" class="block text-sm font-semibold text-slate-700 mb-1">
          ステータス <span class="text-rose-500">*</span>
        </label>
        <div class="relative">
          <select 
            id="status" 
            name="status" 
            required
            class="w-full px-4 py-2.5 border border-slate-200 rounded-lg text-slate-800 bg-white focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition duration-150 appearance-none"
          >
            <option value="" disabled selected hidden>ステータスを選択してください</option>
            <option value="保管中(貸出可)">🟢 保管中(貸出可)</option>
            <option value="使用中">🔵 使用中</option>
            <option value="故障中(修理待ち)">🟡 故障中(修理待ち)</option>
            <option value="廃棄済">🔴 廃棄済</option>
          </select>
          <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-4 text-slate-500">
            <svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
              <path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"/>
            </svg>
          </div>
        </div>
      </div>

      <!-- 使用者 -->
      <div>
        <label for="user" class="block text-sm font-semibold text-slate-700 mb-1">
          使用者 / 管理責任者 <span class="text-rose-500">*</span>
        </label>
        <input 
          type="text" 
          id="user" 
          name="user" 
          required 
          placeholder="例: 山田 太郎 (未使用の場合は「共通管理」など)"
          class="w-full px-4 py-2.5 border border-slate-200 rounded-lg text-slate-800 placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition duration-150"
        >
      </div>

      <!-- 送信ボタン -->
      <div class="pt-2">
        <button 
          type="submit" 
          id="submitBtn"
          class="w-full py-3 px-4 bg-gradient-to-r from-indigo-600 to-violet-600 hover:from-indigo-700 hover:to-violet-700 text-white font-semibold rounded-lg shadow-md hover:shadow-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transform active:scale-[0.98] transition-all duration-150 flex items-center justify-center space-x-2"
        >
          <span id="btnText">この内容で登録する</span>
          <svg id="loadingSpinner" class="hidden animate-spin h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
            <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
            <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
          </svg>
        </button>
      </div>
    </form>
  </div>

  <!-- カスタム通知ダイアログ(モーダルUI) -->
  <div id="modalOverlay" class="fixed inset-0 bg-slate-900/40 backdrop-blur-sm z-50 flex items-center justify-center p-4 hidden opacity-0 transition-opacity duration-300">
    <div id="modalCard" class="bg-white rounded-2xl max-w-sm w-full p-6 shadow-2xl border border-slate-100 transform scale-95 transition-transform duration-300 text-center">
      <div id="modalIconContainer" class="mx-auto flex items-center justify-center h-12 w-12 rounded-full mb-4">
        <svg id="iconSuccess" class="h-6 w-6 text-emerald-600 hidden" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
          <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
        </svg>
        <svg id="iconError" class="h-6 w-6 text-rose-600 hidden" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
          <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
        </svg>
      </div>
      
      <h3 id="modalTitle" class="text-lg font-bold text-slate-800 mb-2">タイトル</h3>
      <p id="modalMessage" class="text-sm text-slate-500 mb-6">メッセージがここに入ります。</p>
      
      <button 
        onclick="closeModal()" 
        class="w-full py-2 px-4 bg-slate-800 hover:bg-slate-900 text-white font-medium rounded-lg shadow transition duration-150"
      >
        閉じる
      </button>
    </div>
  </div>

  <script>
    const form = document.getElementById('itemForm');
    const submitBtn = document.getElementById('submitBtn');
    const btnText = document.getElementById('btnText');
    const loadingSpinner = document.getElementById('loadingSpinner');

    const modalOverlay = document.getElementById('modalOverlay');
    const modalCard = document.getElementById('modalCard');
    const modalTitle = document.getElementById('modalTitle');
    const modalMessage = document.getElementById('modalMessage');
    const modalIconContainer = document.getElementById('modalIconContainer');
    const iconSuccess = document.getElementById('iconSuccess');
    const iconError = document.getElementById('iconError');

    function showModal(title, message, isSuccess = true) {
      modalTitle.innerText = title;
      modalMessage.innerText = message;

      if (isSuccess) {
        modalIconContainer.className = "mx-auto flex items-center justify-center h-12 w-12 rounded-full mb-4 bg-emerald-100";
        iconSuccess.classList.remove('hidden');
        iconError.classList.add('hidden');
      } else {
        modalIconContainer.className = "mx-auto flex items-center justify-center h-12 w-12 rounded-full mb-4 bg-rose-100";
        iconSuccess.classList.add('hidden');
        iconError.classList.remove('hidden');
      }

      modalOverlay.classList.remove('hidden');
      setTimeout(() => {
        modalOverlay.classList.remove('opacity-0');
        modalCard.classList.remove('scale-95');
        modalCard.classList.add('scale-100');
      }, 10);
    }

    function closeModal() {
      modalOverlay.classList.add('opacity-0');
      modalCard.classList.remove('scale-100');
      modalCard.classList.add('scale-95');
      setTimeout(() => {
        modalOverlay.classList.add('hidden');
      }, 300);
    }

    function submitForm(event) {
      event.preventDefault();

      submitBtn.disabled = true;
      btnText.classList.add('opacity-50');
      loadingSpinner.classList.remove('hidden');

      const formData = {
        id: document.getElementById('id').value.trim(),
        name: document.getElementById('name').value.trim(),
        location: document.getElementById('location').value.trim(),
        status: document.getElementById('status').value,
        user: document.getElementById('user').value.trim()
      };

      if (typeof google !== 'undefined' && google.script && google.script.run) {
        google.script.run
          .withSuccessHandler(onSuccess)
          .withFailureHandler(onFailure)
          .addNewItem(formData);
      } else {
        console.warn('Google Apps Script の実行環境が検出されませんでした。シミュレーションモードで処理します。');
        setTimeout(() => {
          onSuccess({ success: true, message: '(シミュレーション)登録が完了しました!' });
        }, 1500);
      }
    }

    function onSuccess(response) {
      submitBtn.disabled = false;
      btnText.classList.remove('opacity-50');
      loadingSpinner.classList.add('hidden');

      if (response && response.success) {
        showModal('登録完了', '備品情報が正常に登録されました!', true);
        form.reset();
      } else {
        showModal('登録エラー', 'エラーが発生しました: ' + (response ? response.message : '不詳なエラー'), false);
      }
    }

    function onFailure(error) {
      submitBtn.disabled = false;
      btnText.classList.remove('opacity-50');
      loadingSpinner.classList.add('hidden');
      showModal('サーバーエラー', '通信エラーまたはサーバー側の不具合が発生しました:\n' + error.toString(), false);
    }
  </script>
</body>
</html>

Google Apps Script(GAS)の設定手順

コードが手に入ったら、実際にGASを設定していきましょう。
スプレッドシート自体もGASで作るので、「スプレッドシートからスクリプトを開く」のではなく、「まっさらな状態からGASを立ち上げる」という手順で進めます。

1. Google Apps Script にアクセスし、左上の 「新しいプロジェクト」 をクリックします。

2.もともと書かれている コード.gs の中身をすべて消し、上記の Code.gs を貼り付けます。

3.コードの最上部にある const FOLDER_ID = 'YOUR_FOLDER_ID_HERE'; の部分を、先ほど事前準備でコピーした「ご自身のフォルダID」に書き換えて、保存ボタン(フロッピーマーク)をクリックします。

4.エディタ左側のファイルリストの上にある 「+」 > 「HTML」 をクリックし、ファイル名に index(拡張子の .html は自動で付くので index のみ)と入力してEnterを押します。

5.作成された index.html の中身をすべて消し、上記の index.html のコードを貼り付けて保存します。

Webアプリとしてのデプロイ(世界への公開)

設定したコードを、世界中のブラウザからアクセスできるWebアプリとして公開(デプロイ)します。

1.エディタ右上にある 「デプロイ」 > 「新しいデプロイ」 をクリックします。

2.左側の歯車マークをクリックして 「ウェブアプリ」 を選択し、以下の通りに設定して「デプロイ」をクリックします。

  • 次のユーザーとして実行: 「自分(ご自身のGoogleアカウント)」
  • アクセスできるユーザー: 「全員」

自動化の成長ステップ!「セキュリティ警告」の突破

デプロイボタンを押すと、初回のみ「アクセス承認」の画面が表示されます。
今回はGASがGoogleドライブ上にファイルを自動作成する(アプローチBの仕様)ため、Googleから少し怖い見た目の警告画面が表示されます。

これはバグでもウイルスでもありません。自動化ツールが自分のデータを操作することを許可するための、Googleの重要なセキュリティ機能(確認プロセス)です。
高度な自動化を使いこなすための「成長ステップ」ですので、以下の手順で冷静に突破しましょう!

1.デプロイ中に表示される 「アクセスを承認」 ボタンをクリックします。

2.さらに表示された 「無題のプロジェクト(安全ではないページ)に移動」 リンクをクリックします。

4.次に、このアプリがGoogleドライブへのアクセスを要求している画面が出るので、内容を確認し、一番下までスクロールして 「許可(Continue)」 をクリックします。

5.デプロイが完了し、画面上に 「ウェブアプリのURL」 が発行されます。このURLをコピーして控えておいてください。

いざ動作テスト!自動ファイル作成を体験する

それでは、発行されたURLを使ってアプリの動作確認をしてみましょう。

1.コピーしたウェブアプリのURLをブラウザの新しいタブで開きます。スマートな備品登録フォームが表示されます。

2.「管理番号」「備品名」「保管場所」などを適当に入力し、ステータスを選択して 「この内容で登録する」 をクリックします。

3.送信が完了すると、画面上に「登録完了」が表示されます!

4.指定したGoogleドライブのフォルダを開いてみましょう。「簡易備品管理シート」というスプレッドシートが自動で作成されています!

5.そのスプレッドシートを開くと、1行目に項目ヘッダー(最終更新日、管理番号など)が自動構築され、その下に今入力したデータが日本時間のタイムスタンプ付きで綺麗に登録されています。

次回以降データを送信すると、このファイルを自動で見つけて、末尾の行にどんどんデータが追記されていきます。

コラム:セキュリティやエラーが不安なときはAIに相談しよう

「デプロイ作業中に、記事と全然違うエラー画面が出て進めなくなった…」
「便利なのは分かったけれど、本当に会社のフォルダへのアクセスを許可して安全なのかな?」

そんなときは、その画面のスクリーンショットを撮影して、そのままGeminiに質問してみるのが一番の近道です!

例えば、Geminiに以下のように質問してみてください。

  • エラーで進めない場合: エラー画面のスクショを貼り付けて、「この記事(URL)の通りにGASをデプロイしようとしたらこの画面が出ました。どう操作すれば進めますか?」と聞く。
  • 安全性を確かめたい場合: GASコードを貼り付けて、「このコードは、指定したGoogleドライブのフォルダ以外に勝手にファイルを作ったり、外部にデータを送信したりするセキュリティ上のリスクはありますか?解説してください」と聞く。

AIをただの「コード生成機」として使うだけでなく、「困ったときの専属アドバイザー」として活用することで、自動化開発のスキルは飛躍的に向上します。

まとめ

今回は、無料のWeb版GeminiとGASを使い、フォルダIDを指定するだけでデータベースの構築からデータ保存までを全自動で行う「社内専用Webアプリ」を開発しました。

Googleドライブのアクセス権の承認という、少し身構えるような警告画面を突破する経験をしたことで、あなたはノンプログラマーから「本格的な自動化ツールを作れる人材」へと一歩前進しました!

AIとの対話を取り入れた開発スタイルに慣れていけば、あなたの仕事はどんどん楽になり、無駄な手作業から解放されます。

これからもバックオフィスの皆さんがもっと楽になれるアイデアを発信していきますので、またいつでも『クロブロ』に遊びにきてくださいね!