アーキテクチャArchitecture
Web 版は Astro 5 の SSG(output: 'static')+ Islands 構成です。
ほぼすべてのページをビルド時にレンダリングして静的 HTML として配信し、
検索 UI と地図 UI のみ React Island としてハイドレートします。
配信は Cloudflare Pages(プロジェクト parky-home-dev、カスタムドメイン dev.parky.co.jp)で、
GitHub Actions が wrangler pages deploy で直接送り込みます。
The web app is an Astro 5 SSG build (output: 'static') with Islands.
Almost every page is rendered to static HTML at build time; only the search and map UIs
hydrate as React islands. Hosting is on Cloudflare Pages
(project parky-home-dev, custom domain dev.parky.co.jp), with
GitHub Actions running wrangler pages deploy directly.
検索は Pagefind で静的化Search via Pagefind (static index)
/search は Pagefind(astro-pagefind)でビルド後の
dist/ をスキャンして生成される静的インデックスを、クライアントから
fetch して全文検索します。ランタイムで Supabase に直接クエリを発行することはありません。
/search is powered by Pagefind (astro-pagefind):
the plugin scans the built dist/ after astro build and emits a
static index under dist/pagefind/ that the client fetches at runtime.
No Supabase queries happen at search time.
Web版のチャネル接続Web app channel view
Web 版だけに関係する接続を抽出した図です。 全体像は 全体アーキテクチャ を参照してください。
The slice of the system the web app touches. For the full picture see the overall architecture.
flowchart LR WA["Web App
Astro + Islands"] subgraph Build["ビルド時 (GitHub Actions)"] GHA["GitHub Actions
ランナー"] BUILD["Astro build"] SR["Supabase service_role
(read only)"] end subgraph Runtime["ランタイム (ブラウザ)"] HTML["静的HTML"] ISLAND["検索 / 地図 Island"] ANON["Supabase anon + RLS"] end subgraph Supabase["Supabase"] DB[("PostgreSQL
+ PostGIS")] end subgraph Storage["Object storage (Cloudflare R2)"] WSB["R2 bucket
parky"] end subgraph External["外部"] MB["Mapbox GL JS"] WP["WordPress
media.parky.co.jp"] XSRV["Cloudflare Pages
dev.parky.co.jp"] end GHA --> BUILD BUILD --> SR SR --> DB BUILD --> HTML GHA --> XSRV HTML --> XSRV XSRV --> WA WA --> ISLAND ISLAND --> ANON ANON --> DB WA --> MB ISLAND --> MB WA --> WP HTML --> WSB ISLAND --> WSB
ビルドとデプロイのおおまかな流れBuild & deploy flow (high-level)
sequenceDiagram participant GHA as GitHub Actions participant API as Workers API
dev-api.parky.co.jp participant Astro as Astro build (@parky/home) participant Supa as Supabase (PostgreSQL) participant PF as Pagefind (postBuild) participant Pages as Cloudflare Pages
parky-home-dev GHA->>API: /v1/hubs/publishable?min=1 (health check, 60s max) GHA->>Astro: npm run build:home Astro->>Supa: getStaticPaths / ページ生成用データ取得 Astro->>API: /v1/* (公開読み取り、CDN キャッシュ経由) Supa-->>Astro: 駐車場・ハブ・シーン等のマスター Astro-->>GHA: dist/ 出力 (静的HTML + Islands JS) GHA->>PF: astro-pagefind が dist/ を走査 PF-->>GHA: dist/pagefind/ (全文検索インデックス) GHA->>Pages: wrangler pages deploy web/home/dist --project-name=parky-home-dev
getStaticPaths を取るかは個別の Astro ページ (web/home/src/pages/**/*.astro) を直接参照してください。
The sequence above is a high-level summary. Which pages pull from which tables in getStaticPaths is best read directly from each page under web/home/src/pages/**/*.astro.
レンダリング戦略(指針)Rendering strategy (guidance)
client:* ディレクティブの実装状況はページによって差があります。確定情報はソース (web/home/src/pages/**/*.astro, src/components/ParkingMapIsland.tsx, src/components/SearchIsland.tsx 等) を参照してください。
The table below lays out intended patterns. Actual island placement and client:* directives vary per page — see web/home/src/pages/**/*.astro, ParkingMapIsland.tsx, and SearchIsland.tsx for the real layout.
| 種別 | Type | 例 | Example | 想定されるハイドレート | Intended hydration |
|---|---|---|---|---|---|
| トップ / 会社情報 / LP | Top / company / LP | /, /company, /for-owners/ |
原則なし (静的HTML) | Static HTML | |
| スポット詳細 | Spot detail | /spot/[id]/, /p/[pref]/[city]/[spotSlug]/ |
SSG、地図は ParkingMapIsland として島 |
SSG, map lives as ParkingMapIsland |
|
| ハブページ | Hub page | /p/[pref]/[city]/ |
SSG、周辺リスト + 地図 island | SSG, neighbourhood list + map island | |
| シーン LP | Scene LP | /scene/[sceneSlug]/ |
SSG、シーン別の導線 | SSG, scene-themed landings | |
| 検索 | Search | /search |
SSG shell + Pagefind 静的インデックスを fetch する SearchIsland |
SSG shell + a SearchIsland that fetches the Pagefind static index |
|
| メディア記事 | Media articles | /media/[...slug]/ |
MDX、静的のみ | MDX, static only |
Web 版の API エンドポイントWeb-app API endpoints
Astro の SSR アダプタ (@astrojs/cloudflare) 上で
src/pages/api/*.ts に置いた APIRoute が Cloudflare Workers
として動作します。BFF (dev-api.parky.co.jp) とは別レイヤで、
公開ポータル固有の軽量ユーティリティを担当します。
With the Astro SSR adapter (@astrojs/cloudflare), files under
src/pages/api/*.ts export APIRoute handlers that run as
Cloudflare Workers. This is a thin utility layer distinct from the BFF
(dev-api.parky.co.jp) and serves portal-specific concerns.
| エンドポイント | Endpoint | 目的 | Purpose | 上流 | Upstream |
|---|---|---|---|---|---|
GET /api/route-eta |
GET /api/route-eta |
クエリ o_lng / o_lat / d_lng / d_lat を受け取り、
2 地点間の車移動時間 (渋滞加味) を秒単位で返す。
/search の「到着予想時刻」ボタンが叩く。
レスポンス: { durationSec, distanceM, source: "mapbox" }。
エラー時 400 / 502。Cloudflare edge で 120 秒キャッシュ
(Cache-Control: public, max-age=120, s-maxage=120)。
|
Takes o_lng / o_lat / d_lng / d_lat query params and returns
driving-traffic duration in seconds between the two points.
Called by the "Arrival ETA" button on /search.
Response: { durationSec, distanceM, source: "mapbox" }.
Errors: 400 / 502. Cached on the Cloudflare edge for 120 seconds
(Cache-Control: public, max-age=120, s-maxage=120).
|
Mapbox Directions API (driving-traffic プロファイル) |
Mapbox Directions API (driving-traffic profile) |
GET /robots.txt |
GET /robots.txt |
prod では sitemap を案内、dev / preview は全 Disallow |
In prod serves sitemap; in dev / preview returns full Disallow |
— | — |
採用技術Tech stack
- Astro 5 — SSG + Islands アーキテクチャSSG + Islands.
- React 19 —
@parky/uiのコンポーネントを island として埋め込みIslands from@parky/ui. - Tailwind CSS v4 — デザイントークン + Parky ブランド変数Design tokens + Parky brand variables.
- Supabase client (読み取り専用) — build 時は service_role、runtime は anon + RLSservice_role at build, anon+RLS at runtime.
- Mapbox GL JS — 地図 island 用For the map island.
- MDX — メディア記事For media articles.
セキュリティ境界Security boundaries
- ビルドは GitHub Actions の閉じたランナー上で実行し、
service_roleキーはビルド時のみ使用 - Builds run on closed runners; the
service_rolekey is used only at build time. - 成果物の静的HTMLには一切の機密情報を含めない
- No secrets are bundled into the static output.
- ランタイムのクライアントサイド検索は anon キー + RLS ポリシーで保護
- Runtime client-side search uses the anon key gated by RLS policies.