狐好きぷろぐらまー

狐好きプログラマーのブログです。

スマホからClaude Codeを操作する - happy-coderでブログ執筆が快適に

はじめに

「外出先でもブログを書きたい」「ちょっとした空き時間にコードレビューをしたい」

そんな願望を持ったことはありませんか?

実は、happy-coderを使えば、スマホだけでClaude Codeを操作して、本格的な開発作業ができるんです。しかも、追加のツールなしで。

この記事では、happy-coderを使ってスマホからClaude Codeを操作する方法と、実際にこの記事を含む2つの記事をスマホだけで執筆した体験をご紹介します。

既存の方法との違い

スマホからClaude Codeを操作する方法としては、こちらのZenn記事で紹介されているように、Tailscale + Termiusを組み合わせる方法が知られています。

この方法も素晴らしいのですが、以下のような準備が必要です:

  • Tailscaleのインストールと設定
  • SSHリモートログインの有効化
  • Termiusアプリの設定
  • PCを常時稼働させる必要がある

一方、happy-coderを使う方法は:

happy-coderをインストールするだけスマホQRコードを読み込むだけで接続完了PCの常時稼働不要追加のVPN設定不要

と、圧倒的に手軽です。

happy-coder とは

happy-coderは、Claude Codeをスマホから操作できるツールです。

主な特徴: - ブラウザからClaude Codeを操作可能 - スマホからでも快適に使える専用UI - Yes/No/Elseの選択がタップ操作で可能 - コマンド入力も音声入力やフリック入力で快適

セットアップ方法

1. PC側: happy-coder のインストール

npm install -g happy-coder

要件: Node.js 18以上が必要です。

2. スマホ側: アプリをインストール

スマホに専用アプリをインストールします:

  • iOS: App Storeで「Happy Claude Code Client」を検索してインストール
  • Android: Google Playで「Happy Claude Code Client」を検索してインストール
  • Web版: app.happy.engineering にアクセス

3. QRコードで認証

PC側で以下を実行してQRコードを表示:

happy --auth

すると、ターミナルにQRコードが表示されます。

スマホ側で接続: 1. インストールしたHappyアプリを起動 2. PC画面に表示されたQRコードスマホで読み込む 3. これだけで接続完了!

一度認証すれば、次回からはhappyコマンドだけで起動できます。

スマホでの操作感

タップ操作で選択肢を選べる

happy-coderの最大の特徴は、Claude Codeからの選択肢(Yes/No/Else)をタップ操作で選べることです。

従来のターミナルベースだと: 1. キーボードでyesと入力 2. Enterキーを押す

という手順が必要でしたが、happy-coderなら:

  1. 画面に表示されたボタンをタップするだけ

これがスマホでの作業効率を劇的に改善します。

音声入力との相性抜群

スマホの音声入力機能を使えば、長文のプロンプトも快適に入力できます:

  1. 入力欄をタップ
  2. 音声入力ボタンをタップ
  3. 話しかける
  4. 送信ボタンをタップ

フリック入力よりもはるかに速く、自然な言葉でClaude Codeに指示を出せます。

コード確認も快適

スマホの画面でもコードが見やすいように最適化されたUIで、差分確認やコードレビューも快適に行えます。

実践例: この記事をスマホで書いてみた

実は、この記事と前回の「gwq と lazygit、agent-deck で実現する効率的なブログ管理ワークフロー」の記事は、全てスマホから happy-coder を使って作成しました。

実際の作業フロー

1. PC側で準備

# 初回のみ認証
happy --auth
# 2回目以降は
happy

2. スマホ側で接続

  • Happy Claude Code Clientアプリを起動
  • 初回のみQRコードを読み込んで認証
  • 以降は起動するだけで自動接続

3. 音声入力で指示

  • 「新しくgwqとlazygit、agent-deckを組み合わせる記事を書いてほしいです」
  • 「lazygitのconfig.ymlはローカルにあるdotfilesリポジトリ内のファイルを参考にしてほしいです」

4. タップ操作で承認

  • Claude Codeからの提案をタップで承認
  • 修正箇所もタップで選択

5. 記事完成

  • PRマージまで全てスマホから実行

所要時間

  • 記事1(gwq + lazygit + agent-deck): 約30分
  • 記事2(この記事): 約20分

従来のPC作業と比べても遜色ない速さで、むしろ移動中や待ち時間を活用できる分、効率的でした。

スマホで開発する利点

1. 場所を選ばない

  • カフェでブログ執筆
  • 電車での移動中にコードレビュー
  • ベッドでリラックスしながらドキュメント作成

2. 隙間時間の有効活用

  • 5分の待ち時間でPRの確認
  • 10分の休憩でブログの下書き
  • 通勤時間で記事執筆

3. 音声入力で快適

  • タイピングより速い
  • 自然な言葉で指示が出せる
  • 手が疲れない

happy-coder の便利な機能

1. エンドツーエンド暗号化

QRコードで交換した共有シークレットを使って、PC(CLI)とスマホ間の通信が暗号化されます。セキュアな環境で開発作業ができます。

2. 履歴の保存

会話履歴が自動的に保存されるため、後から見返すことができます。

3. ダークモード対応

スマホでの長時間作業でも目に優しいダークモードに対応しています。

注意点とTips

セキュリティ

QRコードで認証を行うため、セキュアな環境で使用できます:

  • 信頼できるデバイスからのみアクセス
  • エンドツーエンド暗号化による安全な通信

バッテリー消費

長時間の作業ではバッテリー消費が気になる場合:

  • モバイルバッテリーを携帯
  • 画面の明るさを調整
  • 必要に応じてダークモードを使用

ネットワーク

安定したネットワーク環境で使用することをおすすめします:

  • Wi-Fi環境が理想的
  • 4G/5G回線でも問題なく動作(通信量に注意)

まとめ

happy-coderを使えば、追加のツールやVPN設定なしで、スマホからClaude Codeを快適に操作できます。

この記事で紹介した内容:

  1. happy-coderの手軽なセットアップ方法
  2. タップ操作による快適な選択肢の選択
  3. 音声入力との組み合わせで効率的なプロンプト入力
  4. 実際にスマホだけで2つの記事を執筆した体験

従来の方法(Tailscale + Termius)との違い:

  • ✅ インストールが簡単(happy-coderのみ)
  • QRコードを読み込むだけで接続完了
  • ✅ PCの常時稼働不要
  • VPN設定不要
  • ✅ タップ操作で快適

「外出先でもブログを書きたい」「隙間時間を有効活用したい」そんなあなたに、happy-coderは最適なツールです。

ぜひ、スマホでの開発体験を試してみてください!

参考リンク

gwq と lazygit、agent-deck で実現する効率的なブログ管理ワークフロー

はじめに

エンジニアとして日々の作業をしていると、複数のツールやワークフローを効率的に管理したいと思うことはありませんか?

今回は、gwq(Gitワークツリー管理)、lazygit(Git操作の効率化)、そしてagent-deck(AI補助ツール)を組み合わせることで、はてなブログの記事管理を含む開発ワークフロー全体を劇的に効率化できる方法をご紹介します。

各ツールの役割

gwq とは

gwqは、Gitのワークツリー機能を簡単に扱えるようにするCLIツールです。

主な特徴: - 複数のブランチを同時に異なるディレクトリで作業可能 - ブランチごとの作業ディレクトリを自動管理 - git worktreeコマンドをより直感的に使える

基本的な使い方:

# 新しいワークツリーを作成
gwq add feature-branch

# ワークツリー一覧表示
gwq list

# ワークツリーを削除
gwq remove feature-branch

lazygit とは

lazygitは、Gitを視覚的かつ高速に操作できるターミナルUIツールです。

主な特徴: - ステージング、コミット、プッシュなどを直感的に操作 - ブランチの切り替えやマージが視覚的に分かりやすい - 差分表示やコンフリクト解決もターミナル内で完結

基本的な使い方:

# lazygitを起動
lazygit

起動後は以下のキー操作で利用できます: - Space: ファイルをステージング/アンステージング - c: コミット - P: プッシュ - p: プル - [: 前のタブ、]: 次のタブ

agent-deck とは

agent-deckは、複数のAIエージェントを並行して管理・操作できるツールです。

主な特徴: - 複数のタスクを異なるAIエージェントに割り当て - ブログ執筆、コードレビュー、ドキュメント作成などを並行処理 - ターミナル内で複数のセッションを効率的に切り替え

統合ワークフロー:はてなブログ管理での実践例

それでは、これら3つのツールをどのように組み合わせて、はてなブログの記事管理を効率化するかを具体的に見ていきましょう。

Step 1: gwq で複数記事を並行執筆

はてなブログリポジトリで、複数の記事を同時に執筆する場合:

# メインブランチから新しい記事用のワークツリーを作成
cd ~/src/github.com/Pregum/hatena-blogs
gwq add draft-article-1
gwq add draft-article-2

# それぞれのディレクトリで独立して作業可能

これにより、以下のような構造になります:

hatena-blogs/               # メインのワークツリー
hatena-blogs-draft-article-1/  # 記事1用のワークツリー
hatena-blogs-draft-article-2/  # 記事2用のワークツリー

Step 2: lazygit で各記事の変更を管理

各ワークツリーでlazygitを起動することで:

# 記事1のワークツリーで
cd ~/src/github.com/Pregum/hatena-blogs-draft-article-1
lazygit

以下の操作が視覚的に行えます: 1. 変更ファイルの確認: 記事のマークダウンファイルの差分をプレビュー 2. 段階的なコミット: セクションごとに分けてコミット 3. プッシュとPR作成: GitHub Actionsで自動的にはてなブログに反映

Step 3: agent-deck で記事執筆をAI支援

agent-deckを使って、複数の記事執筆タスクをAIに並行して依頼できます:

# agent-deckを起動
agent-deck

使用例: - エージェント1: 「gwqについての技術解説セクションを執筆」 - エージェント2: 「lazygitの使い方のスクリーンショットを作成」 - エージェント3: 「統合ワークフローのサンプルコードをレビュー」

これにより、記事の異なるセクションを並行して作成・改善できます。

実際のワークフロー例

シナリオ: 新しいブログ記事を執筆してPublishするまで

  1. gwqで新しいワークツリーを作成 bash gwq add draft-gwq-lazygit-article cd ../hatena-blogs-draft-gwq-lazygit-article

  2. GitHub Actionsで下書き作成 bash gh workflow run create-draft.yaml -f title="新しい記事のタイトル"

  3. agent-deckでAI支援を受けながら記事執筆 ```bash agent-deck

    複数のエージェントに異なるセクションの執筆を依頼

    ```

  4. lazygitで変更を確認・コミット ```bash lazygit

    視覚的に変更を確認してコミット

    ```

  5. PRをマージして記事を公開 bash gh pr merge --auto --squash

GitHub Actionsのpush.yamlワークフローが自動的に実行され、はてなブログに記事が公開されます。

各ツールのメリット

gwq を使うメリット

  • ✅ 複数の記事を同時進行できる
  • ✅ ブランチごとの環境が独立し、混乱しない
  • git worktreeの複雑さを隠蔽

lazygit を使うメリット

  • ✅ Git操作が視覚的で分かりやすい
  • ✅ コミット履歴やブランチ状態を一目で把握
  • ✅ マウスを使わずキーボードだけで完結

agent-deck を使うメリット

  • ✅ 複数のAIエージェントに並行してタスクを依頼
  • ✅ 記事の異なるセクションを効率的に作成
  • ✅ コードレビューやドキュメント生成も同時進行

さらなる効率化: lazygit と gwq の統合

gwq のパス管理設定

gwqは、ワークツリーのパスを柔軟に管理できます。~/.config/gwq/config.tomlで設定することで、オリジナルリポジトリと作業ディレクトリを同じルート配下に統一できます。

# ~/.config/gwq/config.toml
template = '{{.Host}}/{{.Owner}}/{{.Repository}}={{.Branch}}'

この設定により、以下のような構造になります:

~/ghq/
  └── github.com/
      └── Pregum/
          ├── hatena-blogs/              # オリジナル (main)
          ├── hatena-blogs=draft-article-1/  # ワークツリー (draft-article-1)
          └── hatena-blogs=draft-article-2/  # ワークツリー (draft-article-2)

この設定のメリット: - オリジナルとワークツリーが同じ階層に並ぶため管理しやすい - 複数のコーディングエージェント(agent-deck)を並列実行してもディレクトリの衝突を防げる - ghqやfzfと組み合わせてさらに便利に

参考: ghq + gwq + fzf で Git worktree を快適に扱う - Zenn

lazygit のカスタムコマンド設定

lazygitの各コンテキストに応じて、gwqのワークツリー操作コマンドを設定できます。

~/.config/lazygit/config.ymlに以下を追加:

keybinding:
  universal:
    diffingMenu: <disabled>  # 組み込みのW(diffingMenu)を無効化
  worktrees:
    viewWorktreeOptions: <disabled>

customCommands:
  # [w] worktreesパネル: gwq addで新規worktree作成(ブランチ名入力)
  - key: "w"
    context: "worktrees"
    description: "Create worktree (gwq add -b)"
    prompts:
      - type: "input"
        title: "New branch name:"
        key: "BranchName"
    command: "/opt/homebrew/bin/gwq add -b {{.Form.BranchName}}"

  # [w] localBranchesパネル: 選択ブランチでworktree作成
  - key: "w"
    context: "localBranches"
    description: "Create worktree for branch (gwq add)"
    command: "/opt/homebrew/bin/gwq add {{.SelectedLocalBranch.Name}}"

  # [w] remoteBranchesパネル: 選択リモートブランチでworktree作成
  - key: "w"
    context: "remoteBranches"
    description: "Create worktree for remote branch (gwq add)"
    command: "/opt/homebrew/bin/gwq add {{.SelectedRemoteBranch.Name}}"

  # [W] グローバル: gwq cdでworktreeに移動
  - key: "W"
    context: "global"
    description: "Switch to worktree (gwq cd)"
    command: "/opt/homebrew/bin/gwq cd"
    output: "subprocess"

  # [d] worktreesパネル: worktreeを削除
  - key: "d"
    context: "worktrees"
    description: "Remove worktree (gwq remove)"
    command: "/opt/homebrew/bin/gwq remove"
    output: "subprocess"

  # [s] worktreesパネル: 全worktreeの状態を表示
  - key: "s"
    context: "worktrees"
    description: "Show worktree status (gwq status)"
    command: "/opt/homebrew/bin/gwq status"
    output: "subprocess"

この設定により、lazygit内で以下の操作が可能になります:

worktreesパネル: - wキー: 新しいブランチ名を入力してworktree作成 - dキー: worktreeを削除(fzfで選択) - sキー: 全worktreeの状態を表示

localBranches / remoteBranchesパネル: - wキー: 選択したブランチでworktree作成(ブランチ名入力不要)

グローバル(どのパネルでも): - Wキー: worktreeを切り替え(fzfで選択)

ワークツリーのパスを意識せずに操作可能になります!

agent-deck へのコマンド統合

agent-deckにも同様のコマンドを登録しておくことで、AIエージェント側からもワークツリーを管理できます。

~/.config/agent-deck/commands.jsonを作成:

{
  "commands": [
    {
      "name": "switch-worktree",
      "command": "gwq list | fzf",
      "description": "Switch to a different worktree"
    },
    {
      "name": "create-worktree",
      "command": "gwq add",
      "description": "Create a new worktree",
      "args": ["branch-name"]
    },
    {
      "name": "list-worktrees",
      "command": "gwq list",
      "description": "List all worktrees"
    }
  ]
}

これにより、agent-deck内で: - AIエージェントが自動的にワークツリーを切り替え - 複数記事の並行執筆時に各エージェントが独立したワークツリーで作業 - ディレクトリパスを意識せずにコマンド実行が可能

導入方法

gwq のインストール

# Homebrewの場合
brew install shibukawa/tap/gwq

# Cargoの場合
cargo install gwq

インストール後の設定:

# gwqの設定ディレクトリを作成
mkdir -p ~/.config/gwq

# config.tomlを作成
cat <<EOF > ~/.config/gwq/config.toml
template = '{{.Host}}/{{.Owner}}/{{.Repository}}={{.Branch}}'
EOF

lazygit のインストール

# Homebrewの場合
brew install lazygit

# その他のパッケージマネージャー
# https://github.com/jesseduffield/lazygit#installation

agent-deck のインストール

# npmの場合
npm install -g agent-deck

# yarnの場合
yarn global add agent-deck

まとめ

gwqlazygitagent-deckを組み合わせることで、以下のような効率的なブログ管理ワークフローを実現できます:

  1. gwq: 複数記事の並行執筆環境を提供
  2. lazygit: Git操作を視覚的かつ高速に
  3. agent-deck: AI支援による記事執筆の効率化

これらのツールは、はてなブログ管理だけでなく、一般的なソフトウェア開発においても大きな生産性向上をもたらします。

ぜひ、皆さんのワークフローに取り入れて、より快適な開発体験を手に入れてください!

参考リンク

【Supabase CLI】Androidの実機でSupabaseのローカルサーバへアクセスする際に127.0.0.1で躓いた時の回避策【adb reserve】

こんにちは。 pregum_foxです。 今回は以前に何回か起きては都度調べているAndroidの実機でローカルサーバーへアクセスする際に127.0.0.1で躓いた時の回避策についてまとめます。

検証環境

項目 内容
Android OSバージョン Android 16
端末名 Google Pixel 6a

遭遇した現象

supabase CLIで起動したローカルサーバへAndroid端末で接続を試みると、下記のようなエラーログが出力されDBへアクセスに失敗しました。

ClientException with SocketException: Connection refused (OS Error: Connection refused, errno = 111), address = 127.0.0.1, port = 41534, uri=http://127.0.0.1:54321/rest/v1/app_versions?select=%2A&limit=1, #0      IOClient.send (package:http/src/io_client.dart:154:7)
I/flutter ( 6789): │ ⛔ <asynchronous suspension>
I/flutter ( 6789): │ ⛔ #1      BaseClient._sendUnstreamed (package:http/src/base_client.dart:93:32)
I/flutter ( 6789): │ ⛔ <asynchronous suspension>
I/flutter ( 6789): │ ⛔ #2      PostgrestBuilder._execute (package:postgrest/src/postgrest_builder.dart:140:20)
I/flutter ( 6789): │ ⛔ <asynchronous suspension>
I/flutter ( 6789): │ ⛔ #3      PostgrestBuilder.then (package:postgrest/src/postgrest_builder.dart:397:24)
I/flutter ( 6789): │ ⛔ <asynchronous suspension>

以下に手順を追って説明します。

Supabase CLIを使用して、supabase start でサーバを起動し、supabase statusで接続を確認し以下のようなURLでアクセスできることを確認しました。

         API URL: http://127.0.0.1:54321
     GraphQL URL: http://127.0.0.1:54321/graphql/v1
  S3 Storage URL: http://127.0.0.1:54321/storage/v1/s3
          DB URL: postgresql://postgres:postgres@127.0.0.1:54322/postgres
      Studio URL: http://127.0.0.1:54323
    Inbucket URL: http://127.0.0.1:54324
      JWT secret: super-secret-jwt-token-with-at-least-32-characters-long
        anon key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
service_role key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
   S3 Access Key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
   S3 Secret Key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
   S3 Region: local

上記のAPI URLを設定して、接続を試みると、冒頭のエラーが発生しました。

解消方法

adb reverse tcp:54321 tcp:54321 コマンド を使用して、 Android端末の54321 ポートをUSB接続しているローカルPCの54321ポートにポートフォワーディング

Supabase のGitHubに似たような人がいるか調べているとちょうど似たような現象のdiscussionがあり、その下の回答で

adb reverse tcp:54321 tcp:54321 コマンドで対応された方がいましたので同様に叩いて解消しました。

github.com

叩いた時に、実機とエミュレータの複数起動していましたので、 adb devices でdevice IDを調べた後、 -s <deviceId>オプションを adb reserve コマンドに追加して叩くとうまくいきました。

例として、deviceIdがABC81JE の場合はこんなコマンドを叩きました

adb -s ABC81JE reverse tcp:54321 tcp:54321

エミュレータの場合

エミュレータの場合は、公式ドキュメントに載っているように http://10.0.2.2/ を使用するようにしてください

developer.android.com

ポートフォワーディングを確認する方法

下記コマンドを叩けばOKです。

adb reverse --list

ポートフォワーディングを元に戻す方法

対応としてはいずれかの対応でOKです。

  • adb reverse --remove tcp:54321 コマンドを実行する
    • 端末に紐づくので複数接続している場合は -s オプションをつける
  • USB接続を解除する
  • 端末を再起動する

まとめ

今回は簡単な備忘録ですが、たまにローカルサーバへアクセスすることがあり、その度に10.0.2.2を設定するのか、サーバのローカルIPアドレスに置き換えるか対応を調べて時間を浪費することが多かったので、これで時間が節約できれば良いなと思っています。

【.envも自動コピー!】git worktree運用を快適にする3つの方法とおすすめツール紹介

こんにちは、pregum_foxです。

今回はGitの便利機能 git worktree の使い方について、特に .env.vscode などの Git管理外ファイルを手軽に扱う方法 にフォーカスしてご紹介します。

運用方法のパターンは大きく分けて3つ。それぞれのメリット・デメリットを比較しながら、私が開発した git-worktree-sync というツールを使った方法も解説します。


✅ そもそも git worktree って何?

git worktree を使うと、1つのGitリポジトリで複数の作業ディレクトリを扱うことができます。

たとえば別ブランチで検証作業したいときに、いちいち git checkout で切り替える必要がありません。

git worktree add ../feature-login feature/login

このようにすると、feature/login ブランチがチェックアウトされた新しい作業ディレクトリが作られます。


🧭 運用方法その1:ブランチごとに切り出す(ディレクトリ=ブランチ名)

git worktree add ../feature-login feature/login

✅ メリット

❌ デメリット

  • .env.vscode などの Git管理外ファイルを都度コピーする必要がある
cp ../main/.env ../feature-login/

🧭 運用方法その2:用途ごとにディレクトリを再利用する

git worktree add ../review review/base
  • ../feature/:feature系ブランチをここで切り替えながら作業
  • ../review/:PRレビュー用ブランチを毎回ここに出す

✅ メリット

  • .env などを 最初にコピーするだけでOK
  • ワークツリー数が少なくて済む

❌ デメリット

  • 今どのブランチが入っているかがディレクトリ名だけでは分からない

🧭 運用方法その3:git-worktree-sync を使う(おすすめ!)

git-worktree-sync は、私が開発したシェルスクリプトです。

git-worktree-sync feature/login

このコマンドだけで以下が完了します:

  • git worktree add の実行
  • .env, .vscode などのGit管理外ファイルのコピー

✅ メリット

  • 方法①のように一意なディレクトリ運用ができる
  • .env などのコピー操作が不要
  • .gitignore に含まれているファイルも .worktree-sync.yaml で柔軟に制御可能

❌ デメリット

  • 初回のみ インストール & PATH設定 が必要
brew install pregum/tools/git-worktree-sync
# または
curl -o /usr/local/bin/git-worktree-sync https://raw.githubusercontent.com/Pregum/git-worktree-sync/main/git-worktree-sync
chmod +x /usr/local/bin/git-worktree-sync

🕹 lazygit × git worktree の連携

最近人気の lazygit でも、実は git worktree の操作が可能です。

操作手順

  1. lazygit を起動
  2. w キーで worktree モードに入る
  3. n キーで新しい worktree を追加
  4. 任意の worktree に移動可能

.env.vscode の同期が必要な場合は git-worktree-sync を組み合わせるとより快適です。

詳細は下記README.mdをご覧ください

github.com


🧾 まとめ:3つの運用方法を比較

運用方法 分かりやすさ .env等の管理 自動化しやすさ 初期コスト
① ブランチごと運用 ×(手動コピー)
② 種類ごとに再利用 ◎(1回だけ)
③ git-worktree-sync 使用 ◎(自動コピー)

🚀 結論:こんな人におすすめ!

  • 明瞭な構成で効率的に開発したい →
  • 開発環境のセットアップが面倒 →
  • .envも含めて全部自動化したい → ③(特におすすめ)

🎁 最後に

.env などの管理外ファイルに悩まされている方は、ぜひ git-worktree-sync を試してみてください!

一度導入すれば、以後のブランチ運用が格段に楽になります。

質問・フィードバックなどあれば、ぜひコメント欄で教えてください!

【Supabase】パスワード設定済みのテストユーザーをseed.sqlで生成する方法【Local Dev】

こんにちは。pregum_foxです。

今回は備忘録なので短めです。

背景

ローカルの開発環境にて、毎回ユーザーを作成するのが大変なので、seed.sqlに固定したパスワードとメールアドレスで生成されるユーザーをsupabase db resetコマンドを叩くと自動で生成されるようにしたかったので、調査しました。

前提条件

  • dockerが起動していること
  • supabase initコマンドが実行されてsupabase/config.tomlファイルが生成されていること
  • Supabase CLIがインストールされていること
  • 設定するプロジェクトでemailのproviderが有効になっていること
    • 具体的には以下のような設定になっていればOKです

環境

結論

seed.sqlが読み込めるようにconfig.tomlの最後にseed.sqlファイルを読み込む設定を追加します。

https://supabase.com/docs/guides/local-development/seeding-your-database

       # 記述されている設定...
         # ↓ を追加
         [db.seed]
   enabled = true
   sql_paths = ['./seeds/*.sql']

supabase/seeds/seed.sqlに以下の関数を書いて呼び出すことで実行できました。

Can't seed or signup auth users locally · supabase · Discussion #9251 · GitHub

     -- ============================================
  -- 1. 拡張機能とヘルパー関数の定義
  -- ============================================
  CREATE EXTENSION IF NOT EXISTS "pgcrypto";
  
  -- 関数はこちらのコードをお借りした
  -- ref: https://github.com/orgs/supabase/discussions/9251#discussioncomment-6199552
  -- パスワード付きのユーザーを作成する関数
  CREATE OR REPLACE FUNCTION public.create_user_for_test(
      email text,
      password text
  ) RETURNS uuid AS $$
    declare
    user_id uuid;
    encrypted_pw text;
  BEGIN
    user_id := gen_random_uuid();
    encrypted_pw := crypt(password, gen_salt('bf'));
    
    INSERT INTO auth.users
      (instance_id, id, aud, role, email, encrypted_password, email_confirmed_at, recovery_sent_at, last_sign_in_at, raw_app_meta_data, raw_user_meta_data, created_at, updated_at, confirmation_token, email_change, email_change_token_new, recovery_token)
    VALUES
      ('00000000-0000-0000-0000-000000000000', user_id, 'authenticated', 'authenticated', email, encrypted_pw, '2023-05-03 19:41:43.585805+00', '2023-04-22 13:10:03.275387+00', '2023-04-22 13:10:31.458239+00', '{"provider":"email","providers":["email"]}', '{}', '2023-05-03 19:41:43.580424+00', '2023-05-03 19:41:43.585948+00', '', '', '', '');
    
    INSERT INTO auth.identities (id, user_id, identity_data, provider, last_sign_in_at, created_at, updated_at, provider_id)
    VALUES
      (gen_random_uuid(), user_id, format('{"sub":"%s","email":"%s"}', user_id::text, email)::jsonb, 'email', '2023-05-03 19:41:43.582456+00', '2023-05-03 19:41:43.582497+00', '2023-05-03 19:41:43.582497+00', email);
  
    RETURN user_id;
  END;
  $$ LANGUAGE plpgsql;

実際に呼び出す場合はdoブロックで囲む必要があるので注意です。 doブロックで囲まないと、failed to send batch: ERROR: function public.create_user_for_test(text, text) does not exist (SQLSTATE 42883) のようなエラーメッセージが表示され実行ができませんでした。

https://github.com/supabase/cli/issues/882#issuecomment-1595725535

下記の例では、以下の2つのusersレコードを作成しています。

  • email: dev1@example.com, password: password123
  • email: dev2@example.com, password: password123
     -- ============================================
     -- 3. 開発用データの作成
     -- ============================================
     -- 開発用のテストユーザーを追加(既存のテストユーザーに加えて)
     -- seed.sql内で関数を実行する場合は、doブロックで囲む必要があった
     -- ref: https://github.com/supabase/cli/issues/882#issuecomment-1595725535
     do $$
     begin
     -- ユーザーの作成
     perform public.create_user_for_test('dev1@example.com'::text, 'password123'::text);
     perform public.create_user_for_test('dev2@example.com'::text, 'password123'::text);
     end $$;

生成したuser_idに対して何かしらのデータを紐付けたい場合は、doブロック内で変数を定義して、sqlを書くことで作成できました。

イメージ

-- ============================================
-- 3. 開発用データの作成
-- ============================================
-- 開発用のテストユーザーを追加(既存のテストユーザーに加えて)
-- seed.sql内で関数を実行する場合は、doブロックで囲む必要がありました
-- ref: https://github.com/supabase/cli/issues/882#issuecomment-1595725535
do $$
declare
    dev1_user_id uuid;
    dev2_user_id uuid;
    dev1_exhibition_id int;
begin
    -- ユーザーの作成
    dev1_user_id := public.create_user_for_test('dev1@example.com'::text, 'password123'::text);
    dev2_user_id := public.create_user_for_test('dev2@example.com'::text, 'password123'::text);

    -- dev1の展示会を作成
    INSERT INTO public.exhibitions (
        name,
        description,
        author_user_id,
        start_at,
        end_at,
        location,
        created_at,
        updated_at
    ) VALUES (
        '開発用展示会1',
        '開発ユーザー1の展示会です',
        dev1_user_id,
        '2024-01-01 00:00:00+00',
        '2024-12-31 23:59:59+00',
        '開発美術館',
        NOW(),
        NOW()
    ) RETURNING id INTO dev1_exhibition_id;

    -- dev1の作品を作成
    INSERT INTO public.artworks (
        name,
        description,
        artist_name,
        author_user_id,
        exhibition_id,
        created_at,
        updated_at
    ) VALUES (
        '開発用作品1',
        '開発用展示会1の作品1です',
        '開発作家1',
        dev1_user_id,
        dev1_exhibition_id,
        NOW(),
        NOW()
    );

    -- 作品の画像を追加
    INSERT INTO public.artwork_images (
        image_url,
        storage_file_path,
        artwork_id,
        created_at
    ) VALUES (
        'https://example.com/dev/artworks/1/image1.jpg',
        'dev/artworks/1/image1.jpg',
        currval('public.artworks_id_seq'),
        NOW()
    );
end $$;

seed.sql内の記述順は以下の順番であれば実行できました。

  1. 関数
  2. 関数呼び出し

sqlの変更が完了したら、supabase db reset でseed.sqlを実行し直して、スキーマ、テーブルのレコードを作り直すことで反映が可能です。

手元のFlutterのアプリにてログインできることを確認しました。

もしローカル環境のレコード内にバックアップをとっておきたいデータがある場合は、先にpg_dumpコマンドやTable Plusのexportなどで保存しておくことを推奨します。

ここまで読んでいただきありがとうございます。

【ESET】Androidにてlocalhostに対してのhttp接続ができなかった時の対応メモ【ファイアーウォール】

こんにちは。pregum_foxです。 今回は実機のAndroid端末からローカルPCへ向けてのhttp接続が動作しないことがあり、一般的なハマりポイントとは異なる箇所でハマっていたので、備忘録としてこちらに残しておこうと思います。

以下目次です。

  • 開発環境
  • 概要
  • 原因
  • 解決方法
  • 調査時に行ったこと
  • 雑感
  • 参考URL
続きを読む

Git操作のストレスを解消!lazygitで快適なバージョン管理を

こんにちは。 pregum_foxです。

最近tigを使ってGitの操作をしていましたが、最近はlazygitに乗り換えてみて直接gitコマンドを打つ頻度が減ってきました。

この記事では以下の内容を紹介します。

  • lazygitとは
  • なぜlazygitを使うのか
  • lazygitの設定手順
    • 日本語化
    • キーバインドのカスタマイズ
    • 現在の設定ファイルの内容
  • lazygitで操作する方法
    • 基本的なgitコマンド
    • よく使うシナリオ

以下目次です。

  • この記事を読むことでわかること
  • 対象外の内容
  • 想定読者
  • 動作確認環境
  • lazygitとは
  • 背景
  • lazygitを使用するメリット
  • lazygitの設定方法と使い方
    • インストール方法
    • 基本的な設定
      • 日本語化の設定
      • アイコンの設定
      • キーバインドのカスタマイズ
      • よく使うキー操作
      • おすすめの設定ファイル
    • よく使うコマンド一覧
    • コマンドごとの操作方法
      • git add ~
        • git add {ファイルパス} | 対象ファイルのステージング
        • git add -A | 全てのファイルのステージング
      • git commit ~
        • git commit -m {メッセージ} | コミットメッセージの設定
        • git commit --amend | コミットメッセージの修正
        • git commit | 標準エディタでコミットメッセージの設定
      • git push ~
        • git push {取得先のremote} {ブランチ名} | ブランチのプッシュ
        • git push --force | 強制プッシュ
      • git pull ~
        • git pull | ブランチのプル
      • git checkout ~ (git restore関連)
        • git checkout . | git restore . | 変更を元に戻す
      • git checkout ~ (git switch関連)
        • git checkout {ブランチ名} | git switch {ブランチ名} | フランチの切り替え
        • git checkout {リモートに存在するブランチ名} | リモートブランチのチェックアウト
      • git branch ~
        • git branch -d {ブランチ名} | ブランチの削除
      • git merge ~
        • git merge {ブランチ名} | ブランチのマージ
      • git rebase ~
        • git rebase {ブランチ名} | ブランチのリベース
        • git rebase -i {コミットID or ブランチ名} | 対象のコミット以降のインタラクティブなリベース
      • git reset ~
        • git reset {コミットID} | 現在のブランチのHEADを移動
      • git stash ~
        • git stash push | ステージングしていない変更をスタッシュ
        • git stash pop | スタッシュのポップ(適用後stash一覧から破棄)
        • git stash drop | スタッシュの削除
        • git stash apply | スタッシュの適用
        • git stash drop & store | スタッシュメッセージの変更
      • git tag ~
        • git tag {タグ名} | タグの作成
      • git revert ~
        • git revert {コミットID} | コミットの取り消し
      • git cherry-pick ~
        • git cherry-pick {コミットID} | コミットの適用
      • コンフリクトの解消
    • 実践ケース集
      • lazygitの設定ファイルを編集するケース
      • 新機能の開発を始めるケース
      • コミットした後にコミットメッセージを変えて再度pushするケース
      • コミットした直後にフォーマッタの差分が出ていたので最新のコミットに混ぜ込むケース
      • 切り出し元のブランチが更新されたのでその差分を作業中のブランチにリベース(or マージ) するケース
        • リベースの場合
        • マージの場合
      • 何らかの作業を行う前に一部分の差分だけstashするケース
      • コミットのURL(or SHA-1)をクリップボードへコピーするケース
      • コミットの順番を入れ替えるケース
      • コミットしないけどデバッグのための変更をpatchファイルとして作成するケース
      • コミットをcherry-pickして、作業中のブランチに適用するケース
      • 任意のファイルの変更のうち一部分だけをステージングにアップしてコミットするケース
        • 1行単位でステージングする場合
        • Hunk(差分の塊)単位でステージングする場合
      • 特定のコミットを削除するケース
      • 任意のコマンドをlazygit上で叩くケース
      • rebase -iで編集モードに入らずにsquashやfixupを行う方法
      • 他のリポジトリへ切り替えるケース
  • まとめ
  • 参考資料
続きを読む