ブログ一覧へ戻る

Cycle 6 でプライバシーポリシー・利用規約・特商法表記・オンボーディングウィザードが完成し、ミセバンAIは「合法的に公開できる」状態になった。法務と導線は整った。しかし、ベータユーザーが「実際の業務で使える」かどうかは別の話だ。

Sprint Cycle 7 では、ベータユーザーが日常業務に組み込める機能を揃える。3つの柱: csv_export.rs によるデータ出力、全18エンドポイントの API ドキュメント、そしてカスタム404エラーページ。Data Export × API Reference × Building in Public Day 2 のサイクルだ。

1. CSV Export API -- データを手元に

crates/api/src/csv_export.rs

CSV データ出力モジュール

来客データを CSV ファイルとしてダウンロードするモジュール。plan_guardcsv_export フィーチャーフラグと連携し、Pro / Enterprise プランのみ利用可能。

店舗オーナーが最も求める機能のひとつは「データを手元に持ち出す」こと。ダッシュボードで見るだけでなく、Excel で加工したり、他のツールに取り込みたい。CSV出力はそのニーズに直接応える。

エンドポイント設計

CSV Export フロー

GET /export/csv?from=2026-02-01&to=2026-02-23
JWT Authユーザー認証
plan_guardcsv_export チェック
Pro/Enterprise → CSV生成Content-Disposition: attachment
Free/Starter → 403プランアップグレード促進

実装コード

/// GET /api/v1/stores/me/export/csv
pub async fn export_csv(
    State(state): State<AppState>,
    AuthUser(user_id): AuthUser,
    Query(params): Query<CsvExportParams>,
) -> Result<impl IntoResponse, ApiError> {
    let store = get_store_by_owner(&state.pool, &user_id).await?;
    let tier = store.tier.as_deref().unwrap_or("free");

    // Plan guard: csv_export は Pro/Enterprise のみ
    if !tier_has_feature(tier, "csv_export") {
        return Err(ApiError::Forbidden(
            "CSV出力はProプラン以上で利用できます".into()
        ));
    }

    let rows = fetch_visitor_data(
        &state.pool,
        &store.id,
        params.from,
        params.to,
    ).await?;

    // CSV生成 (標準ライブラリのみ)
    let mut csv = String::from("日付,時間,カメラ名,来客数\n");
    for row in &rows {
        csv.push_str(&format!(
            "{},{},{},{}\n",
            row.date, row.time, row.camera_name, row.count
        ));
    }

    let filename = format!(
        "miseban_{}_{}_{}.csv",
        store.name, params.from, params.to
    );

    Ok((
        [
            (header::CONTENT_TYPE, "text/csv; charset=utf-8"),
            (
                header::CONTENT_DISPOSITION,
                &format!("attachment; filename=\"{}\"", filename),
            ),
        ],
        csv,
    ))
}

plan_guardtier_has_feature(tier, "csv_export") が最初の関門。Free/Starter ユーザーがこのエンドポイントを叩くと、403でアップグレードを促す。Pro/Enterprise ならCSVデータを生成し、Content-Disposition: attachment ヘッダーでブラウザにファイルダウンロードさせる。

Query パラメータ

#[derive(Deserialize)]
pub struct CsvExportParams {
    /// 開始日 (YYYY-MM-DD)
    pub from: NaiveDate,
    /// 終了日 (YYYY-MM-DD)
    pub to: NaiveDate,
}

fromto を必須パラメータにすることで、無制限のデータ取得を防ぐ。日付バリデーションは NaiveDate の Deserialize に任せている。不正な形式なら 400 Bad Request が自動で返る。

2. API Documentation Page -- docs.html

web/landing/docs.html

全18エンドポイントの API リファレンス

ベータユーザーや将来の開発パートナーに向けた、静的HTMLの API ドキュメント。認証方式、エンドポイント一覧、curl サンプル、レスポンス例を網羅。

APIドキュメントがないプロダクトは信用されない。ベータユーザーに「APIがある」と言っても、仕様書がなければ使いようがない。Cycle 7 では全18エンドポイントを体系的にドキュメント化した。

認証方式

# Supabase Auth でJWTトークンを取得
curl -X POST https://xxx.supabase.co/auth/v1/token?grant_type=password \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","password":"***"}'

# APIリクエスト (Bearer token)
curl https://misebanai.com/api/v1/stores/me \
  -H "Authorization: Bearer eyJhbG..."

エンドポイント一覧 (抜粋)

MethodPath認証説明
GET /api/v1/health Public ヘルスチェック
POST /api/v1/stores JWT 店舗登録
GET /api/v1/stores/me JWT 自店舗情報取得
PATCH /api/v1/stores/me JWT 店舗情報更新
POST /api/v1/cameras JWT カメラ登録
GET /api/v1/cameras JWT カメラ一覧取得
POST /api/v1/frames JWT フレーム送信 (画像解析)
GET /api/v1/analytics/daily JWT 日次分析データ
GET /api/v1/analytics/hourly JWT 時間帯別分析データ
GET /api/v1/stores/me/usage JWT 使用量・プラン情報
GET /api/v1/stores/me/export/csv JWT CSV出力 (Pro以上)
POST /api/v1/alerts JWT アラート設定
GET /api/v1/alerts JWT アラート一覧取得
POST /api/v1/line/webhook Public LINE Webhook受信
POST /api/v1/billing/checkout JWT Stripe Checkout Session作成
POST /api/v1/billing/portal JWT Stripe Customer Portal
POST /api/v1/webhooks/stripe Stripe Stripe Webhook受信
GET /api/v1/onboarding/status JWT オンボーディング進捗

レスポンス例

// GET /api/v1/stores/me/usage
{
  "tier": "pro",
  "cameras_used": 3,
  "cameras_max": 16,
  "retention_days": 90,
  "features": [
    ["basic_count", true],
    ["demographics", true],
    ["heatmaps", true],
    ["alerts", true],
    ["line_alerts", true],
    ["csv_export", true],
    ["api_access", true],
    ["custom_models", false]
  ]
}
// GET /api/v1/stores/me/export/csv
// Content-Type: text/csv; charset=utf-8
// Content-Disposition: attachment; filename="miseban_cafe_2026-02-01_2026-02-23.csv"

日付,時間,カメラ名,来客数
2026-02-01,09:00,入口カメラ,12
2026-02-01,10:00,入口カメラ,28
2026-02-01,11:00,入口カメラ,45
...

全エンドポイントに対して curl コマンド + 期待されるレスポンスJSON を記載。ベータユーザーがドキュメントだけで API 連携を実装できる状態を目指した。

3. カスタム 404 エラーページ

web/landing/404.html

ユーザーフレンドリーな 404 ページ

存在しないURLにアクセスしたユーザーを迷子にさせない。ブラウザデフォルトの404ではなく、ブランドに沿ったカスタムページで適切な導線を提供。

些細に見えるが、404ページの品質はプロダクトの信頼感に直結する。ブラウザのデフォルトエラー画面が表示されると「このサービスは雑に作られている」という印象を与える。カスタム404ページは、迷子になったユーザーを正しい場所へ誘導するナビゲーションの役割を果たす。

4. Before / After 比較

項目Before (Cycle 6)After (Cycle 7)
データ出力 なし CSV出力 (Pro以上)
API仕様書 なし 18エンドポイント文書化
エラーページ ブラウザデフォルト カスタム404ページ
ベータ準備 6/8項目 8/8項目完了

Cycle 6 まで残っていた「データ出力」と「API仕様書」の2項目が埋まり、クローズドベータに必要な全8項目が完了した。ダッシュボード、API、決済、法務、オンボーディング、データ出力、ドキュメント、エラーハンドリング。プロダクトとして公開するために必要な要素が揃った。

ベータチェックリスト 8/8: 認証、API、決済、プランガード、法務、オンボーディング、CSV出力、APIドキュメント -- 全項目 DONE。

5. 技術的判断

なぜこの設計にしたか

6. 成果と数字

~500
追加コード
18
API Docs
1
新規エンドポイント
7cycles
to beta

作成・更新したファイル

  1. crates/api/src/csv_export.rs -- CSV出力モジュール (新規、約80行)
  2. crates/api/src/main.rs -- mod csv_export 宣言、GET /api/v1/stores/me/export/csv ルート追加 (+15行)
  3. web/landing/docs.html -- APIドキュメントページ (新規、約350行)
  4. web/landing/404.html -- カスタム404ページ (新規、約60行)

「動くプロダクト」と「使えるプロダクト」は違う。データが出力でき、仕様書があり、迷子にならない。この3つが揃って初めて、ベータユーザーに「使ってください」と言えるプロダクトになる。

7. ロードマップ

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料金刷新完了 -- tier enforcement、8機能フラグ、セルフサーブ動線
Cycle 6
法務・オンボーディング完了 -- プライバシーポリシー、利用規約、特商法、ウィザード
Cycle 7
CSV出力・APIドキュメント・エラーページ完了 -- 本記事の内容。ベータ準備 8/8
Cycle 8
パブリックベータローンチ実店舗での動作検証、実データチューニング、フィードバック収集

7サイクルを経て、ミセバンAIはパブリックベータに耐えうる完成度に到達した。Cycle 8 ではいよいよ実店舗にデプロイし、実データでの動作検証とフィードバック収集に入る。ここからが本番だ。

7サイクル、7週間。ダッシュボードから始まって、API、決済、法務、そしてデータ出力とドキュメントまで。Building in Public で走り続けた結果、ベータに出せるプロダクトが出来上がった。次はユーザーの声を聞く番だ。

クローズドベータへの参加をお待ちしています。

ミセバンAIは、7スプリントサイクルで「使えるプロダクト」に到達。
既存の防犯カメラがAI店長に変わる、小規模店舗のための次世代AI分析。