技術スタック
Tech stack
Parky で採用している主要技術とその役割、配置場所の一覧です。
どのプロダクトがどれを使っているかを素早く把握するためのリファレンスです。
The major technologies Parky uses, their responsibilities, and which product relies on them.
A quick reference to see which client consumes what.
BFF(クライアントが叩く唯一の API 層)BFF (the only API surface clients hit)
| 技術 | Tech |
用途 | Purpose |
使用プロダクト | Used by |
| Cloudflare Workers |
全クライアント共通の BFF ランタイム。/v1/* を単一 API 層として提供。東京 PoP で Supabase ap-northeast-1 と至近 |
Shared BFF runtime serving /v1/* as the single API surface. Tokyo PoP colocated near Supabase ap-northeast-1 |
All (Flutter / Web / Admin) | All (Flutter / Web / Admin) |
| Hono |
Workers 上のルーティング・ミドルウェア。@hono/zod-openapi で OpenAPI と実装を連動 |
Routing/middleware on Workers. @hono/zod-openapi keeps implementation in sync with the spec |
— | — |
| OpenAPI 3.1 + Zod |
API 契約の Single Source of Truth(packages/api-spec/)。CI で TS / Dart クライアントを自動生成 |
Single source of truth for the API contract (packages/api-spec/). TS and Dart clients are regenerated in CI |
— | — |
| Cloudflare Cache API |
公開 GET のエッジキャッシュ。middleware/cache.ts が GET+200 に max-age=300 を付け、それ以外は no-cache |
Edge cache for public GET. middleware/cache.ts sets max-age=300 for GET+200, no-cache otherwise |
— | — |
Cloudflare KV (parky-cache) |
isolate 跨ぎキャッシュ。FCM OAuth access_token を 2 層キャッシュ(isolate Map + KV / TTL 55分)で共有 |
Cross-isolate cache. FCM OAuth access_token uses a 2-tier cache (isolate Map + KV, TTL 55 min) |
— | — |
| Cloudflare Rate Limiting binding |
ユーザー単位のレート制限(RATE_LIMIT_USER)。/v1/search/ai で 10 req / 60 秒 |
Per-user rate limiting via the RATE_LIMIT_USER binding. 10 req / 60 s for /v1/search/ai |
— | — |
Cloudflare Analytics Engine (parky_ai_usage) |
AI 呼出のテレメトリ集計。現行は PG ai_usage_logs と dual write、段階的に AE 単独化 |
Telemetry dataset for AI calls. Dual-writes with PG ai_usage_logs today; moving to AE-only |
— | — |
| Cloudflare Logpush / Workers Observability |
構造化ログ、req/sec、エラー率、レイテンシ分布([observability] enabled = true) |
Structured logs, req/sec, error rate, latency ([observability] enabled = true) |
— | — |
バックエンド(Workers から呼ばれるコア基盤)Backend (core, called from Workers)
| 技術 | Tech |
用途 | Purpose |
使用プロダクト | Used by |
| Supabase (PostgreSQL 15) |
全データの永続化。PostGIS 拡張で位置検索。Workers が Service Role で接続 |
Primary datastore with PostGIS for geo queries. Workers connect with the Service Role key |
All | All |
| Supabase Auth |
認証(メール+PW、OAuth、電話番号)。クライアントは SDK 経由で直接利用(例外①)、Workers は JWT 検証のみ |
Auth (email+password, OAuth, phone). Clients use the SDK directly (exception 1); Workers only verify JWTs |
All | All |
| Supabase Realtime |
テーブル変更のライブ購読。クライアント直接接続(例外②) |
Live table subscriptions. Clients connect directly (exception 2) |
Admin, Mobile | Admin, Mobile |
Cloudflare Hyperdrive (parky-db) |
Workers → Supabase Postgres の接続プール+グローバルキャッシュ。lib/db.ts の postgres.js が env.HYPERDRIVE.connectionString で接続(Direct Connection 経由、Supavisor は使わない) |
Connection pool + global cache for Workers → Supabase Postgres. lib/db.ts uses postgres.js via env.HYPERDRIVE.connectionString (Direct Connection; Supavisor bypassed) |
Internal | Internal |
| Cloudflare Cron Triggers |
定期ジョブ。*/10 * * * * で handleSponsorProximity を起動。pg_cron は使わず wrangler.toml の [triggers] crons に集約 |
Scheduled jobs — */10 * * * * invokes handleSponsorProximity. No pg_cron; schedules live in [triggers] crons |
Internal | Internal |
| Cloudflare Queues |
parky-store-sync(Google Play / App Store Connect API → DB upsert)と parky-fcm-dispatch(FCM 通知 fan-out)。各 DLQ 配線・max_retries=3 |
parky-store-sync (Google Play / App Store Connect APIs → DB upsert) and parky-fcm-dispatch (FCM fan-out). DLQs wired, max_retries=3 |
Internal | Internal |
| Cloudflare Workers AI |
エッジ推論(env.AI)。Instagram tool で DETR 物体検出を使って顔/ナンバープレート候補領域を検出 |
Edge inference (env.AI). Used by the Instagram tool for DETR object detection (face / license-plate candidate regions) |
Internal | Internal |
Cloudflare D1 (parky-instagram) |
SQLite at edge。Instagram tool 専用(Parky 本体の Supabase とは分離) |
SQLite at edge for the Instagram tool (isolated from Parky's main Supabase) |
Instagram tool | Instagram tool |
オブジェクトストレージObject storage
| 技術 | Tech |
用途 | Purpose |
使用プロダクト | Used by |
| Cloudflare R2 (S3 互換) |
駐車場画像・アバター・バッジ/テーマアセット・PDF など全バイナリの保管(bucket: parky)。旧 Wasabi は 2026-04-19 に廃止。Instagram tool 用に parky-instagram-assets 別 bucket も配線。 |
Holds all binary assets (bucket: parky) — parking images, avatars, badge/theme assets, PDFs. Wasabi was retired on 2026-04-19. A separate parky-instagram-assets bucket is wired for the Instagram tool. |
All | All |
R2 Custom Domain cdn.parky.co.jp |
匿名公開 GET 用のカスタムドメイン。R2_PUBLIC_BASE が未設定だと account-private endpoint(署名必須)にフォールバック |
Custom domain for anonymous public GET. If R2_PUBLIC_BASE is unset, falls back to the account-private endpoint (signature required) |
All | All |
Workers /v1/storage/upload-url |
R2 の presigned PUT URL を発行し、assets テーブルに s3_key を含むメタデータを登録するブリッジ。JWT 検証・user_id スコープで発行。クライアントは presigned URL に直接 PUT する(バイト列は Workers を経由しない) |
Mints R2 presigned PUT URLs and registers metadata (including s3_key) in the assets table. JWT-verified and scoped to user_id. Clients PUT bytes directly — bytes skip Workers |
Admin (write), All (read) | Admin (write), All (read) |
R2_ENDPOINT / R2_BUCKET / R2_ACCESS_KEY_ID / R2_SECRET_ACCESS_KEY / R2_PUBLIC_BASE |
Workers に必要なシークレット。wrangler secret put で登録 |
Secrets required by Workers, registered via wrangler secret put |
— | — |
フロントエンドFrontend
| プロダクト | Product |
スタック | Stack |
ホスティング | Hosting |
| 管理者ポータル | Admin portal |
React 19 + Vite + TypeScript + Lucide Icons |
Cloudflare Pages (parky-admin-dev → dev-admin.parky.co.jp / parky-admin-prod → admin.parky.co.jp) |
| モバイルアプリ | Mobile app |
Flutter (Dart) — mobileapp/prototype/flutter/ |
App Store / Google Play(将来) |
App Store / Google Play (future) |
| Web版 (一般向け) | Web app (public) |
Astro 5 + React 19 (islands) + Tailwind CSS v4 + MDX + Pagefind + Mapbox GL JS |
Cloudflare Pages (parky-home-dev → dev.parky.co.jp) |
| メディア (記事) | Media (articles) |
Astro content collection(旧 WordPress 子テーマ blogsy-child は廃止) |
Astro content collection (legacy WordPress blogsy-child retired) |
dev.parky.co.jp/media/ (Cloudflare Pages) |
| LP | LP |
静的HTML | Static HTML |
Cloudflare Pages (parky-lp-prod → parky.co.jp) |
| Docs(本サイト) | Docs (this site) |
静的 HTML + Mermaid | Static HTML + Mermaid |
Cloudflare Pages (parky-docs-dev → dev-docs.parky.co.jp) |
| Mobile Web Mock | Mobile Web Mock |
単一 HTML + Mapbox GL JS | Single HTML + Mapbox GL JS |
Cloudflare Pages (parky-app-mock-dev → dev-app-mock.parky.co.jp) |
地図・位置情報Maps & geo
- Mapbox GL JS — 地図表示・マーカー・経路表示。全クライアントで統一利用。Map rendering, markers, and routing — used by every client.
- PostGIS — 駐車場の半径検索、Nearest検索。Radius and nearest-neighbour queries for parking lots.
検索Search
- Pagefind (
astro-pagefind) — Web 版の /search はビルド後の dist/ をスキャンして生成される静的 Pagefind インデックスをクライアントから fetch する方式。ランタイムで Supabase に直接クエリは発行しない。The web app's /search reads a static Pagefind index generated after build from dist/ — no direct Supabase query at runtime.
AI・LLMAI & LLM
- Claude API (Anthropic) — AI検索のメインプロバイダー。tool_use でクエリを構造化 JSON にパース。Haiku 4.5 / Sonnet 4.6 / Opus 4.6 をサポートPrimary AI search provider. Parses queries into structured JSON via tool_use. Supports Haiku 4.5 / Sonnet 4.6 / Opus 4.6
- Gemini API (Google) — フォールバック用プロバイダー。function_calling で同一スキーマに対応。Flash / Pro モデルをサポートFallback provider. Uses function_calling with the same schema. Supports Flash / Pro models
- OpenAI GPT — フォールバック用プロバイダー。function_calling で同一スキーマに対応。GPT-4o / 4.1 系をサポートFallback provider. Uses function_calling with the same schema. Supports GPT-4o / 4.1 family
- Workers
/v1/search/ai — 統一エントリポイント。プロバイダー自動選択・フォールバック・Vault からのキー復号(vault_read_secret RPC)・使用量ログを Workers 内で一括処理Unified entry point. Handles provider routing, fallback, Vault key decryption (via the vault_read_secret RPC), and usage logging — all inside Workers
- Web Speech API — ブラウザネイティブの音声認識。管理画面の AI 検索モーダルで音声入力に対応(Chrome/Edge)Browser-native speech recognition. Voice input in the admin AI search modal (Chrome/Edge)
通知・決済・外部サービスNotifications, payments & externals
- Firebase Cloud Messaging (v1 API) — ユーザー向けプッシュ配信。
POST /v1/admin/user-notifications/{id}/send は受信者トークンを 500 件/バッチで parky-fcm-dispatch キューに投入し、consumer(src/queue/fcm-dispatch.ts)が Web Crypto で OAuth2 JWT(RS256)を署名して FCM v1 エンドポイントを fan-out。OAuth access_token は KV(parky-cache)で isolate 跨ぎ共有。Flutter プロトタイプには firebase_messaging がまだ入っていないため、端末側でのトークン登録・Push 受信は未実装。End-user push delivery. POST /v1/admin/user-notifications/{id}/send chunks receiver tokens 500/batch into the parky-fcm-dispatch queue; the consumer (src/queue/fcm-dispatch.ts) signs the OAuth2 JWT (RS256) with Web Crypto and fans out to the FCM v1 endpoint. The OAuth access_token is shared cross-isolate via KV (parky-cache). firebase_messaging is not yet in the Flutter prototype, so device-side token registration and receive are not implemented.
- Google Play Developer API / App Store Connect API — Store 同期。
POST /v1/admin/store-sync/trigger は parky-store-sync キューに投入、consumer が Play Developer API(レビュー)/ App Store Connect API(レビュー・売上 DAILY SUMMARY)から取得して store_reviews / store_sales_daily に upsert する。Play sales(Cloud Storage 月次 CSV)は未実装Store sync. POST /v1/admin/store-sync/trigger enqueues into parky-store-sync; the consumer pulls reviews from the Play Developer API and reviews + DAILY SUMMARY sales from App Store Connect, upserting into store_reviews / store_sales_daily. Play sales (monthly Cloud Storage CSV) is not yet implemented
- Stripe — 課金・サブスクリプション決済(計画のみ)。DB スキーマには
revenue_transactions.stripe_payment_intent_id / stripe_status とコードマスター revenue_channel = stripe が用意されているが、実 SDK 呼び出し・Webhook は未実装。Subscriptions / billing — planned only. The DB schema has revenue_transactions.stripe_payment_intent_id / stripe_status columns and a revenue_channel = stripe master entry, but no Stripe SDK calls or webhooks are wired up yet.
- 1Password Service Account — CI/CD のシークレット配信。GitHub Actions でトークン参照。Secret delivery to CI via 1Password SA tokens in GitHub Actions.
ドキュメント・周辺ツールDocs & tooling
- Mermaid — 本ドキュメント内の図(ER/フロー/シーケンス)。All diagrams in this site (ER, flow, sequence).
- GitHub Actions — 全プロダクトのデプロイパイプライン。Deployment pipelines for every product.
メモ:
Note:
クライアントが叩く API は Cloudflare Workers 上の /v1/* に一元化しています(2026-04-17 設計変更、Phase 2 に向けて)。Supabase Edge Functions は Parky では採用せず、FCM 配信・LLM 呼び出し・ストア同期・定期ジョブまですべて Workers 内に実装します。例外は Auth / Realtime / Storage presigned PUT のみ(データ面の最適化)。バイナリは Supabase Storage ではなく R2 に格納します(コスト・エグレス料金最適化のため)。
Clients hit a single unified API surface: Cloudflare Workers /v1/* (design change 2026-04-17, ahead of Phase 2). Supabase Edge Functions are not used in Parky — FCM delivery, LLM calls, store syncs, and scheduled jobs all live inside Workers. The exceptions are Auth, Realtime, and Storage presigned PUTs — data-plane optimizations. Binary assets live in R2, not Supabase Storage (chosen for cost and egress).