勉強嫌いな我が子へ!Antigravityと作った学習アプリ個人開発記録
📋 1分で読めるこの記事の概要
- 開発の根本動機は泥臭い親のリアル:上二人の勉強嫌い、高額な塾代への悩み、机に向かわない現実。「タブレットを見るなら、敵を味方にして自分専用アプリを作ればいい」という逆転の発想からスタート。
- 「せっかく作ったんだから自分も使おう」パパも後からユーザーへ:年長(ひらがな・計算)、小2(九九・漢字)、小4(わり算・つるかめ算)。完成後に「UIはそのままで問題だけITストラテジストや中小企業診断士を出せばいい」と後からパパ自身も参入。親も横で本気で学ぶ共創空間が自然に完成。
- 衝撃の事実:人間はコードを1行も書いていない!:TypeScriptもReactもDrizzleスキーマも、私自身は1行もコードを書いていません。親としての課題感や愛、PMP的な要件を「こうして、こういうのやって」と自然言語で伝えただけで、Antigravityが全自動で自律実装。
- 観察から生まれた機能の引き算(YAGNI原則):年長児の観察から「ひらがなは完璧に読める」と判明。テンポを損なう音声読み上げ機能はバッサリ削除し、爆速で解ける操作性を最優先。
- 認知心理学と愛あるUI設計:直後のやり直し正解で満足させない「翌日再テスト原則(短期記憶の錯覚防止)」、「かんたんモード」などの表記を一切出さずに裏側で調整する「UIサイレント適応」、100点満点の紙吹雪演出、掛け算認証付き保護者ダッシュボードを完備。
- 令和最強の完全無料エッジ技術スタック:Astro 5 + React 19 + Tailwind CSS v4 + Cloudflare Pages + Cloudflare D1(分散SQLite)+ Drizzle ORM + GitHub Actions CI/CDによる維持費0円・表示速度ミリ秒の世界を構築。
「勉強しなさい!」
夕暮れ時のリビングに、私の怒鳴り声が響き渡る。
返ってくるのは子供たちの深いため息と、不満げな表情。机に向かわせても鉛筆はピクリとも動かず、ノートの端に落書きが量産されていくだけ。
「塾に通わせるべきか……?」
そう考えて近隣の学習塾のパンフレットを取り寄せるものの、子供3人分の月謝を計算して愕然としました。毎月数万〜十数万円の固定費が重くのしかかる現実は、いくら子どもの教育のためとはいえ簡単には受け入れられません。
そんなある日の夜、ふとリビングのソファに目をやると、あんなに机に向かうのを嫌がっていた子どもたちが、タブレット端末を食い入るように見つめ、指先をリズミカルに動かしていました。
「……待てよ?」
机の上にある紙のドリルには1ミリも興味を示さないのに、タブレットの画面にはこれほど強烈に没頭している。
ならば、タブレットという敵を無理やり奪い取るのではなく、 敵を味方にしてしまえばいいのではないか?
市販の知育アプリを探しても、広告だらけだったり、アニメーションが長すぎてテンポが悪かったり、月額課金が高すぎたりと、我が家にぴったりのものが見当たらない。
「それなら、Googleの次世代自律開発AIであるAntigravityを使って、我が子たち専用の最強学習アプリを作ってしまおう!」
こうして始まったのが、子供向け学習アプリ『まなびキッズ(manabi-kids)』の個人開発プロジェクトでした。
世の中に溢れる「AIでToDoアプリを作ってみた」というような単なる技術デモではありません。小4・小2・年長の我が子たちが毎日リビングで実際に使い倒し、記憶科学と認知心理学に基づいたアルゴリズムが走り、パパエンジニアのPMP(プロジェクトマネジメント・プロフェッショナル)流の設計思想を注ぎ込んだ、 生きた現場のプロダクト です。
そして何より驚くべきは、 このプロダクトのコードを、私自身は1行も書いていない ということです。
私がやったのは、「こういう課題があるから、こうしてほしい」「次はこういうのをやって」と自然言語で指示を出したことだけ。本記事では、その誕生秘話から完全自律開発の裏側まで、すべてを包み隠さず公開します。
第1章:我が子3人の要求分析とMVP設計、そして「パパの後から参入」
個人開発で最も陥りがちな失敗は、「作り手が作りたいものを作ってしまい、誰も使わないゴミを生み出すこと」です。
特に相手が子どもである場合、大人の理屈で作ったアプリは容赦なく見向きもされません。1回タップして反応が遅かったり、面白くないと感じた瞬間に画面を閉じられ、二度と開いてくれません。
そこで私は、本業で培ってきたPMP(プロジェクトマネジメント)のステークホルダー分析と要件定義の手法を、そのまま我が家のリビングに持ち込みました。当初のターゲットは、勉強嫌いに悩む我が子3人です。
【まなびキッズのステークホルダー構造】
┌─────────────────────────────────────────────────────────────┐
│ まなびキッズ空間 │
├─────────────────┬─────────────────┬─────────────────────────┤
│ 🐥 たいよう(年長)│ 🌸 ひなた(小2) │ 🚀 そうた(小4) │
│ ひらがな完璧・計算 │ つまづき九九・漢字│ 2桁わり算・つるかめ算 │
├─────────────────┴─────────────────┴─────────────────────────┤
│ 👨💼 【後から参入!】パパ(LEE):ITストラテジスト & 中小企業診断士 │
│ 「せっかく作ったんだから自分も使おう」UIそのまま問題だけ入替│
└─────────────────────────────────────────────────────────────┘
1-1. 我が家の3人の子どもたちと要求事項
当初のユーザーである子ども3人それぞれの習熟度と課題を徹底的に分析しました。
🐥 年長(たいよう):知的好奇心の芽生え
- 現状: ひらがなは完璧に読める。文字を書くこと、数字を数えることに強い興味を持ち始めている。
- 課題: 小学校入学に向けて、1桁の足し算・引き算の概念を楽しく身につけたい。
- 要求事項: テンポよくサクサク答えられること。直感的な数字の増減演出。
🌸 小2(ひなた):小学生最大の関門「九九」
- 現状: 計算は嫌いではないが、暗記が苦手。小学2年生の最大の壁である「掛け算九九」で足踏み中。
- 課題: 2年で習う160字もの新出漢字と、7の段・8の段の定着。
- 要求事項: つまづいた段を集中的に反復できること。間違えても恥ずかしくない工夫。
🚀 小4(そうた):抽象的思考へのステップアップ
- 現状: 上の子特有のプライドがあり、簡単な問題をやらされるとへそを曲げる。
- 課題: 2桁の割り算、小数・分数、つるかめ算の基礎、ことわざ・四字熟語などの語彙力。
- 要求事項: ちょっと背伸びした「難しい問題に挑戦してクリアした」という達成感。
1-2. 機能の引き算(YAGNI原則):年長児を見て「音声読み上げ」を捨てた日
アプリ開発において、プログラマーが最も陥りやすい病気があります。それは「あれもこれも便利そうだから付けよう」という機能の肥大化です。
ソフトウェア工学には、 YAGNI原則(You Aren't Gonna Need It:今必要なもの以外は作るな) という黄金律があります。
まなびキッズの企画当初、私は「年長児も使うのだから、問題文を機械音声で読み上げるWeb Speech API機能は必須だろう」と考えていました。
しかし、実際にプロトタイプを作って年長のたいようを観察したとき、衝撃的な事実に気づきました。
たいようは、画面に問題が出た瞬間にひらがなをスラスラと目で読み、音声が「つ・ぎ・の・も・ん・だ・い・は……」と喋り終わるのを待たずに、パパッと答えのボタンを押していたのです。
それどころか、流れてくる音声読み上げが自分の回答テンポを邪魔するため、イライラして画面を連打していました。
「ひらがなが完璧に読めるなら、音声読み上げは価値を提供するどころか、ユーザー体験を損なう致命的なノイズでしかない!」
この観察を得た瞬間、私は音声読み上げ機能の実装コードをバッサリと削除(引き算)しました。
【機能の引き算:何を採用し、何を捨てたか】
⭕ 攻めた機能(残したもの)
・0.1秒で即座に反応する軽量タップUI
・1問1答のリズミカルな画面遷移
・正解・不正解の明快な視覚演出(○×アニメーション)
・100点満点時のド派手な紙吹雪
❌ 捨てた機能(削ぎ落としたもの)
・もたつく音声読み上げ機能(テンポの阻害)
・過度なキャラクターのおしゃべり(思考の邪魔)
・回答前のチュートリアル動画(触れば分かる設計)
・複雑なアバター着せ替え要素(勉強の本質からの逸脱)
学習アプリにおいて最も大切なのは、「思考と回答のテンポ(リズム感)」です。無駄な装飾を徹底的に削ぎ落としたことで、子どもたちはゲームの「テトリス」をプレイするかのように、集中して問題に没頭できるようになりました。
1-3. 「せっかく作ったんだから自分も使おう」UIそのまま、パパの高度資格モードを後から追加
子ども3人向けのアプリが完成し、リビングで子どもたちが楽しそうにサクサク問題を解いている姿を眺めていたとき、ふと強烈なひらめきが降ってきました。
「……待てよ? せっかくこんなに優れた忘却曲線アルゴリズムと、0.1秒で動く爆速UIを作ったんだ。自分もユーザーになればいいんじゃないか?」
実は私自身も、IPAの最難関資格である「ITストラテジスト(ST)」や「中小企業診断士」の試験を控えており、まとまった勉強時間をどう捻出するかに悩んでいました。
そこで試したのが、 UIはそのままで、問題データだけ大人の高度資格問題に差し替える という拡張です。
まなびキッズは最初から「画面の表示ロジック」と「問題の出題ロジック」が完全に分離(疎結合)されたデータドリブン設計になっていました。そのため、フロントエンドのReactコンポーネントには1行も手を加えることなく、データベース(Cloudflare D1)の問題マスターに「ITストラテジストの午前IIキーワード」や「中小企業診断士の企業経営理論・経済学」の4択問題を流し込むだけで、一瞬にして パパ専用の本格学習モード が誕生したのです。
【UIそのまま、データだけ差し替える疎結合の勝利】
┌────────────────────────────────────────────────────────┐
│ 共通UIコンポーネント(React 19) │
│ ・0.1秒レスポンスの4択カードボタン │
│ ・翌日再テスト & 忘却曲線アルゴリズム │
│ ・満点時の紙吹雪演出 & サウンドエフェクト │
└───────────────────────────┬────────────────────────────┘
│ 出題データを切り替え
┌───────────────────┴───────────────────┐
▼ ▼
【子ども用マスター】 【パパ用マスター】
・年長:1桁たし算・ひらがな ・ITストラテジスト午前II
・小2:九九・2年漢字 ・中小企業診断士(企業経営・経済)
・小4:2桁わり算・つるかめ算
子どもたちがタブレットで九九を解いている横で、私も同じアプリの画面を開いてストラテジストや診断士の問題を解く。
「パパも今、難しい大人のテスト勉強中なんだ。誰が先に満点取れるか、一緒に10問勝負しよう!」
この一言で、リビングの空気は一変しました。「勉強を強制される場」から「家族みんなでスコアを競い合う共創空間」へとパラダイムシフトしたのです。親が本気で学ぶ背中を見せることこそ、何百回の「勉強しなさい!」よりも強力な動機づけになりました。
第2章:私はコードを1行も書いていない!Antigravityによる完全自律開発
今回の個人開発において、開発速度と品質を劇的に引き上げてくれたのが、Googleの次世代自律AI開発環境である Antigravity でした。
2-1. 人間が書いたコードは「0行」:自然言語だけでアプリが完成した事実
ここで、本記事の中で最もお伝えしたい衝撃の事実を白状します。
本記事でこのあと紹介するAstroの画面構成、React 19コンポーネント、TypeScriptの記憶アルゴリズム、Drizzle ORMのスキーマ定義、Cloudflare D1のSQLクエリ、さらにはGitHub ActionsのCI/CDワークフローに至るまで、 私自身はコードを1行も書いていません 。
私がキーボードで打ち込んだのは、プログラミング言語ではなく、リビングで子どもたちを観察して感じた「こうしてほしい」「次はこういうのをやって」という 自然言語(日本語)の指示だけ です。
従来の個人開発であれば、TypeScriptの型エラーと格闘し、Reactの状態管理で悩み、CSSの微調整に何時間も溶かすのが当たり前でした。しかし本作『まなびキッズ』の開発において、私は完全に プロダクトオーナー(要件定義と受け入れテストの担当者) に徹し、実装・ビルド・デバッグのすべてをAntigravityに一任しました。
2-2. CursorやClaude Codeとの決定的な違い
昨今、CursorやClaude CodeといったAIコーディングツールが大きな注目を集めています。私自身もこれらを日常的に使い倒してきました。
しかし、Antigravityを実際に使ってみて痛感したのは、従来のツールとは AIの関与する抽象度の次元が根本的に異なる ということです。
従来のコーディングAIは、人間が指示した関数やコンポーネントを局所的に生成する「超優秀なタイピスト(コード補完)」でした。ファイル間の依存関係やアーキテクチャの選定、DBスキーマのマイグレーションといった大局的な判断は、常に人間側が手を動かして管理する必要がありました。
これに対し、Antigravityは プロジェクト全体の意図と文脈を自律的に理解するシニアテックリード です。
graph TD
subgraph Traditional["従来のAIコーディングツール"]
U1["人間(プログラマー)"] -->|"局所プロンプト入力"| AI1["コード補完AI"]
AI1 -->|"関数・コンポーネントの出力"| U1
U1 -->|"人間が手動でファイル配置・動作検証"| DB1["コードベース"]
end
subgraph Antigravity["Antigravity 自律開発環境"]
U2["人間(パパ・プロダクトオーナー)"] -->|"「こうして、こういうのやって」自然言語で指示"| AG["Antigravity 自律エージェント"]
AG -->|"スキーマ策定・ファイル生成・リファクタ"| Code["フルスタックコード"]
AG -->|"ビルド実行・エラー自己修復・テスト"| Build["CI/CD・検証"]
AG -->|"「完了しました。確認してください」"| U2
end
私が「小2の娘が九九の7の段でいつもつまずく。前回の正答率データを参照して、苦手な段の出現頻度を重み付けするロジックを組みたい」と自然言語で指示を出すと、Antigravityは即座に以下の作業を自律的に実行してくれました。
- 既存のDrizzle ORMスキーマから解答履歴テーブルの構造を自ら把握
- 過去の誤答率に基づいた重み付けランダム抽出アルゴリズムを設計・実装
- TypeScriptの型安全性を担保したユーティリティ関数の作成
- ユニットテストの記述とテスト実行、エラーがあれば自己修復してパスを確認
2-3. 阿吽の呼吸で進むペアプログラミング体験
Antigravityとの開発は、単なる命令と実行という一方通行の関係ではありませんでした。こちらの教育心理的な意図まで深く汲み取ってくれる、まさに「阿吽の呼吸」の体験でした。
例えば、後述する「自尊心を傷つけないサイレント適応UI」を指示した際、私とAntigravityの間で交わされた対話は以下のようなものでした。
私: 「正答率が落ちたときに難易度を下げたいんだけど、画面に『かんたんモードに切り替えました』とか『レベルダウン!』って絶対に出したくないんだよね。うちの子、そういうのを見るとプライドが傷ついてアプリを投げ出しちゃうから、裏側でこっそり調整してほしい」
Antigravity: 「素晴らしい洞察ですね。教育心理学の観点からも、外的なラベリングによる自己効力感の低下は学習意欲を著しく阻害します。画面のUI状態は『きょうの 10もん』というポジティブな表現を維持したまま、出題スコアの内部パラメータのみを 100 ➔ 90 ➔ 80 とサイレントに調整するステートマシンを実装しましょう。コンポーネント側には一切の差分を出さず、バックエンドの取得クエリ側で重み係数を制御するアーキテクチャを提案します」
この返答を見た瞬間、私は鳥肌が立ちました。こちらの親としての想いやニュアンスを完全に汲み取り、それを最もクリーンな設計へと落とし込んでくれる。
人間が「愛ある要件」を自然言語で語り、AIがそれを「プロフェッショナルなコード」へと具現化する。これこそが、AI時代のソフトウェア開発の真の姿だと確信しました。
第3章:子供が夢中になる「記憶科学」と「愛あるUI設計」
まなびキッズが市販の学習アプリと決定的に一線を画しているのは、 子供の認知心理学と最新の記憶科学をコードレベルで徹底的に突き詰めている点 です。
3-1. 【記憶科学】短期記憶の錯覚(Fluency Illusion)を防ぐ「翌日再テスト原則」
間違えた問題を復習させる際、世の中のほとんどのドリルやアプリは、間違えた直後に「もう一度解いてみよう!」と同じ問題を解かせます。
そして子供がそこで正解すると、「よくできました!100点!」と花丸をつけて終わります。
しかし、これは脳科学的に見れば「学習」ではなく、単なる「直前の残像の再生」に過ぎません。
認知心理学では、これを 流暢性の錯覚(Fluency Illusion) と呼びます。
【流暢性の錯覚(Fluency Illusion)の罠】
❌ 一般的な学習アプリの流れ
間違える ➔ 直後に再出題 ➔ 網膜に残った記憶で正解 ➔「覚えた!」と錯覚 ➔ 3日後に完全に忘れる
⭕ まなびキッズの「翌日再テスト原則」
間違える ➔ 当日は解説を見て理解に留める ➔【意図的な時間の間隔】➔ 翌日以降のセッションで再想起 ➔ 初めて長期記憶へ昇格!
間違えた直後は、脳のワーキングメモリ(作業記憶)に答えが残っているため、誰でも簡単に正解できます。子供は「できた!」と喜びますが、それは長期記憶に定着したわけではありません。3日も経てば綺麗さっぱり忘れてしまいます。
真に知識を脳に定着させるためには、 忘れかけた頃に頭に負荷をかけて思い出す作業(検索練習:Retrieval Practice) が絶対に不可欠です。
そこでまなびキッズでは、以下の 翌日再テスト原則(Spaced Retrieval Logic) を実装しました。
- 当日のセッションで間違えた問題は、その場で正解しても「要復習ステータス」のまま維持する。
- どんなに当日にやり直して全問正解しても、その日の総合ステータスは「マスター(習得済み)」には昇格させない。
- 日付が変わった翌日以降のセッション において、ノーヒントで正解できて初めて「マスター」フラグを付与する。
このロジックを組み込んだことで、見せかけの100点に惑わされることなく、本当に子供たちの脳に九九や漢字が刻み込まれるようになりました。
3-2. 【教育心理UI】子どもの自尊心を傷つけない「UIサイレント適応ロジック」
大人は「今のレベルが難しすぎるなら、簡単なレベルに落としてあげよう」と親切心で考えがちです。
しかし、プライドが芽生え始めた小学2年生や小学4年生にとって、画面に「レベルを下げました」「かんたんモード」と表示されることは、屈辱以外の何物でもありません。
「僕、バカにされてるの……?」
そう感じた瞬間、子供の心はシャットダウンし、アプリを二度と開かなくなります。
まなびキッズでは、画面上の表記は常に「きょうの 10もん」という堂々たるタイトルを維持し続けます。
しかしその裏側では、直近の正答率スコアに応じて、出題される問題の難易度係数がサイレントに適応していきます。
【自尊心を傷つけないサイレント適応の仕組み】
・初期状態(スコア100):標準〜やや難しめの問題(挑戦意欲を刺激)
↓(3問連続で不正解が発生)
・適応状態(スコア80) :画面の見た目は一切変えずに、内部で基礎反復問題の比率を70%まで上昇
↓(スムーズに解けて笑顔が戻る)
・回復状態(スコア90) :成功体験を積み重ねたところで、再び標準難易度へ緩やかに復帰
子供から見れば、「今日も10問やり切った!」という達成感だけが残ります。挫折感を一切味わわせずに、裏側でそっと手すりを差し伸べる。これこそが、親でありエンジニアである私が込めた 愛あるUI設計 です。
3-3. 【ドーパミン演出】100点満点で画面いっぱいに広がる紙吹雪と効果音
子供のモチベーションを爆発させるために、クリア時の演出には徹底的にこだわりました。
単に「100点」という文字を表示するだけでは、子供の脳内にドーパミンは分泌されません。
全問正解を達成した瞬間、画面いっぱいにカラフルな紙吹雪が舞い散るcanvas-confettiライブラリを採用しました。
さらに、Web Audio APIを用いて、レトロゲームのファンファーレのような軽快な効果音を鳴り響かせます。
// 100点満点時の紙吹雪演出コンポーネント例
import confetti from 'canvas-confetti';
export const triggerFullScoreCelebration = () => {
// 左右からのダイナミックな紙吹雪発射
const count = 200;
const defaults = {
origin: { y: 0.7 },
zIndex: 9999,
};
function fire(particleRatio: number, opts: confetti.Options) {
confetti({
...defaults,
...opts,
particleCount: Math.floor(count * particleRatio),
});
}
// 複数の破片パターンで豪華さを演出
fire(0.25, { spread: 26, startVelocity: 55 });
fire(0.2, { spread: 60 });
fire(0.35, { spread: 100, decay: 0.91, scalar: 0.8 });
fire(0.1, { spread: 120, startVelocity: 25, decay: 0.92, scalar: 1.2 });
fire(0.1, { spread: 120, startVelocity: 45 });
};
この演出が入った瞬間、小2のひなたは「パパ見て!花火出た!」と飛び跳ねて喜びました。
「もう1回やって花火出す!」と、自分から次の10問に挑戦していく姿を見たとき、ゲームUIが持つポジティブな力の偉大さを痛感しました。
3-4. 【家庭内ガバナンス】掛け算認証ゲート付き保護者ダッシュボード
子供にタブレットを渡す際、最も心配なのが「子供が勝手に設定をいじってしまうこと」や「勉強の進捗をどう把握するか」です。
だからといって、子供の横にずっと張り付いて監視していては、親の時間が奪われてしまいます。
そこで、親だけが入れる 保護者ダッシュボード(管理画面) を構築し、入り口に 二重掛け算認証ゲート を設置しました。
【保護者ダッシュボードの二重掛け算ゲート】
┌──────────────────────────────────────────────┐
│ 🔒 ほごしゃのかたへ │
│ おとなの かたは けいさんを してください │
│ │
│ 【 17 × 8 = [ ] 】 │
│ │
│ ※九九の範囲を超える2桁掛け算で子供をブロック │
└──────────────────────────────────────────────┘
小2のひなたや年長のたいようには絶対に暗算できない「2桁×1桁」の掛け算をランダムに出題することで、パスワードを入力させる手間を省きつつ、子供の誤侵入を100%シャットアウトします。
この保護者ダッシュボードを開けば、以下のデータが一目で分かります。
- 子供ごとの日別の学習回数と総解答数
- 単元別(九九の各段、漢字の読み書き)の正答率ヒートマップ
- 翌日再テスト待ちになっている「苦手問題リスト」
「勉強やったの!?」とガミガミ怒鳴る必要はもうありません。キッチンで夕食の支度をしながら、手元のスマホでダッシュボードを開くだけで、「あ、ひなたが7の段をクリアしたな」「たいようが足し算を2回やったな」と静かに見守ることができるのです。
第4章:令和最強の完全無料エッジ技術スタック
ここからは、現役Webエンジニアの皆様に向けて、本作『まなびキッズ』を支える技術スタックの全貌を解説します。
個人開発において追求すべきは、 極限の表示速度と運用コスト0円(完全無料枠)の両立 です。
子ども向けのアプリでは、画面遷移で1秒待たされただけで離脱されます。また、家庭用の個人開発アプリに毎月数千円のサーバー代を払い続けるのは持続可能ではありません。
選んだのは、2026年現在における令和最強のエッジ構成です。
【まなびキッズの技術スタック一覧】
・フロントエンドフレームワーク: Astro 5(Islands Architecture)
・UIコンポーネントライブラリ : React 19
・CSSスタイリング : Tailwind CSS v4
・ホスティング基盤 : Cloudflare Pages
・エッジデータベース : Cloudflare D1(エッジ分散型サーバーレスSQLite)
・ORM (Object-Relational Map) : Drizzle ORM
・CI/CD パイプライン : GitHub Actions
4-1. なぜNext.jsではなくAstro 5なのか?
近年のWeb開発ではNext.js(App Router)がデファクトスタンダードのように扱われています。しかし、今回のプロジェクトにおいてNext.jsは採用しませんでした。理由は明確です。
- ゼロJavaScriptの圧倒的な軽さ: AstroはデフォルトでHTMLのみを出力し、動的なインタラクションが必要な部分だけをReactコンポーネントとして独立して動作させる(Islands Architecture)。
- エッジでのコールドスタート問題の皆無: Next.jsの重厚なランタイムに比べ、AstroはCloudflare Workers / Pages環境においてミリ秒単位の超高速レスポンスを叩き出します。
- コンテンツ主導の設計との親和性: 学年ごとの固定問題や解説データなど、静的にビルドできる部分が極めて多く、SSG(静的サイト生成)とSSR(エッジサーバーサイドレンダリング)のハイブリッドが最も自然に構築できる。
4-2. Cloudflare D1 + Drizzle ORMによるエッジデータベース
データベースには、Cloudflareが提供するエッジ分散型SQLiteである Cloudflare D1 を採用しました。
世界中のエッジロケーションに自動的にレプリケーションされ、東京リージョンからのアクセスであれば数ミリ秒でクエリが返ってきます。しかも、Cloudflareの無料枠(1日あたり500万行の読み込み、10万行の書き込み)は、家族4人で使う分には一生かかっても使い切れないほど潤沢です。
このD1を型安全に操作するために、最軽量のORMである Drizzle ORM を組み合わせました。
データベーススキーマ設計(schema.ts)
もちろん、このスキーマ定義も私が手作業でキーボードを叩いたものではありません。「子供3人とパパのユーザー管理、学年別の問題マスター、そして忘却曲線を管理する解答テーブルを作って。Cloudflare D1で動く最軽量の構成でお願い」と日本語で伝えただけで、Antigravityが型定義から外部キーのリレーションまで一瞬で自律生成したものです。
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
// ユーザー(子供たち+パパ)テーブル
export const users = sqliteTable('users', {
id: text('id').primaryKey(),
name: text('name').notNull(),
grade: text('grade').notNull(), // 'kindergarten' | 'grade2' | 'grade4' | 'father'
silentDifficultyScore: integer('silent_difficulty_score').default(100).notNull(),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
});
// 問題マスターテーブル
export const questions = sqliteTable('questions', {
id: text('id').primaryKey(),
category: text('category').notNull(), // 'math' | 'kanji' | 'it_strategist' | 'smec'
gradeLevel: text('grade_level').notNull(),
questionText: text('question_text').notNull(),
correctAnswer: text('correct_answer').notNull(),
optionsJson: text('options_json').notNull(), // 選択肢の配列(JSON)
difficultyLevel: integer('difficulty_level').default(1).notNull(), // 1〜5
});
// 解答履歴 & 忘却曲線管理テーブル
export const learningRecords = sqliteTable('learning_records', {
id: text('id').primaryKey(),
userId: text('user_id').notNull().references(() => users.id),
questionId: text('question_id').notNull().references(() => questions.id),
isCorrect: integer('is_correct', { mode: 'boolean' }).notNull(),
answeredAt: integer('answered_at', { mode: 'timestamp' }).notNull(),
// 記憶科学に基づく復習管理フラグ
isMastered: integer('is_mastered', { mode: 'boolean' }).default(false).notNull(),
nextReviewDate: text('next_review_date').notNull(), // 'YYYY-MM-DD'
reviewIntervalDays: integer('review_interval_days').default(1).notNull(),
});
4-3. 忘却曲線・翌日再テスト判定ロジックの実装
忘却曲線の判定ロジックも同様です。私が指示したのは「当日のやり直し正解はマスターと認めず、翌日以降のセッションで正解したときに初めてマスターに昇格させて」という自然言語だけ。それを受け取ったAntigravityが、以下のTypeScriptコードを一発で自律生成しました。
// 翌日再テスト判定ロジック(Spaced Retrieval Engine)
interface AnswerResult {
userId: string;
questionId: string;
isCorrect: boolean;
currentDateStr: string; // '2026-09-12'
}
export function calculateMemoryProgress(
previousRecord: {
answeredAt: Date;
isMastered: boolean;
reviewIntervalDays: number;
nextReviewDate: string;
} | null,
result: AnswerResult
) {
// 不正解の場合:即座にインターバルを1日にリセットし、未マスター化
if (!result.isCorrect) {
return {
isMastered: false,
reviewIntervalDays: 1,
nextReviewDate: getNextDateString(result.currentDateStr, 1),
};
}
// 初回正解の場合:翌日の再テストへ回す(同日ではマスターにしない)
if (!previousRecord) {
return {
isMastered: false,
reviewIntervalDays: 1,
nextReviewDate: getNextDateString(result.currentDateStr, 1),
};
}
const lastAnswerDateStr = previousRecord.answeredAt.toISOString().slice(0, 10);
// 【最重要】同日内のやり直し正解の場合:ステータスを進めない
if (lastAnswerDateStr === result.currentDateStr) {
return {
isMastered: previousRecord.isMastered,
reviewIntervalDays: previousRecord.reviewIntervalDays,
nextReviewDate: previousRecord.nextReviewDate,
};
}
// 翌日以降に想起できた場合:初めてインターバルを拡張し、長期記憶へ昇格!
const nextInterval = previousRecord.reviewIntervalDays * 2; // 1日 ➔ 2日 ➔ 4日 ➔ 8日
return {
isMastered: nextInterval >= 4, // 2回以上間隔を空けて想起できたらマスター
reviewIntervalDays: nextInterval,
nextReviewDate: getNextDateString(result.currentDateStr, nextInterval),
};
}
function getNextDateString(baseDateStr: string, addDays: number): string {
const d = new Date(baseDateStr);
d.setDate(d.getDate() + addDays);
return d.toISOString().slice(0, 10);
}
このわずか数十行のロジックが、子供たちの学習効率を劇的に引き上げます。「その場で解けたから満足」を仕組みとして許さず、忘れかけた未来の自分へパスを出す。これぞソフトウェアで教育をハックする醍醐味です。
4-4. GitHub Actionsによる完全自動CI/CD
開発したコードは、GitHubのmainブランチにプッシュするだけで、GitHub Actionsがトリガーされ、Cloudflare Pagesへと即座にエッジデプロイされます。
# .github/workflows/deploy.yml
name: Deploy to Cloudflare Pages
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
- name: Install Dependencies
run: npm ci
- name: Run Lint & Type Check
run: |
npm run lint
npx tsc --noEmit
- name: Build Astro Project
run: npm run build
- name: Deploy to Cloudflare Pages
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy dist --project-name=manabi-kids
夕食を食べ終わった後、子どもたちから「パパ、今日の漢字でこの問題の選択肢が分かりにくかった!」とフィードバックをもらったら、リビングのPCでサッと修正してGitプッシュ。
子供たちが歯を磨いている数十秒の間にCI/CDが走り、お風呂から上がる頃には本番環境に反映されている。このアジャイルな開発サイクルこそ、個人開発の最高の強みです。
第5章:実運用してわかった家庭内マネジメントの奇跡
まなびキッズをリビングに導入して1ヶ月。我が家の学習環境には、信じられないような奇跡的な変化が起きました。
5-1. 「パパ、今日の分やったよ!」に変わるまで
最も劇的な変化は、冒頭に書いた「勉強しなさい!」という私の怒鳴り声が、 我が家から完全に消え去ったこと です。
学校から帰ってくると、子供たちは自分からリビングのタブレットを手に取り、「きょうの 10もん」をサクサクと解き始めます。
満点を取って画面いっぱいに広がる紙吹雪を見てはガッツポーズをし、「パパ、今日の分もう終わったよ!」「明日の問題は何が出るかな?」と笑顔で報告してくるようになりました。
【まなびキッズ導入前後の比較】
❌ 導入前のリビング(親子の疲弊)
・親:「早く宿題やりなさい!」「いつまでダラダラしてるの!」
・子:ふてくされてノートに落書き、鉛筆を持ったままフリーズ
・結果:親も子もストレスMAXで夕食の空気が最悪に
⭕ 導入後のリビング(自律と共創)
・子:自分からタブレットを開いて10問クリア、紙吹雪で歓声
・親:スマホのダッシュボードで進捗を静かに確認して「すごいじゃん!」
・結果:パパも横でITストラテジストや中小企業診断士を勉強し、お互いを讃え合う空間に
机に向かって紙のドリルを開くことは「苦行」でしたが、タブレットで10問のゲームをクリアすることは「毎日の快感」へと変わったのです。
5-2. 子供たちからの容赦ないバグ報告とアジャイル改善
実際のユーザーである子どもたちは、世界で最も厳しいQA(品質保証)エンジニアでした。
- 小2のひなた:「パパ、ボタンを押したときの音がたまに遅れて聞こえる!」
- 年長のたいよう:「数字のボタンが小さくて、隣のボタンを押しちゃう!」
- 小4のそうた:「解説の文字が小さすぎて読む気がしない!」
大人のユーザーなら「まあ無料アプリだしな」と我慢してしまうような細かな違和感を、子どもたちは一切忖度せずに指摘してきます。
言われたその日の夜にAntigravityへ「ここが押しづらいからタップ領域を広げて」「解説の文字サイズを大きくして視認性を上げて」と日本語で指示を出し、数分で改善を本番デプロイ。翌朝「ほら、直したよ!」と見せると、子どもたちは「パパすごい!天才!」と目を輝かせます。
家族の役に立ち、目の前のユーザーが最高の笑顔を見せてくれる。
これ以上のエンジニア冥利に尽きる瞬間があるでしょうか。
5-3. AI時代、エンジニアの本当の価値とは何か?
Antigravityとまなびキッズを作り上げる過程で、私はエンジニアという職業の未来について深く考えさせられました。
コードを1行も書かずに、本番稼働するフルスタックアプリが完成してしまった という動かしがたい事実。
これはエンジニアにとって恐怖でしょうか? それとも絶望でしょうか?
私の答えは、圧倒的に 希望 です。
AIがどれほど高度に進化しても、AI自身が「うちの子が勉強嫌いで困っている」「塾代が高すぎる」「年長の子はひらがなが読めるから音声はいらない」と勝手に気づいてくれることはありません。
- 誰かの切実な痛みに気づくこと(「塾は高い」「勉強嫌いで机に向かわない」)
- 対象を深く観察して本質を見抜くこと(「年長児はひらがなを読めるから音声は不要」)
- 相手を思いやる愛を仕様に落とし込むこと(「自尊心を傷つけないサイレント適応」)
- 言葉にして伝え、AIと共に泥臭く解決し切ること (「こうしてほしい」「こういうのやって」)
エンジニアの真の価値は、「構文をキーボードでタイピングすること」から解放され、 大切な人の課題を発見し、愛を持って要件を定義し、自然言語で形にすること へと劇的にシフトしたのです。
AIは仕事を奪う敵ではありません。私たちの頭の中にある「身近な家族を幸せにしたい」という想いを、最も速く現実に変えてくれる最強のパートナーなのです。
まとめ:全体システムアーキテクチャ図とオープンな知の還元
最後に、今回構築した『まなびキッズ』の全体システムアーキテクチャをまとめます。
graph TB
subgraph Clients["マルチデバイス クライアント"]
C1["🐥 年長(タブレット)"]
C2["🌸 小2(タブレット)"]
C3["🚀 小4(タブレット)"]
C4["👨💼 パパ(PC / スマホ)"]
end
subgraph EdgePlatform["Cloudflare Edge Network"]
direction TB
Pages["Cloudflare Pages<br/>(Astro 5 + React 19 Islands)"]
D1["Cloudflare D1<br/>(サーバーレス 分散SQLite)"]
subgraph Logic["エッジ実行ロジック (TypeScript)"]
SR["Spaced Retrieval Engine<br/>(翌日再テスト忘却曲線判定)"]
SD["Silent Difficulty Engine<br/>(自尊心を傷つけない自動調整)"]
Auth["Parental Gate<br/>(2桁掛け算認証)"]
end
end
subgraph DevOps["自律開発 & CI/CD パイプライン"]
Dev["LEE (CEO / パパ)"] <-->|"対話型ペアプロ"| AG["Antigravity AI Agent"]
AG -->|"PR作成 & コミット"| GH["GitHub Repository"]
GH -->|"Actions CI/CD"| Pages
end
C1 & C2 & C3 & C4 -->|"ミリ秒レスポンス"| Pages
Pages --> Logic
Logic <-->|"Drizzle ORM"| D1
今回ご紹介した設計思想やコードは、特別な大企業にしかできないエンタープライズな技術ではありません。
すべて無料枠で使えるオープンなエッジ技術と、Googleの次世代AIエージェントであるAntigravity、そして「子どもたちを笑顔にしたい」というパパの情熱があれば、誰でも今週末に立ち上げることができる仕組みです。
もし、ご家庭で子どもの勉強嫌いや高額な教育費に悩んでいるパパママエンジニアの方がいらっしゃいましたら、ぜひ「AIと自分専用の学習アプリを作る」という選択肢に挑戦してみてください。
リビングの景色が、そして家族との会話が、明日から劇的に変わるはずです。
著者プロフィール
LEE
インフラエンジニア / PMP®(Project Management Professional) / 情報処理安全確保支援士 / ネットワークスペシャリスト。
30代未経験からIT業界に飛び込み、現場での大規模インフラ運用・セキュリティガバナンスに従事する傍ら、自宅サーバ運用記(https://jetree.work/)にて自律型AI組織「MyOffice」の運営知見や高度IT資格の最短攻略ノウハウをオープンに発信中。3児の父。
LEE
SIチーム管理職
2024年よりSIチームの管理職に従事。技術とマネジメントの両立をモットーに、現場のリアルな知見を発信しています。趣味は車とガジェット。