はじめに
このアプリのアイデアは2020年、日本に住んでいたときに生まれました。日本語を勉強しながら「こんな学習アプリがあったらいいな」と思って、メモを作っていました。でも、そこから3年半、仕事や勉強で忙しくて、あまり作る時間がありませんでした。リポジトリだけ作って、何もしないでいた、ということが何度もありました。
日本を出たあとも、そのアイデアはずっと頭に残っていました。そして2026年、AIを使った開発(Claude Codeなど)を本気で始めてから、やっと少しずつ形になっていきました。自分の感覚では「一緒に考えてくれるパートナーができた」ような感じで、6年間止まっていたプロジェクトを、ついに人が使えるところまで進めることができました。
この記事では、日本語マスター(Nihongo Master)というプロジェクトで、どんな技術を使ったかを、ソースコードは見せずに、図と表で紹介します。個人でバックエンド・Web・モバイル・管理画面・インフラまで全部作ったので、技術を選ぶときの参考になったらうれしいです。
日本語を勉強している人のためのアプリです。漢字と文法をSRS(くり返し復習する方法)で復習しながら、リスニング問題や模擬試験(N5〜N1)もできます。
プロジェクト全体像
個人で作っていますが、役割ごとにリポジトリを分けています。
| リポジトリ | 役割 |
|---|---|
nihongo-master-backend |
REST API(Spring Boot) |
nihongo-master-frontend |
学習者向けWebアプリ(React) |
nihongo-master-app |
モバイルアプリ(Expo / React Native) |
nihongo-master-admin |
管理画面(React) |
nihongo-master-infra |
AWSデプロイ(CloudFormation) |
3つのアプリ(Web、モバイル、管理画面)は、同じバックエンドAPIを使っています。認証やロジックが違うアプリでバラバラにならないように、あとで紹介する「共通のレイヤードアーキテクチャ」で作り方を揃えています。
バックエンド:Spring Boot + DDD + TDD
| 項目 | 採用技術 |
|---|---|
| 言語 / フレームワーク | Java 21, Spring Boot 3.3, Maven |
| 認証 | Spring Security + JWT(jjwt) |
| DB | PostgreSQL 16 + Flyway(マイグレーション管理) |
| キャッシュ / トークンストア | Redis 7 |
| オブジェクトストレージ | S3(本番)/ MinIO(ローカル、S3互換) |
| メール送信 | Amazon SES |
| API仕様 | springdoc-openapi(Swagger UI) |
| テスト | JUnit + Spring Security Test + H2(DB) |
| 品質管理 | JaCoCo(カバレッジ), Spotless(フォーマット) |
設計するときは、DDD(ドメイン駆動設計)とTDD(テスト駆動開発)を意識しています。今は、マイグレーションファイルが36個、テストファイルが43個あります。
認証:JWTのアクセス/リフレッシュをRedisでローテーション
アクセストークンは15分、リフレッシュトークンは7日だけ使えるようにしています。そして、リフレッシュするたびに、Redisの中の古いトークンを捨てて、新しいトークンに変えています(ローテーション)。こうすると、もし誰かにリフレッシュトークンを盗まれても、それがまた使われたときに気づきやすくなります。
共通アーキテクチャ:Web / モバイル / 管理画面
3つのフロントエンド(学習者用Web、モバイル、管理画面)は、同じレイヤーの作り方をしています。React RouterとExpo Router、localStorageとexpo-secure-storeのように、使っているものは少し違いますが、ロジックを置く場所は同じにしています。だから、仕様を変えるときに「こっちには直したけど、あっちは直し忘れた」というミスを減らせます。
| リポジトリ | スタック |
|---|---|
| Web(学習者向け) | React 19, Vite, TypeScript, TanStack Query, Zustand, React Router v7, Tailwind CSS v4, React Hook Form + Zod |
| 管理画面 | 上と同じスタック + TanStack Table, Recharts(グラフ表示) |
| モバイル | Expo SDK 57, Expo Router, NativeWind(Tailwind for RN), Zustand, TanStack Query, React Hook Form + Zod |
Web版は漢字の書き順アニメーションにkanjivg-jsを使っていて、モバイル版は@jamsch/react-native-hanzi-writerを使っています。ライブラリはプラットフォームごとに違いますが、見た目や動きはできるだけ同じになるようにしています。
学習者向けに実装している機能
- 漢字学習:レベル別(N5〜N1)の一覧、めくれるフラッシュカード、書き順のアニメーション、SRS(くり返し復習)で答えを送る機能
- 文法学習:レベル別の一覧、例文つきの詳しい説明、SRSで答えを送る機能
- リスニング:レベル別の一覧、音声プレイヤー、今どこを話しているか分かるトランスクリプトのハイライト、選択式の問題
- 進捗ダッシュボード:XP(経験値)、連続で勉強した日数(ストリーク)、今日復習する数、レベルごとの進み具合
- 模擬試験(プレミアム機能):レベルを選ぶ、時間制限があるテスト(セクションごとにタブで分かれている)、セクションごとの結果、これまでの記録
- 課金:プランを比べる画面、購入したものを元に戻す機能、サブスクリプションの設定画面
モバイルアプリだけの機能
Webにはない、ネイティブならではの機能もいくつか作っています。
| 機能 | 使用技術 |
|---|---|
| 生体認証ロック | expo-local-authentication |
| プッシュ通知 | expo-notifications |
| アプリ内課金 / サブスク |
react-native-purchases(RevenueCat) |
| 通信のSSLピンニング | react-native-ssl-public-key-pinning |
| クラッシュ / エラー監視 | Sentry |
| OTAアップデート | JSやアセットだけならすぐに配信できる。ネイティブの部分を変えたときは、いつも通りストアの審査が必要 |
サブスクリプションの流れ(RevenueCat Webhook)
購入は、モバイルのストア決済(App StoreかGoogle Play)だけでできます。Web版には、独自の決済機能はありません。RevenueCatからWebhookが送られてきたら、バックエンドが署名を確認して、それからサブスクの状態をDBに保存します。
インフラ:CloudFormationで5つの独立スタックにデプロイ
インフラだけ別のリポジトリ(nihongo-master-infra)に分けています。GitHub Actions(workflow_dispatch、手動で動かすトリガー)から、他の4つのリポジトリを取ってきて、ビルドしてデプロイする仕組みです。
大きな1つのスタックにまとめないで、5つの独立したスタックを順番にデプロイする方法を選びました。理由は、デプロイが途中で失敗しても(多いのはECSやALBのヘルスチェックの問題です)、失敗したスタックだけをロールバックできるからです。もうできているRDSやVPC、フロントエンドには影響しません。
工夫している点をいくつか挙げます。
- ECRを先にデプロイする:ECSサービスを作る前に、イメージを置く場所と最初のイメージを用意しておきます。そうすると、「イメージがなくて先に進めなくなる」ことを防げます
-
DeploymentCircuitBreakerを使う:ECSのデプロイがうまくいかないとき、何度もリトライさせないで、早めに失敗させます - GitHub ActionsからAWSへOIDCでつなぐ:長い間使えるAWSのアクセスキーを、GitHub Secretsに置かなくてすみます
- バックエンド:ECS Fargate(内部ALB)+ API Gateway(HTTP API)
- DB / キャッシュ:RDS PostgreSQL 16 + ElastiCache Redis 7
- フロントエンドの配信:S3 + CloudFront(学習者Web / 管理画面それぞれ)
- モバイルのビルド:Expo EAS Build(同じワークフローからビルドだけできる。ストアへの申請はまだつなげていない)
CloudFormationのテンプレートは、全部で12個あります(ネットワーク、データ、シークレット、ACM×2、バックエンド、ECR、API Gateway、フロントエンド、SES、DNS×2、GitHub OIDC)。
数字で見るプロジェクト
| 指標 | 値 |
|---|---|
| リポジトリ数 | 5 |
| 総コミット数(全リポジトリの合計) | 172 |
| DBマイグレーション数 | 36 |
| バックエンドのテストファイル数 | 43 |
| CloudFormationテンプレート数 | 12 |
| アイデアからリリースまでの期間 | 約6年(2020年〜2026年) |
おわりに
技術としては「よくあるWeb + モバイル + 管理画面 + REST API + AWS」という組み合わせです。でも、これだけの範囲を一人で(しかも仕事をしながら)作れたのは、AIを使った開発があったからだと思います。特に、いろいろなリポジトリで考え方を同じにすること(3つのアプリで同じレイヤーの作り方にする、JWTのローテーションの方法を決める、デプロイの失敗をできるだけ小さくするなど)を、AIと話しながら決められたのが大きかったです。
2020年に日本で「こんなアプリが欲しい」と思ってから6年たちましたが、やっと自分でも使えるところまで来ました。同じように「作りたいものはあるけど時間がない」という人の参考になればうれしいです。