データモデルData model
Web 版は Supabase を読み取り専用で使います。スキーマの全容は 共通データモデル を参照してください。 ここでは Web 版が ビルド時 / ランタイムにどのテーブルをどう使うかだけを示します。
The web app reads from Supabase only. For the full schema see the shared data model. This page only lists which tables the web app touches at build time vs. runtime.
ビルド時に参照するテーブルTables read at build time
| Table | 用途 | Purpose |
|---|---|---|
parking_lots | スポット詳細 / ハブページ生成 | Spot detail and hub pages |
parking_lot_images | ギャラリー | Galleries |
parking_lot_hours | 営業時間表示 | Hours display |
parking_lot_pricing_rules | 料金表 | Pricing tables |
parking_lot_attributes | 設備・特徴 | Facilities & features |
parking_lot_tags + tags | タグ(シーン別マッチ) | Tags — for scene matching |
parking_reviews | 平均星・レビュー抜粋 | Aggregated rating and excerpts |
articles | メディア記事の一部(見出し・メタ) | Media article metadata |
codes | 列挙値のラベル解決 | Enum label resolution |
ランタイムで参照するテーブルTables read at runtime
原則、Web 版はランタイムで Supabase から直接テーブルを読みません。
/search の全文検索は Pagefind が生成した静的インデックス
(dist/pagefind/) をクライアントから fetch して完結します。
検索対象の本体データは、Pagefind がビルド時に各ページの HTML を走査してインデックスに埋め込みます。
By default the web app does not read Supabase at runtime.
Full-text search on /search runs entirely against the
Pagefind static index (dist/pagefind/) fetched by the client.
Pagefind scans the built HTML at post-build time and embeds everything it needs.
例外的にクライアントから Supabase に anon キーで問い合わせる島が追加される場合は、 以下の RLS 前提が必須になります。
Should an island be added that really needs an anon-key query against Supabase at runtime, it must assume the RLS policies below.
deleted_at IS NULL AND published = true 等の公開条件でフィルタする RLS を必ず設定する。
Any table read by anon at runtime must have an RLS policy filtering to something like deleted_at IS NULL AND published = true.
代表的なクエリパターンTypical queries
スポット詳細の集約 (build)Spot detail aggregate (build)
select pl.*,
(select json_agg(i) from parking_lot_images i where i.parking_lot_id = pl.id) as images,
(select json_agg(h) from parking_lot_hours h where h.parking_lot_id = pl.id) as hours,
(select json_agg(pr) from parking_lot_pricing_rules pr where pr.parking_lot_id = pl.id) as pricing,
(select avg(rating)::numeric(3,2) from parking_reviews where parking_lot_id = pl.id) as avg_rating
from parking_lots pl
where pl.id = $1 and pl.deleted_at is null;
近隣スポット(PostGIS)Nearby spots (PostGIS)
select id, name, st_distance(location, st_makepoint($1, $2)::geography) as dist_m
from parking_lots
where deleted_at is null
order by location <-> st_makepoint($1, $2)::geography
limit 20;