miive プロダクトブログ

miiveのプロダクトチームのブログです。

WezTermでいい感じの開発環境を一発で起動する

こんにちは。

miiveの基盤チームでエンジニアをしている akito です。

みなさん、気持ちよく開発できていますでしょうか?

わたしはWezTermのおかげで気持ちよく開発できています。

コーディングエージェントが登場してから、Neovimを開きつつClaude Code(たまにCodexも)を開くことがデフォルトになっています。 そうなると毎回ペインを複数分割し、Claude Code, Codexを起動させるのが面倒になります。

はい、改善しましょう。

tmux使ってみるか〜と思いはしたものの、WezTermだけでできるんじゃね?と思い調べたところ簡単にできたのでご紹介します。

WezTermとは

wezterm.org

WezTerm is a powerful cross-platform terminal emulator and multiplexer written by @wez and implemented in Rust

wezさんが開発しているRust製のターミナルエミュレータです。 以前はiTerm2を使用していたのですが、動作がもっさりしているのが気になりWezTermに移行しました。(多分わたしの使い方が悪い) なぜWezTermにしたのか。「ターミナル 軽い」などでググり、上位に出てきたからです。理由なんてあとから付いてくるものです。

いい感じの開発環境を一発で起動させる

では本題です。

私の環境でWezTermを起動したときはこんな感じです。

WezTermを起動

タブが4つ開きます。(見づらいですが左下にタブが並んでいます)

タブはそれぞれ左から

  • タブ①
    • docker compose up, yarn dev などをペイン分割して実行し
      ローカルサーバー、各種エミュレータを起動させる
  • タブ①②③
    • タブを分割し Neovim, Claude Code を起動

されています。

ターミナルを起動するだけで準備されるのはとても気持ちがいいです。やる気が漲ります。

設定ファイルはこんな感じです(一部抜粋)

local wezterm = require("wezterm")
local mux = wezterm.mux
local config = wezterm.config_builder()

wezterm.on('gui-startup', function(cmd)
  local home = wezterm.home_dir

  -- ===== tab1: 開発サーバー =====
  local tab, server_pane, window = mux.spawn_window {
    cwd = home .. '/server',
  }
  server_pane:send_text 'docker compose up\n'

  local app_pane = server_pane:split {
    direction = 'Right',
    size = 0.66,
    cwd = home .. '/app',
  }
  app_pane:send_text 'yarn dev\n'

  local admin_pane = app_pane:split {
    direction = 'Bottom',
    size = 0.5,
    cwd = home .. '/admin',
  }
  admin_pane:send_text 'yarn dev\n'

  window:gui_window():maximize()

  -- ===== tab2(各プロジェクト別タブ + claude) =====
  local editor_tab1, editor_server_pane = window:spawn_tab {
    cwd = home .. '/server',
  }
  editor_tab1:set_title 'server'
  local claude = editor_server_pane:split {
    direction = 'Right',
    size = 0.33,
    cwd = home .. '/server',
  }
  wezterm.sleep_ms(500)
  editor_server_pane:send_text 'nvim\n'
  claude:send_text 'claude\n'

-- 以降もtab2, tab3の設定を追記していく

end)


return config

細かく説明していきます。

まずはtab1から

-- まずはウィンドウ、ペインを作成 
 local tab, server_pane, window = mux.spawn_window {
    cwd = home .. '/server',
  }
-- 実行したいコマンド
  server_pane:send_text 'docker compose up\n'

-- ペインを分割
  local app_pane = server_pane:split {
    direction = 'Right',
    size = 0.66,
    cwd = home .. '/app',
  }
  app_pane:send_text 'yarn dev\n'

-- さらにペインを分割
  local admin_pane = app_pane:split {
    direction = 'Bottom',
    size = 0.5,
    cwd = home .. '/admin',
  }
  admin_pane:send_text 'yarn dev\n'

つぎはtab2について(ほぼ同じですが)

-- タブを作成
  local editor_tab1, editor_server_pane = window:spawn_tab {
    cwd = home .. '/server',
  }

-- タブタイトルを設定
  editor_tab1:set_title 'server'

-- ペインを分割
  local claude = editor_server_pane:split {
    direction = 'Right',
    size = 0.33,
    cwd = home .. '/server',
  }
-- Neovim, Claude Code をそれぞれ起動 
 wezterm.sleep_ms(500)
  editor_server_pane:send_text 'nvim\n'
  claude:send_text 'claude\n'

設定ファイルを軽く書くだけでこんな事ができます。すばら。

ぜひ皆さんもお試しください。

おまけ

WezTerm には Copy Mode なるものがあります。

その名から想像がつくように、テキストをコピーするためのModeです。 キーボードから手を動かしたくない自分のような人間からすると神機能です。 vimライクにカーソル操作が可能なので例えば

こんな文字列があるとします

Ctrl + Shift + X で Copy Mode を起動し、vFTy と入力するだけで「This is a pen.」がクリップボードに入ります。

Copy Modeで文字列を選択した状態

最高です。

We're Hiring!!!

miiveでは一緒に福利厚生の未来を作ってくれる仲間を募集しています。ちょっとでも興味のある方は一度ぜひお話しましょう!

hrmos.co

また、定期的にお酒と軽食を楽しみつつ、カードゲームやボードゲームで遊びながら、miiveメンバーと気軽に仕事や働き方の話ができる「miive bar🍷」を開催しています。

「いきなりカジュアル面談はちょっとハードルが高い…」という方はぜひ、miive barにご参加ください! miive.notion.site

本当に「刺さる」Raycastの機能は?~社内勉強会を開催しました~

こんにちは。Seijiと申します。現在は株式会社miiveで、Webやバックエンド、アプリの開発をしております。私は業務や私生活で日常的にRaycastを使っています。

Raycastは生産性をあげてくれるランチャーアプリです。任意のアプリの起動から、よく使うスクリプトの実行までなんでもできます。

www.raycast.com

こんなRaycastを社内に広めれば生産性の向上、ひいてはサービスの開発が加速するのではないか?という仮説のもと社内へのRaycast布教活動をしています。

blog.miive.jp

今回は社内でRaycastの勉強会をして「結局どの機能が刺さったのか?」を書きます。

逆にRaycastの機能については軽く触れるのみで、詳細については解説しません。

はじまり

私はRaycast Community Japanの運営メンバーの1人です。息をするようにRaycastを布教しています。

現職に入社をする時も面接でRaycastの話、Community運営の話をしました。そのため、社内では「せーじ=Raycast好き」というブランディングが確立しています。

そのため、入社後に開発責任者の daichiさんから「Raycastの勉強会とかやらないんですか?」とご提案いただき実施に至りました。

実はこの勉強会、入社して2週間ほどで開催しています。社内メンバーとの交流の機会としてもとてもいい場でした。

準備

準備は社内のメンバーに刺さりそうな以下の記事を執筆したぐらいです。

blog.miive.jp

弊社はWeWorkというシェアオフィスに入居しています。そのためMTGスペースは豊富にありました。

勉強会

勉強会はオンライン/オフラインのハイブリッドで開催しました。合計13名の開発メンバーが参加してくれました。

勉強会自体は最初の15分ほどで私が解説をし、残りの30分で参加メンバーに色々と試してもらいました。

何が刺さったか?

「UIがカッコイイ」

勉強会の中でUIがカッコイイという話があがりました。私もはじめは「UIがカッコイイ」という理由で使い始めたのでとてもよくわかります。

個人的にはWebサイトからしてカッコイイと思います。

Raycast - Your shortcut to everything

「Clipboard History が便利!」

私も最もよく使う機能だと思います。Clipboard Historyはみなさんが恒常的に利用する機能になっていました。

メンバーの反応を見る中で、特に以下の点がユニークで刺さりやすいと感じました。

  • URLをコピーした時、サムネもプレビューされる
  • コピーした画像が検索できる&プレビューがでる
  • 検索しやすい
  • やっぱりUIがカッコイイ

www.raycast.com

QuickTime Playerで画面の録画を始める

Macの場合、画面の録画をするためにQuickTime Playerを使う方も一定数いらっしゃると思います。特にエンジニアだと実装途中の画面の動きを録画して共有したり。

ただ、このQuickTime Playerで画面を録画するためにはステップが非常に多いです。5回ぐらいUIを操作しないと録画が開始できません。

これを解決するのがRaycast Extensionsの『QuickTime Recording』です。Raycastをインストール済の場合、以下のリンクからインストールできます。

www.raycast.com

このExtensionを利用することで5ステップ -> 2ステップに短縮できます。

同様の課題を感じていた同僚にとても刺さりました。

Confetti

この機能は画面に紙吹雪を飛ばせるというシンプルな機能です。

開発責任者の daichiさんがとても楽しそうに紙吹雪を飛ばしていました。

この機能のTipsを少しだけ紹介すると

  • Claude Code等のAgentが入力待ち状態になったのをフックに紙吹雪を飛ばす
  • Build Jobが終わったら紙吹雪を飛ばす

など、「強烈な通知」としても優秀です。

以下のようなdeeplinkをフックに指定すれば利用できます。色々な方が試してるのでWebで検索してぜひ試してみてください。

# 普通の紙吹雪
raycast://extensions/raycast/raycast/confetti

# 指定した絵文字を飛ばす
raycast://extensions/raycast/raycast/confetti?emojis=💻💻🔥🔥

小話

CEOのrenさんが「せいじさん、Raycast課金しました」と唐突に言ってきた時は大変驚きました。RaycastはAnnualだと3万円以上します。

経営者の決断力たるやすごい、、、

全社へのRaycast導入を目指して引き続き精進します。

弊社に入社しませんか!

弊社にご興味を持っていただけましたら、カジュアル面談や、miive bar(ゆるく雑談とボードゲームをする会)なども実施しています。

ぜひご参加ください!お待ちしております!

hrmos.co

miive.notion.site

XでDMでも大歓迎です!

プロダクトチームで初のオフサイトミーティングを実施しました

こんにちは、miiveでプロダクトマネージャーをしているhayashiです。

先日、プロダクトチームで初となるオフサイトミーティングを実施しました!
直近でプロダクトチームの人数がぐっと増え(現在23名)、普段の仕事だけだと「仕事では知ってるけど、人となりは詳しく知らない」が起きやすいフェーズに入ってきました。

そこで今回は「相互理解」を目的に、ちょっとだけ普段の業務から離れてチームでじっくり向き合う時間をつくりました。

オフサイトミーティングの目的(今回のゴール)

今回のオフサイトは下記の3点の理由から、いわゆる「戦略や目標を決める会」ではなく、「チームで仕事をしていくうえでの土台づくり(相互理解)」を目的に開催しました。

  • 直近の採用加速で、初めましてのメンバーが増えた
  • 日々のコミュニケーションを "仕事の話だけ" に閉じず、安心して相談できる関係性をつくりたい
  • 「この人は何が得意で、どんな価値観で、何を大切にしているか」を知るきっかけが欲しかった

当日のプログラム

オフサイトミーティングでは、以下のワークを実施しました。

1. プロフィール帳を使った自己紹介

まずはアイスブレイクも兼ねて、事前に記入してもらったプロフィール帳をもとに自己紹介を行いました。
※ プロフィール帳を知らない若者は「プロフィール帳 平成」でググってください...

プロフィール帳を使った自己紹介タイムの様子

プロフィール帳には、趣味や好きな食べ物といった基本的な情報はもちろん、「生まれ変わるなら」「座右の銘」「わたしの〇〇〇TOP3」など、普段の業務では知ることができないパーソナルな情報を記載してもらいました。

「そんな趣味があったんですか!?」「同い年だったんですね!」など、思わぬ共通点が見つかり、質問パートでも盛んに質問が弾んでいました。

2. ライフラインチャートで「人となり」を共有

自己紹介パートで打ち解けたあとは、ライフラインチャートを使ったワークを実施しました。

ライフラインチャートとは、自分のこれまでの人生を「幸福度」という軸で振り返り、1本の曲線で表現するものです。横軸に時間(年齢)、縦軸に幸福度をとり、人生の山や谷となった出来事をプロットしていきます。

各自が事前に作成したライフラインチャートをグループ内で共有し、「なぜこの時期が山だったのか」「この谷からどう乗り越えたのか」といったストーリーを語り合いました。

ライフラインチャートの共有の様子

このワークを通じて、単なる自己紹介では知ることのできない価値観や考え方の背景を理解することができました。
普段一緒に働いているメンバーの意外な一面や、これまでの経験を知ることで、「だからこの人はこういう考え方をするんだ」という理解が深まったように思います。

オフサイトミーティング後は懇親会で親睦を深める

オフサイト終了後は、懇親会を実施しました🍻

ワークで共有した内容をきっかけに、さらに深い話ができたり、普段あまり話す機会のないメンバー同士が打ち解けたりと、チームとしての一体感が生まれた時間となりました。

※ 筆者が飲みすぎたため懇親会中の写真がありませんでした・・・

オフサイトミーティングを終えて

今回のオフサイトミーティングを通じて、以下のような効果を実感しています。

  • 心理的安全性の向上:お互いの人となりを知ることで、気軽に相談・質問しやすい関係性ができた
  • コミュニケーションの活性化:共通の話題が増え、日々のコミュニケーションがより円滑に
  • チームとしての一体感:「同じチームの仲間」という意識がより強くなった

プロダクトチームが今後も拡大していく中で、こうした「相互理解」の機会を継続的に設けていくことが重要だと改めて感じました。

最後に

プロダクトチームが23名になって、デリバリーできる価値の総量は増えてきました。
その一方で、普段の仕事だけだと「知っているようで、実は人となりまでは知らない」が増えやすいのもこのタイミングだなと感じています。
だからこそ、お互いのことをより深く知ったうえで、一緒に働ける状態をつくるために、このタイミングで相互理解のオフサイトミーティングを実施できたのは本当に良かったです。

この日できた関係性をより強固にし、日々のプロダクトづくりにしっかりつなげていきます💪

 

We're Hiring!!!

miiveでは一緒に福利厚生の未来を作ってくれる仲間を募集しています。ちょっとでも興味のある方は一度ぜひお話しましょう!

hrmos.co

また、定期的にお酒と軽食を楽しみつつ、カードゲームやボードゲームで遊びながら、miiveメンバーと気軽に仕事や働き方の話ができる「miive bar🍷」を開催しています。

「いきなりカジュアル面談はちょっとハードルが高い…」という方はぜひ、miive barにご参加ください!

「〇〇さん、ミーティング来られそうでしょうか...?」をなくす

こんにちは。せーじと申します。現在は株式会社miiveで、Webやバックエンド、アプリの開発をしております。私は業務や私生活で日常的にRaycastを使っています。

突然ですが、Slackでこんなメッセージが来ることないですか?

〇〇さん、ミーティング来られそうでしょうか...?

私は「多忙すぎてミーティングに気づかない」みたいな経験はありませんが、「コーディングにノリノリの時にミーティングに気づかない」ことが本当にたまにありました。

そんな時に限って大事なミーティングが入ってたりするんですよね。

余談ですが、私が大学4年生のころはコロナ真っ最中でした。そのため、卒論の発表もオンラインです。そんな時に限って、「いつもできていた画面共有ができない!」なんてこともありました。ハプニングは時と場を選ばないの本当につらい。

この記事では一人でも多くの人が「大事なミーティングに気づかず遅れてしまう」ことを阻止するために、Raycastの Auto-Join Meetings についてお話しします。

※この記事で利用してるRaycastのバージョンはVersion 1.104.1です

Auto-Join Meetings

Auto-Join Meetingsを設定していると、ミーティングの30秒~1分ほど前に画面ポップアップがでてきます。 オンラインであればEnterでそのままミーティングに参加できます。

また、Raycastを起動すると指定した時間内にあるミーティングを表示してくれるようになります。こちらもEnterでそのままミーティングに参加できます。

さらに、Menu Barにも予定までの時間、残り時間を表示することができます。

仕組みは?

Raycastから以下のカレンダーアプリを読み込み、予定の有無、オンラインミーティングのURLを読み込んでいます。

どうやって設定するのか?

この機能はRaycastの「Calendar」Extensionを使って実現できます。このExtensionは初めからRaycastに組み込まれているので、別途インストールする必要はありません。

まずは、Raycastの「Extensions」の設定画面を開いてください。

以下のように検索してEnterを押すと設定画面がでてきます。

「calendar」と検索すると該当のExtensionを絞り込めます。

初期設定はポチポチすることで設定できます。

Tips

対象のカレンダーを絞りたい

「Extensions」の設定画面 > Calendar から対象のカレンダーを絞ることができます。

予定が入っているのに、出てこない

このパターンは原因が3つ考えられます。

1. カレンダーアプリにアカウントが追加されていない

例えばGoogle Calendarの予定をRaycastで表示するようには、初めにカレンダーアプリへのGoogleアカウントの追加が必要になります。

カレンダーアプリの設定画面からアカウントを追加してください。

2. カレンダーアプリに予定が同期されていない

同期する頻度も設定画面から変更可能です。1分にしておくと、直前に入ったミーティングも見逃すことがなくなります。

1分にしても困ったことがないので、1分に設定しておくことがおすすめです。

3. オンラインのミーティングURLが設定されていない

Google Calendarの場合、一人だけの予定にはMeetのURLが追加されません。 以下の設定がオン(チェックボックス入っている)場合、オンラインミーティングのURLが設定されていない予定はRaycast上に表示されません。

Show Events in Menu Barの設定値を変更することで表示する予定を絞ることができます。

例えば「10min」に設定すると、10分以内に開始する直近の予定がMenu Barに表示されるようになります。

Raycastの検索窓に出てくる予定を絞りたい

先ほど、以下のような表示がされると紹介しました。これが表示される時間をShow events before/after they startで変更できます。

例えば「5min」にすると、予定が始まる5分前~開始してから5分後まで以下のような表示がありますが、それ以外のタイミングでは表示されなくなります。

その他にも

RaycastのCalendar Extensionには数日先までの予定をリスト表示したりする機能もあります。ぜひ試してみてください!

終わりに

miiveはFintechの企業です。そのためセキュリティに厳しいイメージをお持ちの方も多いと思います。もちろんセキュリティについてはしっかりとしたルールが存在しますが、一方で、開発者の体験を損なわないために、新しい技術やサービス、アプリなどは積極的に利用できる制度・環境が整えられています。

少しでもご興味を持っていただけましたら、カジュアル面談や、miive bar(ゆるく雑談とボードゲームをする会)なども実施しています。ぜひご参加ください!お待ちしております!

hrmos.co

miive.notion.site

QAとして最初にやったこと

あいさつ

こんにちは、miiveでQAエンジニアやってるragiです。

QAエンジニアやってるといいつつ、11月に入社したので、まだまだペーペーなもんで、日々諸先輩方に支えてもらいながら、仕事しています。

さて今回、人生初ブログを書くわけですが、人生一発目の記事って何がええんや?という壮大な疑問から、miiveのブログなので、まずはmiiveでやったこと書くかーと思い、タイトルの通りの記事を書こうと思い立ちました(実績も少ないので)

miiveのQA状況

miiveのQA体制は、社員1名(ragi)、業務委託1名の2名となっています。
面接時、QAチーム立ち上げとの話だったので、ゼロスタートを覚悟してたんですが、業務委託の方が下地を作ってくれてたので、とても助かりました(マジで感謝)

ただ当然のことながら、下地はあるが充足はしてない。なので、現状把握も兼ねて、抱えている問題を把握する必要がありました。

現状やれていること、大丈夫なことは、業務委託の方との会話や実績(対応内容、成果物など)から把握できましたので、ヨシ。
対して、問題は業務委託の方がまとめていたものもありましたが、ragi自身が思ったもの、感じたものもあり、お互いが持っているものを洗い出して整理しよう!という提案をしました。

これが始まりです。

問題の洗い出しと整理と管理

何かフレームワークが活用できればよかったんですが、特に思いつかなかったので、とりあえず、FigJam使って2人で思いつく問題を付箋(ピンクと黄色)でペタペタ。

それはどこにアクションすれば解決しそうか(QAチーム、開発チーム、会社)をそれぞれ分類しつつ、類似問題をグルーピング。という感じで、整理していきました↓

結構問題が出た笑

QAチームが抱えている問題の洗い出しと整理できたので、あとは課題に落とし込んで対応していけば、自然と問題解決ができることになります。

課題も、グルーピングしたものに付箋(紫)を貼っていって整理した後、問題とあわせてNotionで管理して、週1で専用の時間をとって課題解決を進めています(まずは目下のQAチームの課題に注力)

※施策管理表の「E2Eテスト自動化」は、QA観点での整備がまだ途中という意味で課題にしていますが、開発側ではすでに CI/CD 上に E2E テストが組み込まれています

やってみて

QAチームの立ち上げで採用いただいての初仕事が上記なわけですが、個人的には大収穫でした。

また、QA2人でアレコレ書き出して話しあって、目先の意識合わせができたのも良かったと思っています。

ただ、これで問題が打ち止めになるわけでもなく、これから先も新しい問題が出てくるので、四半期に1回ぐらいのペースで、この取り組みをやっていこうと考えています。

最後に

QAという仕事は、プロダクトQA(開発物のテスト)に目線が行きがちですが、チーム自体の品質を上げるというのも、QAの役割だと思っています。
対象のチームは、QAチーム、開発チーム、会社(広義の意味でチーム)、どれもです。

まずは現状把握を兼ねて、QAチームから着手しましたが、開発チームや会社へアクションの必要がある問題もあったので、徐々に開発チーム、会社と目線を上げていけたらと考えています。

「良き品質のチームは、良き品質のサービス・プロダクトを届けられる」

そんな信念でQAを推進して、miiveに貢献したいと思っています。

まだ技術でゴリゴリ何かを推進しているわけではなく、泥臭く進めていますが、並行してテスト自動化やAI活用なども絶賛推進中ですので、またブログを書ければと思います。

we are hiring!

miiveはWe Work 新宿を拠点にしており、気軽に仕事や働き方を語れる「miive bar」を定期的に開催中です。
miiveについて気になった方はぜひご連絡ください!

miive.notion.site

カード決済の突合設計:BASE1 / BASE2 をどう突合させるか。〜請求と返金のマッチングの裏側〜

あいさつ

こんにちは。miiveのmineです。カード決済のお金にかかわるところを開発しています。

今回は半年以上関わってきたBASE1(仮売上)とBASE2(請求)の突合についてお話ししていこうと思います。

業務用語 決済用語 意味
BASE1 Authorization / Void / Cancel 与信
BASE2 Capture / Refund 売上確定

カード決済において仮売上と請求は切っても切れない関係ですが、突合するのは一苦労です。

カード決済の業務で、
「仮売上」と「請求」の突合しようとした場合、
だいたいの人は最初にこう思います。

仮売上と請求って、IDでくっつければ終わりじゃないの?

私も最初はそう思っていました。そうだったら本当に良かったです。。。

しかし、実運用ですぐにわかります。

IDだけではデータは合いません。時には合います。これ本当に曲者です。

完全な整合性が取れない以上、信用してはいけません。

以下、一例で他にもいろいろあります

  • IDが違う。そもそも空白。
  • 日付がズレる
  • 加盟店IDが違う

「合わない」のが普通、という世界でした。

今回はBASE1の時点で売上と返品が発生した場合、BASE2で同一の決済に対して徴収と返金が再度処理されないようにするためBASE1と突合して、重複処理をさせないようにする実装をした経験からくるお話です。


売上・返金と BASE1 / BASE2 の関係

場面 業務用語 決済用語 BASE1 / BASE2 との関係 やさしい説明
カードが使えるか確認 仮売上 Authorization BASE1 「このカードで払えますか?」を確認するだけの処理。この時点ではまだ実際のお金は動きません。
カードのユーザー視点ではここでお金が動いているように見えます。
決済システムでもお金が動いているように処理しますが、現実では動きません。
売上前に取り消す 売上取消 Void / Cancel BASE1 「やっぱり(仮売上を)やめます」を伝える処理。この時点ではまだ実際のお金は動きません。
カードのユーザー視点ではここでお金が動いているように見えます。
決済システムでもお金が動いているように処理しますが、現実では動きません。
売上を確定する 売上確定 Capture BASE2 実際にカード会社へ請求がいき、本当に支払いが確定する処理です。
お客様視点では仮売上でお金は動いていますので、金額変更がなければカード会社側では何もしないです。
支払い後に戻す 返金 Refund BASE2 「すでに払ったお金(売上確定)を返す」処理です。本当に返金が確定する処理です。
お客様視点では売上取消でお金は動いています。

返金は売上確定とほぼワンセットなので、返金の場合は売上確定1000円、返金1000円とデータが連携されます。日時も順番もバラバラなのでBASE1とBASE2で二重処理しないためにもBASE1との突合が必要になります。


突合とは「一致させる」作業ではない

この業務を続けていく中で、
私は突合を次のように定義するようになりました。

突合とは、
フィルターを一つずつ追加していく作業である。

一致しているものを探す、のではなく、

  • 1つ1つの条件を積み上げる
  • 条件は厳しくし、怪しいと思ったら突合させません。
  • 突合対象は正確を期し、誤突合は発生させてはいけません。
  • 誤突合するくらいなら通してしまいましょう。あとで調査します。

そんな設計にしています。

最初のうちはよく突合条件からこぼれ落ちてそのまま処理されてしまう。

調査は一苦労。いろいろな角度から目で見てマッチング。フィルターとして有用なら追加します。


BASE1 と BASE2 はそもそも別物

BASE1(仮売上)

  • 与信結果
  • 金額は仮
  • 実売上ではない
  • キャンセルされることもある

BASE2(請求)

  • 売上確定
  • 実際に請求される金額
  • 会計に乗るデータ

BASE1とBASE2は
「同じ取引を表現しているが、同じデータではない」

ここを混ぜると設計が破綻します。

突合に使われるものとしては主に以下のような情報があります。

  • 契約番号 (これは信用できるがこれだけでは突合できないです)
  • 承認番号
  • 取引ID
  • 金額
  • 日時
  • 加盟店情報

 


図解:突合は「ふるい」にかける作業

誤解されがちな突合

ID一発で一致!

現実はこうです。

フィルターに検知されたデータのみ突合。

これでも漏れる時は漏れますので、日々研鑽を心がけます。


最初は「厳しく」突合します

実装初期、私は意図的に条件を厳しくしました。

最初に使っていた条件

  • 承認番号
  • 取引ID
  • 契約番号
  • 金額
  • 日時
  • 45日を超えない。※これは仕様で45日を超えてBASE2が来ない取引は不成立として候補から除外するためです

誤突合は最悪
未突合は調査できる

「絶対に間違わない突合」を最優先しました。

最初は突合できないことが多かったが、日々の観察と調査からフィルター②、フィルター③などを追加していき狙い通りの突合ができるようになっていきました。日々改良を施して少しずつ100%に近づけていきます。100%にはなりませんが観察対象(マッチング失敗データ)が日々減っていくのは嬉しかったです。


実運用では必ずズレる

  • 承認番号が違う
  • 取引IDが違う
  • 日付がずれる
  • 数日後にくる
  • 加盟店IDが違う

BASE2 は「到着即処理」が鉄則

BASE2 到着
   ↓
即突合
   ↓
候補抽出
   ↓
保存

放置すると:

  • 未請求
  • 二重請求
  • 問い合わせ地獄

おわりに

システムは、
正しく動くより、
誤らないことの方が重要な場面があります。

カード決済は、その典型だと思います。

数字の誤り、誤情報はお金を扱う場面ではひとつのミスでも致命的になります。

安直な突合はやめましょう。

この記事がこれから決済に関わる誰かの設計のヒントになれば幸いです。

we are hiring!

miiveはWe Work 新宿を拠点にしており、気軽に仕事や働き方を語れる「miive bar」を定期的に開催中です。
miiveについて気になった方はぜひご連絡ください!

miive.notion.site

aws login が miive の開発で使えるかどうか検証する

miiveでエンジニアのsato-shinです。 組織の人数が一気に増え、入社ワークフローの自動化を本格的に取り組まねばと思う今日この頃です。

aws login について

2025年11月19日にawscliにloginコマンドが爆誕しました🚀
https://aws.amazon.com/jp/blogs/security/simplified-developer-access-to-aws-with-aws-login/

これによりAWS CLIAWS SDKsを利用する際の認証情報の取得が簡単かつ安全になりました。

利用方法はとても簡単で $ aws login をすると、ブラウザが開くのでぽちぽちするだけです。
なお、 awscli v2.32.0 以降 が必要ですので、あらかじめawscliのアップデートはかけておきます。

aws loginが成功すると AWS CLIの各種コマンドで権限の範囲内で情報を取得できるようになります。

miiveでの課題

miiveではAWSの一時的な認証情報をsaml2awsを利用して取得しています。IDPにはgoogle workspaceを利用しています。
チーム内でsaml2awsでの認証時にMFAが不安定だったり、手数が多く面倒という声がありました。
saml2awsの脱却は前々から考えて調査はしていたのですが、良い代替方法が見つからず放置していたところに
aws login がやってきてテンションが上がったため実験してみました。

AWS SDK からAWSのリソースにアクセスしてみる

miiveではgoを使っているのでAWS SDK for Go v2を使ってS3の情報を取得してみます。
AIにプログラムを作らせて $ go run main.go をしてみます。

failed to list buckets: not found, ResolveEndpointV2

なるほど、なるほど。AWS SDK for Go v2のバージョンが古かったようです。
https://github.com/aws/aws-sdk-go-v2/releases/tag/release-2025-11-19.2
このリリース以降でaws loginで発行された認証情報の形式をサポートしているようなので、AWS SDKを最新版にアップデートします。

AWS SDKのアップデート後、再度 $ go run main.go を実行すると無事にS3の情報を取得できるようになりました🎉

docker上で実行してみる

docker上で実行すると問題が発生するかどうか確認していきます。
実行してみると以下のエラーに遭遇しました。

failed to list buckets: operation error S3: ListBuckets, get identity: get credentials: failed to refresh cached credentials, save token: open /root/.aws/login/cache/xxx.json: read-only file system

AWS CLIAWS SDKではrefreshTokenを利用して自動的に認証情報を更新しています。
なので、~/.aws/login へdockerから更新ができるようにパーミッションを与える必要があります。
aws login で取得した認証情報の中身を確認すると、expiresAtが発行から15分で、refreshTokenの項目が確認できます)

Dockerへマウントしている .aws ディレクトリへ書き込み権限を与えて再度実行したところ、認証情報が更新されS3の情報を取得することができました。

まとめ

最小サンプルを作ってみることで、aws loginによりsaml2awsから脱却できそうな未来は見えてきました。
実際にmiive開発環境で利用開始できたら、また筆をとろうと思います。
今回利用したコードはGitHubにおいてありますので、よかったら参考にしてみてください。
https://github.com/sato-shin/aws-login-test

we are hiring!

miiveはWe Work 新宿を拠点にしており、気軽に仕事や働き方を語れる「miive bar」を定期的に開催中です。
miiveについて気になった方はぜひご連絡ください!

miive.notion.site