{"id":31669285,"url":"https://github.com/susatthi/github-search","last_synced_at":"2025-10-08T01:21:43.791Z","repository":{"id":36985193,"uuid":"472553415","full_name":"susatthi/github-search","owner":"susatthi","description":"GitHub API を利用して GitHub のリポジトリを検索するアプリです。株式会社ゆめみのFlutterエンジニアコードチェックの要件を満たすよう実装しています。","archived":false,"fork":false,"pushed_at":"2023-10-11T01:16:23.000Z","size":33171,"stargazers_count":199,"open_issues_count":8,"forks_count":6,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2023-10-11T05:13:23.301Z","etag":null,"topics":["dart","flutter"],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/susatthi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2022-03-22T00:01:16.000Z","updated_at":"2023-09-29T17:03:43.000Z","dependencies_parsed_at":"2023-02-16T02:45:52.728Z","dependency_job_id":null,"html_url":"https://github.com/susatthi/github-search","commit_stats":null,"previous_names":[],"tags_count":4,"template":null,"template_full_name":null,"purl":"pkg:github/susatthi/github-search","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/susatthi%2Fgithub-search","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/susatthi%2Fgithub-search/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/susatthi%2Fgithub-search/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/susatthi%2Fgithub-search/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/susatthi","download_url":"https://codeload.github.com/susatthi/github-search/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/susatthi%2Fgithub-search/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278874850,"owners_count":26061054,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-07T02:00:06.786Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dart","flutter"],"created_at":"2025-10-08T01:21:42.457Z","updated_at":"2025-10-08T01:21:43.786Z","avatar_url":"https://github.com/susatthi.png","language":"Dart","funding_links":[],"categories":["Dart"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003ca href=\"https://github.com/susatthi/github-search/actions/workflows/flutter_ci.yaml\"\u003e\u003cimg src=\"https://github.com/susatthi/github-search/actions/workflows/flutter_ci.yaml/badge.svg\" alt=\"Flutter CI\"\u003e\u003c/a\u003e\n\u003ca href=\"https://codecov.io/gh/susatthi/github-search\"\u003e\u003cimg src=\"https://codecov.io/gh/susatthi/github-search/branch/develop/graph/badge.svg?token=C48OG86U8O\" alt=\"codecov\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-purple\" alt=\"MIT\"\u003e\u003c/a\u003e\n\u003cimg width=\"100%\" src=\"https://user-images.githubusercontent.com/13707135/165474118-d7a43467-7e8e-4dc7-9aed-2e1dd1456ea6.png\"\u003e\n\u003c/p\u003e\n\n# GitHub Search\n\n\u003e **:warning: 制限事項**  \n\u003e - 現在 Web 版がビルドできません。Isar 3.0.2 が Web をサポートしなくなったためです。詳細は [Issue](https://github.com/isar/isar/issues/686) をご参照ください。\n\u003e - 現在テストが通りません。ディレクトリ構造を変更したことにテストが追従できていません。対応中です。\n\n[GitHub API](https://docs.github.com/ja/rest) を利用して GitHub のリポジトリを検索するアプリです。[株式会社ゆめみのFlutterエンジニアコードチェック](https://github.com/yumemi-inc/flutter-engineer-codecheck)の要件を満たすよう実装しています。\n\n本アプリを通して自分なりの最適なアーキテクチャを確立し、リファレンスコードにすることを目的にしています。\n\n\u003e **:warning: 注意**  \n\u003e このアプリは `GitHub API` を利用するために GitHub の `アクセストークン` をアプリの内部でハードコーディングして保持する構成になっています。このアプリを公開すると悪意のある者に `アクセストークン` を抜き取られ悪用される恐れがありますのでお控え下さい。もちろん、手元でビルドして動かすことは問題ありません。\n\n一覧(Light)|一覧(Dark)\n--|--\n![index-light](https://user-images.githubusercontent.com/13707135/183786156-c6506906-9eb1-419f-8466-fdbe907934f7.png)|![index-dark](https://user-images.githubusercontent.com/13707135/183786212-11334663-f095-4a22-a98a-13a4b5dde6c1.png)\n\nデスクトップ|タブレット\n--|--\n![desktop](https://user-images.githubusercontent.com/13707135/183787423-b404c9d3-e1e6-4c57-bd96-4e4c5c06703a.png)|![tablet](https://user-images.githubusercontent.com/13707135/183787582-86eabebc-7d99-4961-ad6c-70c75f299725.png)\n\n\n詳細|0件|エラー\n--|--|--\n![view](https://user-images.githubusercontent.com/13707135/183786405-5f925803-83ad-4066-a01e-f903d2b45148.png)|![empty](https://user-images.githubusercontent.com/13707135/183786643-bca0977e-f6e6-4a8c-a651-2a150163de07.png)|![error](https://user-images.githubusercontent.com/13707135/183786950-221a389c-8613-4b1d-8755-726f9b71654f.png)\n\n![github_search_0_9_0_demo](https://user-images.githubusercontent.com/13707135/172117146-22d5f5b2-5e90-4d09-8060-8c1976b2b42a.gif)\n\n\n## ビルド方法\n\n#### ソースコードを clone\n  \n```bash\ngit clone https://github.com/susatthi/github-search.git\n```\n\n#### GitHub の個人アクセストークンを取得\n\n本アプリで使用する GitHub の[個人アクセストークン](https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)を取得して、カレントディレクトリで次のコマンドを実行してください。\n\n```bash\n# 引数で与えられた環境変数を基にビルドに必要な `lib/util/env/env.dart` を作成してくれます。\n# 作成された `lib/util/env/env.dart` を直接編集しても大丈夫です。\n\nbin/flutter_env -g [GitHub 個人アクセストークン] -s [検索文字列の初期値]\n```\n\n|パラメータ                     |          |説明                                                       |\n|-----------------------------|----------|----------------------------------------------------------|\n|`-g`                         |`Must`    |値には [GitHub 個人アクセストークン](https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) を設定してください。|\n|`-s`                         |`Optional`|値には好きな文字列を設定してください。指定しない場合は空文字が設定されます。|\n|`-h`                         |          |ヘルプを表示します。                                          |\n\n#### ビルド\n\nConfigurations を選択してビルドしてください。\n\n|Configurations 名 |説明                       |\n|------------------|--------------------------|\n|`app-debug`       |アプリ向けデバッグビルド      |\n|`app-release`     |アプリ向けリリースビルド      |\n|`web-debug`       |Web 向けデバッグビルド       |\n|`web-release`     |Web 向けリリースビルド       |\n\n## 技術スタック\n\n- アプリの機能\n  - GitHub リポジトリの検索と詳細表示\n  - 検索結果の並び替えと [hive](https://pub.dev/packages/hive) を使ったデータの永続化\n  - Sliver を使った無限スクロール対応\n  - [isar](https://isar.dev/) を使った検索履歴の保存とサジェスト\n- [go_router](https://pub.dev/packages/go_router) と [go_router_builder](https://pub.dev/packages/go_router_builder) を使ったルーティング\n- [http](https://pub.dev/packages/http) を使った REST API の実装\n- [fast_i18n](https://pub.dev/packages/fast_i18n) を使った多言語対応（日本語/英語）\n- カスタムフォント対応\n- [mocktail](https://pub.dev/packages/mocktail) を使った Unit / Widget テスト\n- [flutter_launcher_icons](https://pub.dev/packages/flutter_launcher_icons) を使ったアプリアイコン\n- [flutter_native_splash](https://pub.dev/packages/flutter_native_splash) を使ったスプラッシュ画面\n- [responsive_framework](https://pub.dev/packages/responsive_framework) を使ったレスポンシブ対応\n- [GitHub Actions](https://github.co.jp/features/actions) によるCI(自動テストと自動ビルド)\n- ダークモード対応\n- サポートするプラットフォーム\n  - iOS / Android / Web / macOS / Windows\n\n### 今後対応予定\n\n- Integration テスト\n- Riverpod 2 対応\n\n### 対応しないこと\n\n- Firebase 連携\n- Flavor 対応（develop / staging / production などの環境分け）\n\n## アーキテクチャ / パッケージ\n\n- [flutter_riverpod](https://pub.dev/packages/flutter_riverpod) + [go_router](https://pub.dev/packages/go_router)\n- [CODE WITH ANDREA](https://codewithandrea.com/articles/flutter-app-architecture-riverpod-introduction/) と [DDD](https://little-hands.hatenablog.com/entry/2018/12/10/ddd-architecture) のアーキテクチャを参考にして、本アプリは下記の３層アーキテクチャで実装しています。\n\n![アーキテクチャ図](https://user-images.githubusercontent.com/13707135/200081763-c2809366-046d-4a82-8367-9bee5a751b90.png)\n\n### Presentation 層\n\nユーザーとの I/F を担う層。Application 層と Domain 層に依存する。Infrastructure 層に依存してはいけない。\n\n#### Widget\n\nページや UI 部品の Widget クラス群。State を監視（ watch / listen ）して UI に表現する。ユーザーイベントを検知して Service のメソッドを呼び出す。キャッシュが効かなくなるので直接 Repository Interface を呼び出してはいけない。画面遷移の実装は Widget のイベントハンドラー内で行ってよい。\n\n#### Application 層\n\nアプリケーションのロジックや状態を定義する層。Domain 層に依存する。Presentation 層と Infrastructure 層に依存してはいけない。\n\n#### State\n\nアプリのあらゆる状態。Domain 層の Entity そのものでもよいし、複数の Repository をまたいだ Entity を統合するクラスでもよい。State は `StateProvider` 等でラップされ Widget や他の State から参照される。\n\n#### Service\n\nユーザーイベントを受け付けて、複数の Repository Interface を呼び出して Entity を受け取って State を更新するサービスクラス。Widget からのメソッド呼び出しや、依存する State の更新を契機に発火する。\n\n### Domain 層\n\nドメインロジックやドメインオブジェクト（エンティティ）を定義する層。どの層にも依存してはいけない。\n\n#### Entity\n\nRepository Interface で扱うドメインオブジェクト（データの構造体）。入力値のバリデーションは Entity のコンストラクタで実装する。Infrastructure 層が投げる例外はドメイン層で定義する。\n\n#### Repository Interface\n\nデータの永続化や外部サービス連携を担う Repository のインターフェース。集約毎に定義する。\n\n### Infrastructure 層\n\nデータの永続化や外部サービス連携を担う層。Domain 層に依存する。Presentation 層と Application 層に依存してはいけない。\n\n#### Repository Implements\n\nRepository Interface の実装。Data Source を利用してデータの永続化を行う。\n\n#### Data Source\n\n様々なデータソース。Firebase だったり、API だったり、Hive だったり、SharedPreferences だったり、Isar だったりする。\n\n## フォルダ構成\n\n```  \n├── application                              アプリケーション層\n│   └── \u003c関心事\u003e\n│       ├── \u003cstate\u003e                          状態クラス群\n│       └── \u003c関心事\u003e_service.dart             サービスクラス\n├── domain                                   ドメイン層\n│   ├── exceptions.dart                      例外クラス\n│   └── repository\n│       └── \u003c集約\u003e\n│           ├── \u003c集約\u003e_repository.dart        リポジトリのインターフェースクラス\n│           └── entity                       集約単位のエンティティ\n├── infrastructure                           インフラストラクチャ層\n│   └── \u003cデータソース\u003e\n│       └── \u003c集約\u003e\n│           └── \u003c集約\u003e_repository.dart       リポジトリの実装\n├── presentation\n│   ├── app.dart                             アプリケーション\n│   ├── router.dart                          ルーティング\n│   ├── theme.dart                           テーマ\n│   ├── component                            プレゼンテーション層で共通の Widget\n│   └── page\n│       └── \u003c関心事\u003e\n│           ├── component                    画面単位の Widget\n│           └── \u003c関心事\u003e_\u003cCURD\u003epage.dart      画面Widget\n└── util                                     どの層からもアクセス可能な便利クラス（ロガー、拡張メソッドなど）\n```\n\n### ファイル分割の方針\n\n基本的に **関心事** 毎にファイルを分割しています。例えば、Controller と State を別々のファイルに分けることはしません。ファイル名は **関心事.dart** とします。ファイル名 = クラス名とはしません。\n\n## 環境\n\n|                | Version                          |\n|----------------|----------------------------------|\n| Flutter        | 3.3.10                           |\n| Dart           | 2.18.6                           |\n\n### コードの自動生成\n\n- `util/localization/*.json` ファイルを変更した場合や `freezed` を使った `dart` ファイルを変更した場合は次のコマンドを実行してください。\n\n```bash\nmake build-runner\n```\n\n### 単体テスト（UnitTest / WidgetTest）\n\n- ローカルで単体テストを行うためには事前に次のライブラリをインストールしてください。\n\n```bash\n# lcov のインストール\nbrew install lcov\n\n# dart_dot_reporter のインストール\nflutter pub global activate dart_dot_reporter\n```\n\n- 次のコマンドで単体テスト（静的解析 =\u003e テスト =\u003e カバレッジの結果を表示 ）を実行します。\n\n```bash\n# 言語設定が英語のテスト\nmake test-en\n\n# 言語設定が日本語のテスト\nmake test-ja\n```\n\n### API ドキュメント\n\n- [API ドキュメント](https://susatthi.github.io/github-search/) で公開しています。\n\n- 生成する場合は次のコマンドを実行してください。\n\n```bash\nmake dartdoc\n```\n\n## CI\n\n- [GitHub Actions](https://github.co.jp/features/actions) を利用して CI を構築しています。\n  - プルリクエストが作成や更新された時、もしくは `main` または `develop` ブランチに `push` されたときに CI が発火します。\n\n```mermaid\n%%{init:{'theme':'base','themeVariables':{'primaryColor':'#f0f0f0','primaryTextColor':'#2f2f2f', 'lineColor':'#2f2f2f','textColor':'#2f2f2f','fontSize':'16px','nodeBorder':'0px'}}}%%\nflowchart LR\n    Start((開始)) --\u003e AnalyzeUbuntu(Ubuntu静的解析)\n    Start --\u003e AnalyzeMacosEn(macOS英語静的解析)\n    Start --\u003e AnalyzeMacosJp(macOS日本語静的解析)\n    Start --\u003e AnalyzeWindows(Windows静的解析)\n    Start --\u003e BuildAndroid(Androidビルド)\n    Start --\u003e BuildiOS(iOSビルド)\n    Start --\u003e BuildWeb(Webビルド)\n    Start --\u003e BuildMacOS(macOSビルド)\n    Start --\u003e BuildWindows(Windowsビルド)\n\n    AnalyzeUbuntu ---\u003e TestUbuntu(Ubuntu単体テスト)\n    AnalyzeMacosEn ---\u003e TestMacosEn(macOS英語単体テスト)\n    AnalyzeMacosJp --\u003e TestMacosJp(macOS日本語単体テスト)\n    TestMacosJp --\u003e UploadCoverageMacosJp(Codecovに結果を送信)\n    AnalyzeWindows ---\u003e TestWindows(Windows単体テスト)\n    UploadCoverageMacosJp --\u003e NotifySlack(Slackに結果を送信)\n    TestUbuntu --\u003e NotifySlack\n    TestMacosEn --\u003e NotifySlack\n    TestWindows --\u003e NotifySlack\n    BuildAndroid ----\u003e NotifySlack\n    BuildiOS ----\u003e NotifySlack\n    BuildWeb ----\u003e NotifySlack\n    BuildMacOS ----\u003e NotifySlack\n    BuildWindows ----\u003e NotifySlack\n    NotifySlack --\u003e End((終了))\n\n    classDef anchor fill:#4063DD, color:#ffffff;\n    classDef testJob fill:#4063DD, color:#ffffff;\n    classDef buildJob fill:#d32f2f, color:#ffffff;\n    classDef reportJob fill:#437C40, color:#ffffff;\n    %% class Start,End anchor;\n    class AnalyzeUbuntu,TestUbuntu,UploadCoverageMacosJp,AnalyzeMacosEn,AnalyzeMacosJp,TestMacosEn,TestMacosJp,AnalyzeWindows,TestWindows testJob;\n    class BuildAndroid,BuildiOS,BuildWeb,BuildMacOS,BuildWindows,CreateApiDoc,DeployGitHubPages buildJob;\n    class NotifySlack reportJob;\n```\n\n## ライセンス\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsusatthi%2Fgithub-search","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsusatthi%2Fgithub-search","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsusatthi%2Fgithub-search/lists"}