電気通信大学 Urban Bee Club の公式サイトです。ミツバチの知性、都市養蜂、IoT・AI研究を、子供から研究者まで楽しめる形で伝えます。
- 公開5画面: Home / ハチのひみつ / スマート巣箱 / 活動と研究 / 参加・問合せ
- Tumblr
#news・#galleryと Notion「Bee Diary」の連携(未設定時は表示確認用データ) - Supabaseへの問い合わせ保存、IoT時系列データ取得・認証付き投入
- WebGLの自律飛行ミツバチ。低性能端末、タッチ端末、
prefers-reduced-motionではCSS版へ自動切替 - Stripe Checkoutを使うショップと月額88円サロン
- Supabase Magic Link認証、会員限定ギャラリー、会員割引コード発行
- Feature Flag無効時のシークレット画面・APIの404化
- レスポンシブ表示、キーボード操作、スキップリンク、十分なコントラスト、動きの抑制設定
Node.js 20以上を用意します。
npm ci
copy .env.example .env.local
npm run devhttp://localhost:3000 を開きます。外部サービスの変数が未設定でも、公開画面はデモデータで確認できます。
npm run lint
npm run typecheck
npm test
npm run build
npm run audit:allまとめて実行する場合は npm run check を使用します。
.env.example を .env.local にコピーし、必要な値を設定します。秘密鍵を NEXT_PUBLIC_ 付き変数へ入れないでください。
- Supabaseプロジェクトを作成します。
supabase/migrations/001_initial_schema.sqlと002_security_hardening.sqlを番号順にSQL EditorまたはCLIで適用します。- Project URL、anon key、service role keyを設定します。
- AuthのSite URLを本番URLにし、
/auth/callbackをRedirect URLへ追加します。 hivesに巣箱を1件作成し、そのUUIDをセンサーノードへ設定します。
service role keyはサーバー専用です。ブラウザへ渡さず、VercelではProduction / Previewを分けて管理します。
旧Bearer token方式は廃止されています。IOT_INGEST_KEYS に端末ごとのKey ID、固定hive UUID、独立した32 bytes以上のsecretを設定し、HTTPSでHMAC署名付きリクエストを送ります。
POST /api/iot/readings
X-UBC-Key-Id: sensor-a
X-UBC-Timestamp: <UNIX秒>
X-UBC-Idempotency-Key: <UUID>
X-UBC-Signature: v1=<timestamp + LF + UUID + LF + raw JSONのHMAC-SHA-256>
Content-Type: application/json
{
"hiveId": "00000000-0000-0000-0000-000000000000",
"recordedAt": "2026-06-30T12:00:00Z",
"temperature": 34.5,
"humidity": 58.2,
"weight": 38.7,
"activity": 72
}正規化対象byte列、署名コード例、鍵ローテーションは docs/SECURITY.md を参照してください。
Tumblr API keyとブログ識別子を設定します。#news はホーム、#gallery は会員ギャラリーへ最大5分程度で反映されます。本文はHTMLとして挿入せず、プレーンテキストへ変換しています。
Integrationを「Bee Diary」データベースへ接続し、データベースIDとTokenを設定します。次のプロパティ名を使用します。
| プロパティ | 型 | 値 |
|---|---|---|
| タイトル | Title | 記事名 |
| 概要 | Rich text | カード用の短い説明 |
| ステータス | Select | 公開 |
| 公開日 | Date | 公開日 |
| カテゴリ | Select | 養蜂日誌、研究、技術など |
- Stripeでショップ商品3点のPrice、88円/月のrecurring Price、会員割引用Couponを作成します。
- 対応する環境変数を設定します。
- Webhook URLを
https://<domain>/api/stripe/webhookにし、checkout.session.completed、customer.subscription.updated、customer.subscription.deletedを購読します。 - Signing secretを設定します。
- Test/Live mode、application ID、割引コード用HMAC secretを設定します。
- 大学・担当教授の正式許可後に限り、対象フラグを有効化して再デプロイします。
ENABLE_SECRET_SHOP=true
ENABLE_SALON=true許可前は必ず両方を false のままにします。false時はナビ・フッターにリンクが出ず、画面、Checkout API、認証API、Webhookも404になります。robots.txt とサイトマップにもシークレットURLを公開しません。
- 長文・研究記録: Notionでページを作り、ステータスを「公開」にします。
- 速報: Tumblrへ
#newsを付けて投稿します。 - 会員写真: Tumblrへ
#galleryを付けて投稿します。 - 問い合わせ: Supabaseの
contact_submissionsを管理者権限で確認します。必要なら固定の通知Webhookも設定できます。 - センサー障害: 最後の取得データまたはデモデータと「ハチたちはお休み中」を表示し、公開画面をエラーにしません。
Vercelへリポジトリを接続し、環境ごとの変数を登録します。main のデプロイ前にCIで npm run check を実行してください。大学サブドメインを使う場合は、Vercelが示すDNSレコードを大学ネットワーク担当へ申請します。
.env*、Supabase service role、Stripe secret、IoT device secretをGitへ追加しません。- RLSと列権限により、会員は自分の会員状態・有効な割引表示列だけを読めます。
- 商品価格と在庫はCheckout APIがサーバー側で再検証します。ブラウザから金額を受け取りません。
- Stripe Webhookは署名、環境、application metadata、Price、イベント冪等性を検証してからDBを更新します。
- 問い合わせと認証には本文上限、同一Origin/Fetch Metadata検査、Supabase共有レート制限があります。本番で共有制限を利用できない場合はfail closedします。
- IoTは端末別HMAC、時刻窓、巣箱固定、DB冪等性で保護します。
- HTMLはリクエストごとのnonce付きCSPを使用し、scriptの
unsafe-inlineを許可しません。
脅威モデル、全設定、migration、検証結果、残余リスク、インシデント対応は docs/SECURITY.md を参照してください。
LICENSE を参照してください。生成済みヒーロー画像の利用条件は、プロジェクトの公開方針に合わせて確認してください。