きっかけは「防犯カメラの映像、誰も見てない問題」
日本のコンビニや飲食店には、だいたい防犯カメラがついている。でも実際にその映像をリアルタイムで見ている人はほぼいない。何か起きたあとに巻き戻して確認する、それが現実だ。
「カメラの映像をAIがリアルタイムで見て、異常があったら通知してくれたら?」
このアイデア自体はありふれている。でも実際にやってみると、カメラ映像の解析、アラート配信、ダッシュボード、課金、マルチテナント...やることが山ほどある。普通にやったら半年かかる。
それを3週間でやった。
19スプリントサイクルの記録
1月29日に最初のコミットを打った。そこから毎日1〜2スプリントを回した。合計19スプリント。Claude Codeをフルに使って、設計→実装→テスト→デプロイのサイクルを1日2回転させる生活が続いた。
最初の1週間でやったこと:
- Rustで4つのクレート分割 — core(ドメインロジック)、api(HTTPハンドラ)、worker(映像解析ワーカー)、cli(管理ツール)
- Fly.io + PostgreSQL — 東京リージョンにデプロイ。SQLiteも考えたが、マルチテナントSaaSなのでPostgresを選んだ
- カメラ映像のRTSP取り込み — ffmpegでフレーム抽出し、Vision APIに投げる
2週目で課金とダッシュボードを作った。Stripeの組み込みはStayFlowで経験済みだったので、ほぼコピペで動いた。ダッシュボードはAskama(Rustのテンプレートエンジン)でSSRする構成にした。SPAを作る時間がなかった。
3週目はひたすらエッジケースの潰し込みと、マルチプラットフォームエージェントの統合だ。LINE通知、Telegram通知、メール通知。店舗オーナーが使い慣れたツールで受け取れるようにした。
技術的な判断とその理由
なぜRust 4クレートか? — 映像解析ワーカーはCPUバウンドで、APIサーバーはIOバウンド。別プロセスで動かしたかった。モノリポの中でクレートを分けておけば、将来ワーカーだけスケールアウトできる。
なぜFly.ioか? — Lambda+DynamoDBの組み合わせはchatweb.aiで使い慣れていたけど、WebSocketでリアルタイム通知を送りたかった。Fly.ioなら永続接続が簡単に張れる。Postgresもマネージドで使える。
なぜSPAじゃないか? — 時間がなかった。SSRなら1ファイルでページが完結する。React+Viteのセットアップ、ビルドパイプライン、APIクライアント生成...その全部をスキップした。正直、SSRで十分だった。
リリース日の数字
2月18日にmisebanai.comを公開した。初日のユーザー数は正直に言うと少ない。でもプロダクトが動いている、課金が通る、カメラ映像が解析される。3週間前にはゼロだったものが、ちゃんとSaaSとして機能している。
一番うれしかったのは、テスト店舗で「万引きっぽい動き」を検知してLINE通知が飛んだ瞬間だった。AIが映像を見て、判断して、人間に伝える。そのループが回った。
学んだこと
3週間でSaaSを出すには、「やらないことを決める」のが一番大事だった。管理画面のデザインは後回し。多言語対応も後回し。カスタムドメインも後回し。MVP(最小限の価値あるプロダクト)という言葉の意味を、体で理解した3週間だった。
技術的な詳細はこちらの記事にまとめている。Rustの4クレート構成、映像解析パイプライン、Fly.ioのデプロイ設定など。