従業員と共にPraLoopというスマホアプリを、iOS/Android向けに開発/リリースしました。
本記事では、PraLoopで使用している技術スタックについて紹介したいと思います。
概要
リポジトリはモノレポ構成で、主なディレクトリは次のように分かれています。
- `mobile/`: Flutter 製のモバイルアプリ
- `api/`: Go 製のバックエンド API
- `deploy/`: Ansible、Terraform、デプロイスクリプト
- `web/`: 公式サイト、ヘルプページなどの Web 側実装
- `.github/workflows/`: mobile,api,webのCI/CD
- `docs`/: Claude Code, CodexでSDDができるように、仕様や開発時のガードレールなどのルールを記載以降、それぞれ解説していきます。
moible(Flutter)
mobileで使用している技術スタックは以下となります。
| 領域 | 技術 |
|---|---|
| フレームワーク | Flutter |
| 言語 | Dart |
| 状態管理 | Riverpod 3、hooks_riverpod |
| コード生成 | riverpod_generator、freezed、json_serializable、build_runner |
| アーキテクチャ | DDD / Onion Architecture 風のレイヤードアーキテクチャ |
| アーキテクチャ検証 | import_lint |
| ルーティング | go_router |
| ローカル DB | Drift / SQLite |
| 課金 | in_app_purchase、in_app_purchase_android、in_app_purchase_storekit |
| 認証 | google_sign_in、sign_in_with_apple、flutter_secure_storage |
| 通知 | flutter_local_notifications、timezone、flutter_timezone |
| 監視 | sentry_flutter |
ポイントとしては、保守性を考慮し、メジャーかつメンテナンスされているパッケージを選んだのと、レイヤードアーキテクチャを用い、import_lint により、CIのlinterで依存方向違反を自動で検知できるようにしたところです。
Claude CodeやCodexに指示を出す際、 AGENTS.md にルールを詰め込みすぎると、コンテキストを圧迫し、トークン消費の向上や推論レベルの低下が起き得るため、コードの書き方などのルールはlinterやskillsで担保するようにしていました。
modile配下のディレクトリ構成は以下となります。
- `presentation/`: UI、ViewModel、State
- `application/`: ユースケース、DTO、アプリケーション固有のワークフロー
- `domain/`: エンティティ、Repository interface、値オブジェクト、ドメインルール
- `infrastructure/`: Repository の具象実装、Drift / SQLite、外部 API、端末機能
- `core/`: ユーティリティ、エラー、i18n、Dependency InjectionAPI(Golang)
APIで使用している技術スタックは以下となります。
| 領域 | 技術 |
|---|---|
| 言語 | Go 1.25 |
| HTTP フレームワーク | Gin |
| アーキテクチャ | DDD / Onion Architecture |
| API スキーマ | OpenAPI |
| 型生成 | oapi-codegen |
| DB | MySQL |
| SQL 生成 | sqlc |
| マイグレーション | Atlas |
| 認証 | JWT、OIDC、メール認証 |
| バリデーション | go-playground/validator/v10 |
| メール送信 | gomail |
| キャッシュ / PubSub | Redis / Valkey |
| 多言語対応 | go-i18n |
| 監視 | Sentry |
| Lint / アーキテクチャ検証 | golangci-lint、depguard、errcheck、govet、staticcheck |
API 側でも、mobile と同じく各レイヤーの境界は linter で守っています。api/.golangci.yml では golangci-lint の depguard を使い、外部からの依存方向がドメインに対し一直線となるようにCIのlinterで制御しています。
また、OpenAPI を用い、oapi-codegen で型とインターフェースを生成しています。
これにより、仕様書を書くだけで一通り必要なコードが自動で出力されるため、開発者やAIによって実装がバラバラという問題がなくなりました。
api配下のディレクトリ構成は以下となります。
- `cmd/api/`: API サーバーのエントリーポイント
- `internal/presentation/`: HTTP handler、middleware、OpenAPI generated schema
- `internal/application/`: 認証、同期、課金などのユースケース
- `internal/domain/`: ユーザー、認証セッション、同期モデルなどのドメイン
- `internal/infrastructure/`: DB、repository、JWT、OIDC、Redis、Google Play、App Store などの具象実装
- `internal/core/`: 設定や横断的な処理
- `sql/`: schema、migration、sqlc query
- `openapi/`: OpenAPI 定義Infrastructure
Infrastructure(deploy/ 配下)で使用している技術スタックは以下となります。
| 領域 | 技術 |
|---|---|
| 構成管理 | Ansible |
| IaC | Terraform |
| コンテナ | Docker |
| API デプロイ | Kamal 2、GHCR、Kamal proxy |
| デプロイ実行基盤 | GitHub Actions、self-hosted runner |
| デプロイ方式 | Kamal proxy によるゼロダウンタイムデプロイ |
| 監視 | Datadog Agent、Sentry、Cloudflare |
ネットワーク図は以下となります。現状、単一ホストですが、負荷に応じて水平スケールする構成としております。

まだ、リリースしたばかりで、トラフィックも少ないため問題ありませんが、ゆくゆくはAPIサーバーの冗長化、DBのリードレプリカ追加、各サーバーの垂直スケーリングなども行う想定です。
また、ネットワーク図を見るとお分かりの通り、CI/CDパイプラインによるデプロイフローの自動化を行っております。
具体的には、GitHub Actionsにより、linter/testが通ったブランチがmasterブランチにマージされると、自動でwebディレクトリの内容がデプロイされます。APIに関しては、DBマイグレーションなどの関係から手動でworkflowを実行するフローとなっています。

実は、mobileに関してもローカルでのスクリプト実行ではありますが、以下を自動化しております。
- スクショからApp Store/Google Play用の画像生成
- アプリ紹介文の自動多言語翻訳
- 生成された↑の画像/テキストのApp Store/Google Playへの反映
これについては、別途記事をかければと思ってます。
終わりに
以上、簡単ではありますが、PraLoopを支えている技術スタックの紹介でした。
PraLoop は、動画や音楽、YouTubeの特定の箇所を繰り返し再生出来るアプリです。
僕自身、ギターのTab譜動画や、ピアノの上から弾く場所が流れてくる動画を見て楽器を練習しており、速度再生や、繰り返し特定の箇所を再生できたら嬉しいなというニーズがあり、開発しました。
便利だと思いますので、同じようなニーズがある方はぜひ、DLしてみて頂ければと思います。
また、今後、各技術を掘り下げて紹介する記事も書いていければと考えておりますので、よければそちらも見て頂けると嬉しいです。

