ブログ一覧へ戻る

Cycle 5 までで、ミセバンAIは技術的に「動くプロダクト」になった。AI推論、DB永続化、リアルタイム通知、Stripe決済、プラン制限。しかし、日本でSaaSを公開するには「法的ページ」が必須だ。

Sprint Cycle 6 では3つの法務ページ (プライバシーポリシー・利用規約・特商法表記) を整備し、ダッシュボードに4ステップのオンボーディングウィザードを実装。セキュリティの強化も行い、クローズドベータ開始の準備を完了した。

1. なぜ法務ページが先なのか

日本でSaaSを公開・課金する場合、以下の法令対応が不可欠だ。

法務ページなしにクローズドベータを開始すると、初期ユーザーの信頼を損なう。特にカメラ映像を扱うサービスでは「映像データはどう扱われるのか」がユーザーの最大の関心事だ。技術の前に信頼。これが Cycle 6 の判断だ。

2. 法務ページ -- 3つのコンプライアンス文書

<!-- privacy.html -- カメラ映像セクション抜粋 -->
<section class="legal-section">
  <h2>4. カメラ映像データの取り扱い</h2>
  <p>当社は、お客様が接続したカメラから送信される
     映像フレームを以下の目的で処理します。</p>
  <ul>
    <li>AI推論による来客数カウント、属性分析、行動分析</li>
    <li>アラート(侵入検知、混雑検知等)の判定</li>
    <li>ダッシュボードへの分析結果の表示</li>
  </ul>
  <p>映像フレームはAI推論完了後、ご契約プランに応じた
     保持期間(Free: 7日、Starter: 30日、Pro: 90日、
     Enterprise: 最大10年)を経過した時点で自動削除されます。</p>
</section>

3. オンボーディングウィザード -- 初回体験を設計する

法務ページが「信頼」なら、オンボーディングは「体験」だ。初回ログインからカメラ接続までの導線が悪いと、Free ユーザーは価値を体感する前に離脱する。

1

Welcome

ミセバンAIへようこそ。サービスの概要と3つのステップを説明。

2

Store Info

店舗名、業種、住所を入力。これがダッシュボードの基本情報になる。

3

Camera Setup

カメラのRTSP URLを入力して接続テスト。映像が届けば成功。

4

Done!

セットアップ完了。CSS-only紙吹雪アニメーションで達成感を演出。

web/dashboard/onboarding.js

4ステップ オンボーディングウィザード

// オンボーディングウィザード -- コア実装
const STORAGE_KEY = 'miseban_onboarding_done';

function initOnboarding() {
  // 既に完了済みならスキップ
  if (localStorage.getItem(STORAGE_KEY) === 'true') return;

  let currentStep = 1;
  const totalSteps = 4;
  const overlay = createOverlay();

  function renderStep(step) {
    switch (step) {
      case 1: return renderWelcome();
      case 2: return renderStoreInfo();
      case 3: return renderCameraSetup();
      case 4: return renderComplete();
    }
  }

  function nextStep() {
    if (!validateStep(currentStep)) return;
    currentStep = Math.min(currentStep + 1, totalSteps);
    overlay.innerHTML = renderStep(currentStep);
    if (currentStep === totalSteps) triggerConfetti();
  }

  function complete() {
    localStorage.setItem(STORAGE_KEY, 'true');
    overlay.remove();
  }

  // 初期表示
  document.body.appendChild(overlay);
  overlay.innerHTML = renderStep(1);
}

CSS-only 紙吹雪アニメーション

/* CSS-only confetti -- JSライブラリ不要 */
@keyframes confetti-fall {
  0%   { transform: translateY(-100vh) rotate(0deg); opacity: 1; }
  100% { transform: translateY(100vh) rotate(720deg); opacity: 0; }
}

.confetti-piece {
  position: fixed;
  width: 10px;
  height: 10px;
  top: -10px;
  animation: confetti-fall 3s ease-in-out forwards;
}
.confetti-piece:nth-child(odd)  { background: var(--indigo-500); }
.confetti-piece:nth-child(even) { background: var(--amber-500); }

/* 20個の紙吹雪を異なるタイミング・位置で配置 */
.confetti-piece:nth-child(1)  { left: 5%;  animation-delay: 0s; }
.confetti-piece:nth-child(2)  { left: 15%; animation-delay: .1s; }
.confetti-piece:nth-child(3)  { left: 25%; animation-delay: .2s; }
/* ... 20個まで展開 */

紙吹雪は純粋CSSで実装した。canvas-confetti 等の外部ライブラリを入れる選択肢もあったが、オンボーディングの最終ステップだけで使う演出に npm パッケージを追加するのはオーバーキル。20個の div@keyframes だけで十分な達成感を演出できる。

4. セキュリティ強化

web/dashboard/auth.js

セッション管理・自動リダイレクト

// セッション検証 -- 5分間隔
const SESSION_CHECK_INTERVAL = 5 * 60 * 1000; // 5分

function startSessionWatcher() {
  setInterval(async () => {
    const { data: { session }, error } = await supabase.auth.getSession();
    if (error || !session) {
      console.warn('Session expired, redirecting to login');
      window.location.href = '/dashboard/login.html';
    }
  }, SESSION_CHECK_INTERVAL);
}

// 401 インターセプター
async function apiFetch(url, options = {}) {
  const res = await fetch(url, {
    ...options,
    headers: {
      ...options.headers,
      'Authorization': `Bearer ${getAccessToken()}`,
    },
  });
  if (res.status === 401) {
    window.location.href = '/dashboard/login.html';
    return;
  }
  return res;
}

apiFetch はダッシュボード内の全API呼び出しを統一するラッパー関数だ。認証ヘッダーの付与と 401 ハンドリングを集約することで、各ページでの個別実装を排除した。

5. Before / After -- ベータ開始前後の比較

項目Cycle 5 (Before)Cycle 6 (After)
法務ページなし (フッターリンクは # 空リンク)privacy / terms / legal 3ページ完備
初回体験ログイン後いきなりダッシュボード4ステップウィザードで丁寧に誘導
セッション管理トークン切れで無言のエラー5分検証 + 401自動リダイレクト
キーボード操作なしショートカットオーバーレイ
オンボーディング永続化なしlocalStorage で完了フラグ管理

6. クローズドベータ開始チェックリスト

Cycle 1-6 の成果を総合すると、クローズドベータに必要な項目がすべて揃った。

ダッシュボード UI + Supabase Auth (Cycle 1)
Rust API + DB パイプライン (Cycle 2)
LINE通知 + リアルタイムアラート (Cycle 3)
Stripe 決済 + 4プラン (Cycle 4)
プラン制限 + LP料金刷新 (Cycle 5)
プライバシーポリシー / 利用規約 / 特商法表記 (Cycle 6)
オンボーディングウィザード (Cycle 6)
セッション管理 + 401リダイレクト (Cycle 6)

6つのスプリントサイクルを経て、「技術デモ」から「ベータ公開可能なプロダクト」になった。法務、課金、オンボーディング。地味だが、これが本物のプロダクトと個人プロジェクトを分ける境界線だ。

7. 技術的判断

なぜこの設計にしたか

8. 成果と数字

~700
追加コード
3
法務ページ
4
ウィザードステップ
6Cycle
ベータ準備完了

作成・更新したファイル

  1. web/landing/privacy.html -- プライバシーポリシー (新規、約180行)
  2. web/landing/terms.html -- 利用規約 (新規、約160行)
  3. web/landing/legal.html -- 特定商取引法に基づく表記 (新規、約100行)
  4. web/dashboard/onboarding.js -- オンボーディングウィザード (新規、約150行)
  5. web/dashboard/auth.js -- セッション検証 + 401リダイレクト (+60行)
  6. web/dashboard/index.html -- オンボーディング統合 + ショートカット (+50行)

9. 次のサイクルで何をするか

Cycle 1
ダッシュボード・DB・認証完了 -- UI、6テーブル、Supabase Auth
Cycle 2
Rust API × Supabase (sqlx + JWT)完了 -- 7エンドポイント、データパイプライン
Cycle 3
LINE通知Bot + リアルタイムアラート完了 -- 5エンドポイント、LINE Messaging API
Cycle 4
Stripe決済統合完了 -- Checkout Session、Customer Portal、Webhook
Cycle 5
プランガード + LP料金刷新完了 -- plan_guard.rs、LP pricing最適化
Cycle 6
法務・オンボーディング・ベータ準備完了 -- 本記事の内容
Cycle 7
クローズドベータテスト実店舗での動作検証。実データによるチューニング
Cycle 8
パブリックベータフィードバック反映、パフォーマンス最適化、広告開始

Cycle 7 ではいよいよクローズドベータテストを開始する。実際の店舗にカメラを接続し、本物の来客データでAI推論の精度を検証する。テスト環境と本番環境のギャップ、カメラ設置角度による精度変動、LINE通知の配信遅延。実データでしか見えない課題を洗い出すフェーズだ。

法務ページとオンボーディング。華やかさはないが、ユーザーの「信頼」と「体験」を支える基盤だ。この地味な仕事を飛ばしたプロダクトは、市場で必ずつまずく。

クローズドベータに参加しませんか? 実店舗での AI 見守りを一緒に検証しましょう。

ミセバンAIは、スプリントサイクルで高速に進化中。
既存の防犯カメラがAI店長に変わる、小規模店舗のための次世代AI分析。