0. はじめに
直近3ヶ月ほど、PostgreSQL16〜18のチューニングについて、実践を交えながら記事にまとめてきました。その過程で、改めて「SQLを書いて練習できる場所」が欲しいと感じるようになり、学習サービスkufu:SQLを開発しました。
こんな方に読んでいただきたい記事です。
- SQLを手を動かして学びたい方(サービスの利用者として)
- 個人開発で低コストなインフラ構成を探している方
- 生成AIを使った開発が、実際どのように進むのか知りたい方
コンセプト・アーキテクチャ・採用するプログラミング言語(当初はScalaを検討していました)については、2週間ほど生成AIと壁打ちを重ねて設計を固めています。壁打ちの段階では、実装にも2ヶ月ほどかかるだろうと見込んでいましたが、いざ着手すると、設計がすでに固まっていたこともあり、実装自体は2日ほどで動作する状態まで仕上がり、そのまま本番公開まで進めることができました。
架空のSaaS企業「Kufu Cloud」に入社した新人データアナリストとして、各部署からの依頼をSQLで解決していく――という体裁で、Lv.1〜70の問題を用意しています。本記事では、このサービスをどのような構成で作ったか、そして生成AIをどのように使ったかをまとめます。
- サービスURL:https://kufusql.sanpo-insight.com
- GitHub(OSS公開):https://github.com/matsutomu/kufu-sql
1. この記事でわかること
- ブラウザ上でSQLを実行できる仕組み(sql.js/SQLite on WebAssembly)の使い方
- サーバー負荷を抑えるハイブリッド構成(クライアント実行+Go API)の考え方
- EC2の自動起動・停止によるコスト削減の設計
- 70問の問題データを、正解SQLの実行結果から自動生成する仕組み
- 開発において、生成AIと人間がそれぞれ何を担ったか
2. サービス概要
| 項目 | 内容 |
|---|---|
| サービス名 | kufu:SQL |
| 名前の由来 | 禅語「工夫」(仏道修行において真剣に考え精進すること)とSQLの造語 |
| コンセプト | Kufu Cloudという架空のSaaS企業に入社した新人データアナリストとして、Lv.1〜70の依頼を解決しながらSQLを学ぶ |
| フロントエンド | React + sql.js(SQLite on WebAssembly) |
| バックエンド | Go |
| データベース | PostgreSQL |
| インフラ | EC2 + CloudFront + S3 + Route53 + EventBridge |
| 開発支援 | Claude Code(AIコーディングアシスタント) |
3. なぜこの構成にしたか
SQL学習サービスというと、「ユーザーが入力したSQLをサーバー側のDBで実行する」構成が一般的です。ただしこの方式は、ユーザー数が増えるほどサーバー負荷が上がるうえ、任意のSQLをサーバー側で実行することになるため、セキュリティ面のリスクも抱えることになります。
kufu:SQLでは、ユーザーが入力したSQLをブラウザ内のsql.js(SQLite on WebAssembly)で実行し、採点や進捗保存など必要な処理だけをGo APIに送る構成にしました。SQLの実行処理はサーバー側で発生せず、APIサーバー側で任意のSQLを実行するリスクも避けられます。
3.1 sql.jsでSQLを動かす最小コード
sql.jsは、SQLiteをWebAssemblyにコンパイルしたライブラリで、ブラウザ内で完結してSQLを実行できます。最小構成は次のとおりです。
import initSqlJs from "sql.js";
const SQL = await initSqlJs({
locateFile: (file) => `https://sql.js.org/dist/${file}`,
});
const db = new SQL.Database();
db.run(`CREATE TABLE customers (id INTEGER, company_name TEXT);`);
db.run(`INSERT INTO customers VALUES (1, 'Kufu商事'), (2, '山田製作所');`);
const result = db.exec(`SELECT * FROM customers WHERE id = 1`);
console.log(result[0].columns); // ['id', 'company_name']
console.log(result[0].values); // [[1, 'Kufu商事']]
これだけで、サーバーを一切介さずにテーブル作成・データ投入・SELECTまで動きます。学習用途のように「ユーザーごとに独立した小さなDBがあればよい」ケースには、非常に相性のよい仕組みです。
4. アーキテクチャ
4.1 全体構成
4.2 EC2の自動起動・停止によるコスト削減
学習サービスという性質上、深夜早朝のアクセスはほとんど見込めません。そこでEventBridgeでEC2の起動・停止スケジュールを組み、サービス提供時間を8時〜19時に限定しています。個人開発でランニングコストを抑えたい場合には有効な手段の一つです。
EC2停止中もElastic IPの保持やEBSのストレージ課金は発生するため、完全に無料になるわけではありません。あくまで「稼働時間分のコンピューティング費用を抑える」施策です。
4.3 コスト目安
| リソース | 月額目安 |
|---|---|
| EC2(日中のみ稼働) | 約5〜7ドル |
| EBS | 約1.6ドル |
| S3 + CloudFront | 約1ドル |
| Route53 | 約0.5ドル |
| Lambda(自動起動停止) | 無料枠内 |
| 合計 | 約8〜10ドル/月 |
5. 問題セットの設計(Lv.1〜70)
5.1 カテゴリ構成
架空のSaaS企業「Kufu Cloud」に新人データアナリストとして入社し、各部署からの依頼を解決していくというストーリー形式で、70問を構成しています。
| カテゴリ | 問題数 | 内容 | 想定部署 |
|---|---|---|---|
| SQL基礎 | 10問 | SELECT・WHERE・ORDER BY・LIMIT | 営業部・経理部 |
| 集計 | 10問 | COUNT・SUM・AVG・GROUP BY・HAVING | マーケティング部・カスタマーサクセス |
| JOIN | 15問 | テーブル結合 | 営業企画・プロダクトマネージャー |
| 分析 | 15問 | サブクエリ・CASE・CTE・UNION | 経営企画・データ分析チーム |
| PostgreSQL実践 | 20問 | Window関数・FILTER・JSON | 開発部・SRE・データエンジニア |
実際の問題画面はこのようなイメージです。問題文・SQLエディタ・実行結果が1画面に収まっており、ブラウザだけで学習が完結します。
5.2 正解データの自動生成
70問分の期待結果(result_json)は手作業では用意していません。各問題ごとにDDL・シードデータ・正解SQLをJavaScriptオブジェクトとして定義し、フロントエンドと同じsql.js(SQLite on WASM)で実際に実行した結果を、そのままマイグレーションSQLとして出力する仕組みにしています。
問題定義は、おおよそ次のようなイメージです(実際のコードを簡略化した例です)。
const problem = {
id: 1,
categoryId: 1,
title: "Lv.1 はじめての顧客リスト",
ddl: `CREATE TABLE customers (...)`,
seed: `INSERT INTO customers VALUES (...)`,
answerSql: `SELECT * FROM customers`,
};
// DDL → シード投入 → answerSqlを実行し、結果をresult_jsonとして確定
const resultJson = runOnSqlJs(problem.ddl, problem.seed, problem.answerSql);
この方式には、以下の利点があります。
- 正解SQLに文法エラーがあれば、生成の時点で検知できる
- 期待結果を手動で書き起こす手間や転記ミスがなくなる
- 問題データを変更しても、生成スクリプトを再実行するだけで整合性を保てる
さらに、生成後には以下のような検証ステップを追加しています。
- 全問題の
answer_sqlが重複していないかのチェック - ヒントの中に正解SQLの核心部分がそのまま含まれていないかのチェック
- 各カテゴリ内で難易度(easy/medium/hard)の並びが不自然になっていないかのチェック
- 実行結果が意図せず0件になっている問題がないかのチェック
70問規模のコンテンツでも、手作業のレビューに頼りすぎずに一定の品質を担保できる仕組みになっています。
6. 開発期間について
kufu:SQLは当初、インフラ構築からβ公開まで12週間程度を見込んで計画していました。実際には、2週間の設計フェーズを経たあと、実装自体は2日ほどで本番稼働まで到達しています。
要因を厳密に切り分けることは難しいですが、以下が影響したと考えられます。
- 設計フェーズで、コンセプト・アーキテクチャ・技術選定をあらかじめ固めておいたこと
- インフラ構成をシンプルなハイブリッド型(クライアント実行+最小限のAPI)にとどめたこと
- 問題データの生成・検証を自動化し、手作業のレビュー工数を減らしたこと
- 実装・インフラ構築の一部にAIコーディングアシスタントを活用したこと
この期間の短さについては、生成AIを使った本格的な新規開発を通じて、いわゆる「産業革命」という言葉で語られる変化の感覚を初めて実感した、というのが率直な印象です。
その一方で、人間の役割が不要になったとは感じていません。今回の開発を通じて、現時点での人間の役割は、次の3点に集約されるのではないかと考えています。
- 実現したいことを明確にすること
- アーキテクチャを明確にすること
- できたものを必ず批判的に確認すること
7. AIコーディングアシスタントの活用について
本プロジェクトでは、実装からインフラ構築まで幅広くClaude Codeを活用しました。ただし、すべてを任せきりにしたわけではなく、役割は次のように分かれています。
AIが担当したこと
- フロントエンド・バックエンドの実装コード生成
- セキュリティ改善(CORS設定・エラーレスポンスの見直し・バリデーション強化)の実装
- AWS CLIコマンドの組み立て
- デプロイ時に発生したエラーメッセージからの原因切り分け
人間が判断・レビューしたこと
- 実現したい機能・仕様、コンセプトの決定
- アーキテクチャ全体の設計判断
- 生成されたコードの内容確認・採用可否の判断
- 本番環境への反映・実行の最終的な意思決定
生成されたコードやコマンドは、そのまま採用するのではなく、内容を確認したうえで反映する運用にしています。個人開発において、実装からインフラ構築までを一人で担う場合、AIコーディングアシスタントと組み合わせることで開発速度を高められる可能性があると感じました。
8. コントリビューション歓迎です
kufu:SQLはOSSとして公開しています。5.2で紹介したとおり、問題は「DDL・シードデータ・正解SQL」をJavaScriptオブジェクト1つで定義するだけで追加できる構造になっているため、問題の追加・改善のハードルは比較的低くなっています。
以下のような形での参加を歓迎しています。
- 問題の追加・改善のPull Request:新しい問題の追加や、既存問題の問題文・ヒントの改善
- Issueでの報告:誤字脱字、難易度バランスへの違和感、動作の不具合など、気づいた点があればお気軽に
- リクエストだけでも歓迎:「こんな問題が欲しい」「このSQL構文のカテゴリを増やしてほしい」といったご要望も、Issueでいただければ検討します
リポジトリを見ていただき、「面白そう」と感じていただけましたら、スターをいただけると開発の励みになります。
9. まとめ
- ブラウザ内でSQLを実行するsql.jsと、採点・進捗管理のみを担うGo APIを組み合わせることで、サーバー負荷を抑えつつSQL学習サービスを構築できます
- EventBridgeによるEC2の自動起動・停止は、個人開発のランニングコストを抑える有効な手段の一つです
- DDL・シードデータ・正解SQLからresult_jsonを自動生成する仕組みにより、70問規模のコンテンツでも品質を保ちやすくなります
- 2週間の設計フェーズを経てから実装に入ったことが、実装自体を2日に短縮できた要因の一つと考えられます
- AIコーディングアシスタントには実装・インフラ構築を任せつつ、仕様決定・設計判断・最終レビューは人間が担う、という役割分担が今回の開発では機能しました
サービスは8時〜19時に稼働しています。SQLを習得する場所として、ぜひご活用ください。



