データサイエンス&Webアプリ開発入門

Google Colaboratory / Pandas / Plotly / PyScript / Cloudflare Pages

氏名:

【ローカル完結型・ブラウザデータサイエンス教材】

コード枠の「📋 コピー」を押すと1タップでコピーできます。Google Colaboratoryで動作を確認したら、各項目の「完了チェック」を押して学習記録をつけていきましょう。数値回答のお題には自動正誤判定システムが組み込まれています。進捗はすべてブラウザ(LocalStorage)に自動保存されます。

第1章

01. 高校生のためのPandas入門 on Google Colaboratory

1. はじめに:PandasとColabって何?

Google Colaboratory (Colab) とは?

Googleが提供している、ブラウザ上でPythonを書いて実行できる無料のWebサービスです。環境設定の苦労がなく、誰でもすぐにデータ分析を始められます。教材のコードをColabのセルに貼り付けて実行していきましょう。

Pandas とは?

Pythonで表形式(Excelのような表データ)を自在に操作するためのデータサイエンス標準ライブラリです。

Pandasのインポート(おまじない)

Colabには最初からPandasが入っています。使うときは短く pd と呼ぶのが世界共通のルールです。

Pandasのインポート
import pandas as pd

2. Pandasの基本:Series(シリーズ)とDataFrame

Pandasには2大データ構造があります。

  • Series(シリーズ): 1次元データ(1つの列)。値にインデックス(ラベル名)を付けられます。
  • DataFrame(データフレーム): 2次元の表データ。複数の列で構成され、Excelのシートと同じ感覚で扱えます。
SeriesとDataFrameの作成
import pandas as pd

# 1. Seriesの作成(果物と価格)
fruits = pd.Series([100, 150, 200, 120], index=['りんご', 'バナナ', 'いちご', 'みかん'])
print("--- Series ---")
print(fruits)

# 2. DataFrameの作成(生徒の成績表)
student_data = {
    '出席番号': [1, 2, 3, 4],
    '名前': ['佐藤', '鈴木', '高橋', '田中'],
    '数学': [85, 92, 78, 88],
    '英語': [76, 88, 95, 82]
}
df = pd.DataFrame(student_data)
print("\n--- DataFrame ---")
display(df)

3. データの読み込みと書き出し

pd.read_csv() でWeb上のURLやローカルのCSVファイルを直接読み込めます。to_csv('ファイル名.csv', index=False) でファイル書き出しも簡単です。

タイタニック号データの読み込み
# Web上のCSVを直接DataFrameに読み込む
csv_url = 'https://raw.githubusercontent.com/pandas-dev/pandas/main/doc/data/titanic.csv'
titanic_df = pd.read_csv(csv_url)

# 先頭5行を表示
display(titanic_df.head())

# 成績データをCSVに出力
df.to_csv('class_scores.csv', index=False)
print("class_scores.csv として保存完了!")

4. まずはデータを観察してみよう

データを手に入れたら、まず全体像をつかむのがデータサイエンティストの第一歩です。

  • shape: 行数と列数(データの大きさ)
  • info(): 各列のデータ型や欠損値の有無
  • describe(): 数値列の平均値、最小値、最大値などの基本統計量
データ観察メソッド
print("--- shape (行数, 列数) ---")
print(titanic_df.shape)

print("\n--- info() ---")
titanic_df.info()

print("\n--- describe() ---")
display(titanic_df.describe())

5. 欲しいデータを自由に取り出す(選択と抽出)

条件に一致する行だけを抜き出すには角カッコ df[条件式] を使います。複数条件は & (AND) や | (OR) を使い、各条件を小カッコ () で囲みます。

条件抽出のコード例
# 1. 18歳未満の乗客
children = titanic_df[titanic_df['Age'] < 18]
print("18歳未満の人数:", len(children))

# 2. 女性(female) かつ 1等客(Pclass=1)
rich_women = titanic_df[(titanic_df['Sex'] == 'female') & (titanic_df['Pclass'] == 1)]
display(rich_women.head())

6. 簡単なデータ加工

新しい列の計算追加や、不要な列の削除(drop(..., axis=1))を試します。

列の追加と削除
# 新しい列の追加 (1ポンド=150円換算)
titanic_df['Fare_JPY'] = titanic_df['Fare'] * 150
display(titanic_df[['Name', 'Fare', 'Fare_JPY']].head())

# 列の削除
titanic_df_clean = titanic_df.drop('Fare_JPY', axis=1)
display(titanic_df_clean.head())

7. 実践練習:クラスのテスト結果を分析しよう!

【お題】期末テスト結果の合計点・平均点・トップ生徒の算出

テスト結果分析コード
import pandas as pd

scores_df = pd.DataFrame({
    '名前': ['A君', 'Bさん', 'C君', 'Dさん', 'Eさん'],
    '国語': [82, 88, 76, 95, 65],
    '数学': [78, 92, 85, 89, 72],
    '理科': [85, 91, 78, 98, 68],
    '社会': [88, 79, 82, 92, 75],
    '英語': [76, 95, 88, 91, 78]
})

# 1. 各生徒の合計点と平均点を追加
subjects = ['国語', '数学', '理科', '社会', '英語']
scores_df['合計点'] = scores_df[subjects].sum(axis=1)
scores_df['平均点'] = scores_df[subjects].mean(axis=1)
display(scores_df)

# 2. 合計点トップの生徒
top_idx = scores_df['合計点'].idxmax()
print("トップ:", scores_df.loc[top_idx]['名前'], f"({scores_df.loc[top_idx]['合計点']}点)")

# 3. 理科90点以上の生徒
display(scores_df[scores_df['理科'] >= 90])

第1章 実践チャレンジお題

🎯 お題 1-A:数学85点以上の人数を求めよう 自動正誤判定

scores_df を使って、「数学が85点以上(scores_df['数学'] >= 85)」の生徒の人数を求め、半角数字で回答してください。

💡 ヒントを表示

math_high = scores_df[scores_df['数学'] >= 85]
print("人数:", len(math_high))

🎯 お題 1-B:英語の平均点を算出しよう 自動正誤判定

scores_df を使って、「英語」列の平均点(mean())を計算し、小数第1位まで(例: 85.6)入力してください。

💡 ヒントを表示

print("英語の平均点:", scores_df['英語'].mean())

🔥 お題 1-C(完全ノーヒント・発展):学年トップ生徒の合計点 ノーヒント

scores_df で5科目の合計点を算出し、「学年トップ(最も合計点が高い生徒)の合計点」を求めて数字のみで入力してください。ヒントはありません!これまでの知識を総動員して自力でコードを書いてみましょう。

第2章

02. 高校生のためのPlotly入門 on Google Colaboratory

1. はじめに:Plotlyって何?

Plotly(プロットリー)は、カーソルを合わせると数値がポップアップしたり、ズームができる対話型(インタラクティブ)なグラフを瞬時に作れるライブラリです。

Plotly Express のインポート
import plotly.express as px
import pandas as pd

2. 基本のグラフを作ってみよう(Plotly Express)

散布図(scatter)、折れ線(line)、棒グラフ(bar)の基本形です。

基本の3大グラフ
# 1. 散布図
fig_scatter = px.scatter(x=[85, 92, 78, 88, 75], y=[76, 88, 95, 82, 80], title="数学と英語の相関")
fig_scatter.show()

# 2. 折れ線グラフ
fig_line = px.line(x=['月', '火', '水', '木', '金', '土', '日'], y=[120, 150, 180, 160, 210, 250, 230], title="週間PV推移")
fig_line.show()

# 3. 棒グラフ
fig_bar = px.bar(x=['りんご', 'バナナ', 'いちご', 'みかん'], y=[15, 25, 18, 10], title="好きな果物")
fig_bar.show()

3. DataFrame連携とカスタマイズ

color(色分け)や size(サイズ変更)を指定することで、1つのグラフに3つ以上の情報を同時に表現できます。

多次元散布図
scores_df = pd.DataFrame({
    '名前': ['A君', 'Bさん', 'C君', 'Dさん', 'Eさん'],
    '国語': [82, 88, 76, 95, 65],
    '数学': [78, 92, 85, 89, 72],
    '理科': [85, 91, 78, 98, 68]
})

fig = px.scatter(
    scores_df, x='数学', y='理科',
    color='国語', size='国語', hover_name='名前',
    title='科目別成績の相関(国語の点数で色とサイズ分け)'
)
fig.show()

4. 応用:タイタニック号の可視化

客室クラス別の人数と、男女別の生存率のヒストグラムを作成します。

タイタニック可視化コード
titanic_df = pd.read_csv('https://raw.githubusercontent.com/pandas-dev/pandas/main/doc/data/titanic.csv')
titanic_df['生存状況'] = titanic_df['Survived'].map({0: '死亡', 1: '生存'})

# 1. 客室クラスごとの人数
pclass_counts = titanic_df['Pclass'].value_counts().reset_index()
pclass_counts.columns = ['客室クラス', '人数']
fig1 = px.bar(pclass_counts, x='客室クラス', y='人数', title='客室クラスごとの乗客数')
fig1.show()

# 2. 男女別の生存状況
fig2 = px.histogram(titanic_df, x='Sex', color='生存状況', barmode='group', title='男女別の生存・死亡数')
fig2.show()

第2章 実践チャレンジお題

🎯 お題 2-A:好きな色やデザインに変えてみよう 自力解答

好きな果物の棒グラフ(px.bar)で、color_discrete_sequence=['teal'] や color='x' を指定して棒の色を自分好みに変更してみましょう!

💡 ヒントを表示

fig_bar = px.bar(x=['りんご', 'バナナ', 'いちご', 'みかん'], y=[15, 25, 18, 10], color_discrete_sequence=['purple'])

🎯 お題 2-B:理科と英語の相関図を作成 自力解答

scores_df を使って、x軸に『理科』、y軸に『英語』をとった散布図を作成し、グラフタイトルを設定して表示してみましょう!

💡 ヒントを表示

fig = px.scatter(scores_df, x='理科', y='英語', hover_name='名前', title='理科と英語の点数相関')

🔥 お題 2-C(コード穴埋め・自動判定):最後の1行を補え! 自動正誤判定

次のコードは、タイタニック号の客室クラス別年齢分布(箱ひげ図)を作成するプログラムです。しかし、このまま実行してもColab上にグラフが表示されません。画面にインタラクティブなグラフを表示するために、最後に実行すべき1行のPythonコードを正確に入力してください。

# 箱ひげ図オブジェクトを作成
fig = px.box(titanic_df, x='Pclass', y='Age', title='客室クラス別の年齢分布')
# ★ ここに入るべき1行は何?
第3章

03. ブラウザでPythonが動く!PyScript × GitHub実践

1. サーバー不要!PyScriptって何がすごいの?

従来のWebアプリ(FlaskやDjango、Dashなど)は、月額料金がかかったりスリープしてしまう専用のバックエンドサーバー(Pythonサーバー)が必要でした。

しかし、最新の PyScript(WebAssembly技術) を使うと、「閲覧者のブラウザ上」で直接Python・Pandas・Plotlyが高速実行されます!これにより、サーバー維持費0円・スリープなし・超高速なWebアプリをHTMLだけで作れるようになります。

PyScriptの基本HTMLテンプレート
<!DOCTYPE html>
<html>
<head>
    <title>はじめてのPyScript</title>
    <!-- PyScriptの読み込み -->
    <link rel="stylesheet" href="https://pyscript.net/releases/2024.1.1/core.css">
    <script type="module" src="https://pyscript.net/releases/2024.1.1/core.js"></script>
</head>
<body>
    <h1>ブラウザで直接動くPython</h1>
    <script type="py">
        from datetime import datetime
        print(f"現在時刻: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    </script>
</body>
</html>

2. 本番アプリ:フロントエンドで動くGapminder分析アプリの作成

世界の国々の「一人当たりGDP」と「平均寿命」を可視化するGapminderバブルチャートアプリを作ります。HTMLのスライダーを動かすと、Python(PyScript)の関数が呼び出されてグラフがリアルタイムに更新されます!

このコードを index.html というファイル名で保存します。

完全版 index.html(GitHub配置用)
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Gapminder Data Dashboard</title>
    <!-- Tailwind CSS -->
    <script src="https://cdn.tailwindcss.com"></script>
    <!-- Plotly.js -->
    <script src="https://cdn.plot.ly/plotly-2.29.1.min.js"></script>
    <!-- PyScript -->
    <link rel="stylesheet" href="https://pyscript.net/releases/2024.1.1/core.css">
    <script type="module" src="https://pyscript.net/releases/2024.1.1/core.js"></script>
</head>
<body class="bg-slate-50 p-6 flex flex-col items-center min-h-screen text-slate-800">
    <div class="max-w-4xl w-full bg-white rounded-2xl p-6 shadow-md border border-slate-200">
        <h1 class="text-2xl font-bold text-center text-slate-900 mb-2" id="app-title">世界の経済力と平均寿命ダッシュボード</h1>
        <p class="text-xs text-center text-slate-500 mb-6">Powered by PyScript & Cloudflare Pages</p>

        <!-- グラフ表示エリア -->
        <div id="chart" class="w-full h-96 flex items-center justify-center bg-slate-100 rounded-xl">
            <span class="text-sm text-slate-400">Pythonエンジン起動中(初回は数秒かかります)...</span>
        </div>

        <!-- スライダー操作 -->
        <div class="mt-6 flex flex-col items-center space-y-2">
            <div class="flex items-center space-x-2 font-bold text-slate-700">
                <span>対象年:</span>
                <span id="selected-year" class="text-orange-600 text-lg">2007</span>年
            </div>
            <input type="range" id="year-slider" min="1952" max="2007" step="5" value="2007" class="w-72 accent-orange-500 cursor-pointer" py-input="on_slider_change">
            <span class="text-[11px] text-slate-400">※1952年から2007年まで5年刻みで移動できます</span>
        </div>
    </div>

    <!-- ブラウザ上で動作するPythonコード -->
    <script type="py" config='{"packages": ["pandas", "plotly"]}'>
        import js
        import json
        import pandas as pd
        import plotly.express as px

        # Gapminderデータの読み込み
        df = px.data.gapminder()

        def draw_chart(year):
            filtered = df[df.year == year]
            fig = px.scatter(
                filtered, x="gdpPercap", y="lifeExp",
                size="pop", color="continent", hover_name="country",
                log_x=True, size_max=60, range_x=[100, 100000], range_y=[25, 90],
                title=f"{year}年の経済力と平均寿命"
            )
            graph_json = json.loads(fig.to_json())
            js.Plotly.newPlot("chart", graph_json.get("data"), graph_json.get("layout"))

        def on_slider_change(event):
            val = int(event.target.value)
            js.document.getElementById("selected-year").innerText = str(val)
            draw_chart(val)

        # 初回描画 (2007年)
        draw_chart(2007)
    </script>
</body>
</html>

第3章 実践チャレンジお題

🎯 お題 3-A:タイトルや配色を自分好みに変更 自力解答

HTMLの <h1 id="app-title"> の文字を自分のオリジナルタイトルに変更し、スライダーのアクセントカラー(accent-orange-500 を accent-indigo-500 など)をカスタマイズしてみましょう。

💡 ヒントを表示

<h1 class="... text-indigo-700">〇〇のGapminder探究ダッシュボード</h1>

🎯 お題 3-B:初期表示年を「1952年」に設定してみよう 自力解答

初期表示を最新年(2007年)ではなく、最も古い年である「1952年」からスタートするように、スライダーの value="1952" と Python 内の draw_chart(1952) を書き換えてみましょう!

💡 ヒントを表示

1. <input ... value="1952">
2. <span id="selected-year">1952</span>
3. Pythonの末尾: draw_chart(1952)

🔥 お題 3-C(完全ノーヒント・自動判定):1952年日本の平均寿命 ノーヒント

スライダーを「1952年」に合わせた状態でグラフ上の「日本(Japan)」の点にカーソルを合わせるか、Colab上で df[(df.year==1952) & (df.country=='Japan')] を実行し、1952年当時の日本の平均寿命(lifeExp)の整数部分(例: 63)を入力してください。

第4章

04. Cloudflare Pagesで世界へ爆速無料公開&Webセキュリティ入門

1. GitHubへアプリを配置(Privateリポジトリの絶大な利点)

なぜGitHub Pagesではなく「Cloudflare Pages」を使うのか?

GitHub Pagesの壁: 無料プランではリポジトリを全世界に丸見えの「Public(公開)」にしなければWebサイトを公開できません。作成途中のコードやコミット履歴が世界中から見えてしまいます。

Cloudflare Pagesの決定的な強み: 無料プランでも「Private(非公開)」リポジトリと直接連携してWeb公開が可能です!生徒はGitHubのコードを非公開にしたまま、完成したWebアプリの画面だけを世界最速のCDNエッジサーバーで安全に配信できます。

  1. GitHub にログインし、新規リポジトリ(例: gapminder-pyscript)を Private(非公開) で作成します。
  2. 先ほど作成した index.html をリポジトリのルート(トップ画面)にアップロード(またはCommit)します。
📁 リポジトリの構成(たったこれだけでOK!)
gapminder-pyscript/ (Private)
└── index.html (PyScriptとPlotlyを含む単一ファイル)
└── README.md (アプリの説明文)

💡 プロのエンジニアはどうやってるの?(ローカルIDEとGitの話)

今回の実習では、学校の端末制限やインストール作業の手間を省くため、「ブラウザのGitHub画面上でファイルを直接作成・コピペしてアップロードする」という最も手軽な方法を採用しました。

しかし、実際のソフトウェアエンジニアがGitHubのWeb画面上でポチポチコードを貼り付けて開発することはまずありません! 現場では次のようなツールを使って本格的に開発しています:

  • ローカルIDE(統合開発環境)の利用: 自分のPCに VS Code(Visual Studio Code) や Cursor などの高機能エディタを入れ、シンタックスハイライト(色分け)や自動補完、AIアシスタントを活用して手元で快適にコードを書きます。
  • Gitコマンドによる厳密なバージョン管理: ターミナル(黒い画面)から git add . ➔ git commit -m "機能追加" ➔ git push origin main とコマンドを打ち込んでGitHubへ送信します。
  • ローカルプレビュー環境: 手元のPCでローカルサーバー(`localhost:3000` など)を立ち上げ、完璧に動くことを確認してからGitHubに反映させます(本番環境の破壊を防ぐため)。

自分のPCを手に入れたり、さらに上のレベルのWeb開発を目指すときは、ぜひ「VS Codeのインストール」と「Gitコマンドでのプッシュ」に挑戦してみてください。それがプロのエンジニアへの確実な第一歩です!

2. Cloudflare Pagesでデプロイ(管理画面のUI注意点!)

⚠️ 超重要:CloudflareのUIの罠(Workersに迷い込まないで!)

Cloudflareは現在「Workers(サーバーレス関数)」を前面に推し出しているため、何も考えずにボタンを押すとWorkersの作成画面に誘導されてしまいます。

左メニューの「Workers & Pages」➔「Create application」を押したあと、画面上部のタブで必ず 「Pages」タブ をクリックして切り替えてください!その中にある「Connect to Git」を選択します。

  1. Cloudflareダッシュボード に無料登録・ログインします。
  2. 左メニューの 「Workers & Pages」➔ 「Create application」 を開きます。
  3. 必ず「Pages」タブを選択し、「Connect to Git」 をクリックします。
  4. GitHubアカウントを連携し、先ほど作成した gapminder-pyscript(Privateリポジトリ)を選択して 「Begin setup」 をクリックします。
  5. ビルド設定画面では、静的HTMLなので設定を一切変更する必要がありません:
    • Framework preset: None(デフォルト)
    • Build command: 空欄のまま
    • Build output directory: 空欄(または /)
  6. 「Save and Deploy」 を押すと、世界中のエッジサーバーにアプリが配備されます!
  7. 発行されたURL(例: https://gapminder-pyscript.pages.dev)を開いて、スリープのない爆速のWebアプリを確認しましょう。
セキュリティ実験①

【プチハッキング体験】別ファイル secret.txt は本当に安全?

「GitHubをPrivate(非公開)にしたし、index.htmlとは別の secret.txt というファイルにパスコードを書いておけば、外からは見えないのでは?」

初心者が最も陥りやすいこの思い込みが、なぜ大間違いなのかを実際に自分の手でハッキング(検証)してみましょう!

  1. GitHubリポジトリ内に secret.txt という新規ファイルを作成します。
  2. 中身に合言葉として open-sesame-777 とだけ書き、コミット(保存)します。
  3. Cloudflare Pagesが自動で再デプロイを完了したら、ブラウザのアドレスバーに自分の公開URLの後ろに /secret.txt を直打ちして開いてみてください:
    https://あなたのプロジェクト名.pages.dev/secret.txt
  4. 結果はどうなりましたか? パスワードが画面に平文でそのまま表示されたはずです!

フロントエンド配信の鉄則:置いたファイルはすべて「配られる」!

Cloudflare Pagesのような静的ホスティングは、リポジトリに置いたすべてのファイルを閲覧者のブラウザへ渡す(ダウンロードさせる)仕組みです。 どれだけファイルを分けたり複雑な名前をつけても、「URL直打ち」や「F12(開発者ツールのNetworkタブ)」を開けば丸見えになります。フロントエンドには絶対に機密情報を置いてはいけません!

セキュリティ実践②

【本物のバックエンド構築】環境変数とPages Functionsで秘密を守る!

「じゃあ本物のWebサービスはどうやってパスワードを守っているのか?」
答えは、「ブラウザ(手元)にパスワードを渡さず、サーバー側(向こう側)の金庫で照合して、判定結果(OK/NG)だけを返す」です。

Cloudflare Pagesには最初から Pages Functions(サーバーレスバックエンド機能) が内蔵されています。コードに一切パスワードを書かず、安全なログイン認証APIを作ってみましょう。

ステップ1:Cloudflareの金庫(環境変数・シークレット)に合言葉を登録

GitHubのコードには絶対に書かず、Cloudflareダッシュボードにだけ保存します。

  1. Cloudflareダッシュボードで自分のPagesプロジェクトを開き、上部(または左メニュー)の 「Settings」 を選択します。
  2. 画面を少しスクロールし、「Variables and secrets」 の欄を見つけます。
  3. 右上の 「+ Add」 ボタンをクリックします。
  4. 項目を入力して保存します:
    • Type: 「Secret」(または Plain text)
    • Name: APP_PASSWORD
    • Value: pyscript999
ステップ2:functions/api/check.js をGitHubに作成
// リポジトリ内に「functions」フォルダを作り、その中に「api」フォルダ、「check.js」を作成
// このファイルはブラウザにダウンロードされず、Cloudflareのエッジサーバー内だけで秘密裏に動きます!
export async function onRequestPost(context) {
    const { request, env } = context;
    const body = await request.json();

    // サーバーの金庫(環境変数)と照合
    const correctPassword = env.APP_PASSWORD;
    const isMatched = (body.inputPassword === correctPassword);

    // ブラウザには正解パスワードを教えず、「合ってるかどうか」の結果だけを返す!
    return new Response(JSON.stringify({ 
        success: isMatched,
        message: isMatched ? "認証成功!秘密データを開放します。" : "合言葉が違います。"
    }), {
        headers: { "Content-Type": "application/json" }
    });
}
ステップ3:フロントエンド(index.html)からサーバーに問い合わせるコード
<!-- 画面側のJavaScriptからサーバーへ安全に確認を依頼する処理 -->
<script>
async function verifyWithBackend(userPassword) {
    const response = await fetch('/api/check', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ inputPassword: userPassword })
    });
    const result = await response.json();
    if (result.success) {
        showToast("サーバー認証成功!F12を開いてもパスワードは漏洩しません", "success");
    } else {
        showToast(result.message, "error");
    }
}
</script>

第4章 実践チャレンジお題

🎯 お題 4-A:GitHubにREADME.mdを作成してみよう 実践課題

GitHubリポジトリ内に README.md を作成し、「このWebアプリはPyScriptで動くGapminder可視化ダッシュボードです。制作者:〇〇」という説明を書いてみましょう。

💡 ヒントを表示

GitHubのリポジトリ画面で「Add file」➔「Create new file」を選択し、ファイル名を README.md とします。

🎯 お題 4-B:Cloudflare Pages公開URLの動作確認 自動URL判定

Cloudflare Pagesで発行されたURL(https://....pages.dev)を入力欄に貼り付けて「判定する」を押してください。正当なPagesドメインであるかを自動判定します!

🔥 お題 4-C(完全ノーヒント・発展):CI/CDによる自動更新確認 ノーヒント

GitHub上の index.html のタイトル文字などを直接編集してコミットしてみてください。Cloudflare Pages側で何もボタンを押さなくても、数秒で本番サイトが自動更新されるサイクル(CI/CD)を確認できたら完了チェックを押してください。

🕵️‍♂️ お題 4-D(セキュリティ体験):直打ちで暴いた合言葉は? 自動正誤判定

実験①で /secret.txt にアクセスしたときに画面に表示された合言葉(パスコード文字列)を入力して判定してください。

🛡️ お題 4-E(バックエンド理解):APIエンドポイントのURL 自動正誤判定

functions/api/check.js というファイルを作った場合、ブラウザから呼び出すときの相対URL(APIのエンドポイントパス)は何になりますか?(例: /api/...)