データモデル Data model

モバイルアプリは管理者ポータル・オーナーポータルと同じ Supabase PostgreSQL データベースを共有します。 そのため、データモデルは 管理者ポータルのデータモデル と完全に同一です。 本ページでは、モバイルアプリから直接読み書きする主要エンティティを中心に整理します。

The mobile app shares the same Supabase PostgreSQL database as the admin and owner portals, so the data model is identical to the admin portal data model. This page focuses on the core entities the mobile app reads from and writes to directly.

一次情報源:Source of truth: スキーマの正本は parky/infra/supabase/migrations/000_init_schema.sql。 コードマスター(ステータス・種別等の列挙値)は codes テーブルで管理され、 CLAUDE.md のコードマスター方針に従い、列挙値は英語小文字のコード値で保持します。 The canonical schema lives in parky/infra/supabase/migrations/000_init_schema.sql. Enumerated values (status, kind, etc.) are managed in the codes master table, and per the CLAUDE.md code-master policy they are stored as lowercase English code values.

7.1 ドメイン俯瞰図 7.1 Domain map

flowchart LR
  subgraph Parking["🅿️ 駐車場ドメイン"]
    PL[parking_lots]
    PLI[parking_lot_images]
    PLT[parking_lot_tags]
    PLA[parking_lot_attributes]
    PLPM[parking_lot_payment_methods]
    PLPR[parking_lot_pricing_rules]
    PLH[parking_lot_hours]
    PR[parking_reviews]
    PS[parking_sessions]
  end
  subgraph Users["👤 ユーザー"]
    AU[app_users]
    USP[user_saved_parkings]
    UAL[user_activity_logs]
    US[user_subscriptions]
    UPT[user_push_tokens]
    UN[user_notifications]
    UE[user_exp]
    UB[user_badges]
    UBP[user_badge_progress]
    UT[user_themes]
    UAT[user_active_themes]
  end
  subgraph Game["🏆 ゲーミフィケーション"]
    BD[badge_definitions]
    LD[level_definitions]
    AER[activity_exp_rules]
  end
  subgraph Content["📝 コンテンツ"]
    ART[articles]
    ADS[ads]
    TAG[tags]
    ER[error_reports]
    ST[support_tickets]
  end
  subgraph Sys["⚙️ マスター"]
    CD[codes]
    SP[subscription_plans]
  end

  PL --> PLI
  PL --> PLT
  PL --> PLA
  PL --> PLPM
  PL --> PLPR
  PL --> PLH
  PL --> PR
  PL --> PS
  AU --> PS
  AU --> PR
  AU --> USP
  AU --> UAL
  AU --> US
  AU --> UPT
  AU --> UN
  AU --> UE
  AU --> UB
  AU --> UBP
  AU --> UT
  AU --> UAT
  BD --> UBP
  BD --> UB
  LD --> UE
  US --> SP

7.2 主要テーブル定義(モバイル視点) 7.2 Core table definitions (mobile-centric view)

parking_lots core

駐車場の中核テーブル。GPS 座標は PostGIS の geography 型で保持され、nearby_parking_lots() RPC で周辺検索します。

The core parking-lot table. GPS is stored in a PostGIS geography column and queried via the nearby_parking_lots() RPC.

カラムColumn Type 備考Notes
iduuidPK
nametext
addresstext表示用住所Display address
lat / lngnumeric表示用。実体は locationDisplay-only; source is location
locationgeography(point)PostGIS
total_spacesint収容台数Capacity
operating_hourstextparking_lot_hours で詳細管理Detail lives in parking_lot_hours
structurecode (text)flat / multistory / underground 等flat / multistory / underground, etc.
entry_methodcode (text)gate / flap / barrier_free 等gate / flap / barrier_free, etc.
max_height_mnumeric車両制限Vehicle limits
max_width_mnumericditto
max_length_mnumericditto
max_weight_tnumericditto
min_clearance_cmint最低地上高Minimum clearance
statuscode (text)new / active / hidden / closed
sourcecode (text)データ取得元Data origin
created_at / updated_attimestamptz
deleted_attimestamptzソフトデリートSoft delete

parking_lot_pricing_rules core

時間帯・曜日別の料金ルール。複数行の組合せでキャップ付きの料金表を表現します。

Time-of-day / day-of-week pricing rules. Multiple rows combine to express a capped pricing table.

カラムColumn Type 備考Notes
iduuidPK
parking_lot_iduuidFK
day_of_weekint[]適用曜日(0=Sun 〜 6=Sat)Applicable weekdays (0=Sun ... 6=Sat)
start_time / end_timetime時間帯Time window
unit_minutesint課金単位(例:30分)Billing unit (e.g. 30 min)
unit_priceint単位あたり円Yen per unit
cap_minutesint最大料金の対象時間(例:720=12h)Window for the cap price (e.g. 720 = 12 h)
cap_priceint最大料金(円)Cap price (yen)
priorityint競合時の優先度Priority when rules overlap

parking_sessions core

モバイルアプリの中心エンティティ。入出庫時刻・請求額・ステータスを保持します。

The central entity of the mobile app. Holds entry/exit timestamps, billed amount, and status.

カラムColumn Type 備考Notes
iduuidPK
user_iduuidFK → app_users
parking_lot_iduuidFK → parking_lots
started_attimestamptz入庫時刻Entry time
ended_attimestamptz出庫時刻(NULL=駐車中)Exit time (NULL = still parked)
statuscode (text)pending/parking/ended/cancelled
total_amountint円(最終確定額)Yen (final billed amount)
vehicle_typecode (text)sedan / suv / kei / truck 等sedan / suv / kei / truck, etc.
memotextメモFree-form memo
personal_ratingcode (text)good / bad / null(個人評価)good / bad / null (personal rating)
start_lat/start_lngnumericGPS記録GPS snapshot
created_at/updated_at/deleted_attimestamptz

parking_reviews

カラムColumn Type 備考Notes
iduuidPK
user_iduuid投稿ユーザーPosting user
parking_lot_iduuid対象駐車場Target parking lot
session_iduuid紐付くセッション(任意)Linked session (optional)
ratingint1–5
commenttext
image_urlstext[]Cloudflare R2 URL(最大4枚)Cloudflare R2 URLs (up to 4)
statuscode (text)draft/pending/approved/rejected
created_at/deleted_attimestamptz

app_users core

カラムColumn Type 備考Notes
iduuidPK (Supabase Auth の user.id と一致)PK (matches the Supabase Auth user.id)
display_nametext
emailemail
avatar_urltextCloudflare R2
vehicle_typecode (text)コードマスター vehicle_typeCode master vehicle_type
premiumbooleanプレミアム契約中かのスナップショットSnapshot of whether a premium subscription is active
statuscode (text)user_status: active/withdrawn/suspended
notification_prefsjsonb通知種別ごとの ON/OFFPer-notification-type ON/OFF flags
localetextja / en
created_at/deleted_attimestamptz

user_push_tokens

FCM デバイストークン。起動時に upsert し、Push 送信時に参照します。

FCM device tokens. Upserted on app boot and read when sending push notifications.

カラムColumn Type 備考Notes
iduuidPK
user_iduuidFK
device_idtextデバイス一意IDUnique device ID
fcm_tokentextFCM v1 トークンFCM v1 token
device_typecode (text)ios / android(device_type マスター)ios / android (via the device_type master)
app_versiontext
last_seen_attimestamptz
UNIQUE (user_id, device_id)

user_notifications

アプリ内通知の受信箱。Push と同じレコードを ここに INSERT し、Realtime で端末に配信されます。

The in-app notification inbox. The same record that backs a push is INSERTed here and streamed to devices via Realtime.

カラムColumn Type 備考Notes
iduuidPK
user_iduuidFK
notif_typecode (text)system/promo/fee_alert/session/review, etc.
notif_categorycode (text)カテゴリグループ(UIタブ分類)Category group (UI tab bucket)
titletext
bodytext
deep_linktextタップで遷移する画面(parky://Target screen opened on tap (parky://)
payloadjsonb任意の付帯情報Arbitrary attached data
sent_attimestamptz送信時刻Sent-at time
read_attimestamptz既読時刻(NULL=未読)Read-at time (NULL = unread)
delivered_attimestamptz端末到達Delivered to device
statuscode (text)notif_status: queued/sent/delivered/failed

user_saved_parkings

カラムColumn Type
user_id, parking_lot_iduuid (PK 複合)uuid (composite PK)
created_attimestamptz

user_activity_logs

全ての行動イベント。metadata(JSONB)にイベント固有の詳細を保持し、バッジ条件エンジンはこのメタデータをドット記法パスで評価します。

Every activity event. Event-specific detail lives in metadata (JSONB), and the badge condition engine evaluates that metadata via dot-notation paths.

カラムColumn Type 備考Notes
iduuidPK
user_iduuidFK
activity_typetextsession_start / session_end / review_post / search, etc.
metadatajsonbイベント詳細Event detail
occurred_attimestamptz

user_exp / level_definitions / activity_exp_rules / badge_definitions / user_badges / user_badge_progress gamification

管理者ポータルと同じゲーミフィケーション基盤を共有。モバイルは書き込みしません(DB トリガ・Cloudflare Workers 経由で自動更新)。

Shares the same gamification stack as the admin portal. The mobile app never writes to it directly — updates are driven by DB triggers and Cloudflare Workers.

user_subscriptions / subscription_plans revenue

articles / ads

メディア記事と広告のマスター。モバイルは read-only。

Master tables for media articles and ads. The mobile app is read-only.

support_tickets / error_reports ops

codes master

カテゴリ付きラベル辞書。起動時に一括フェッチし、クライアントのドロップダウン・ラベル表示に使用。既存カテゴリは user_status, vehicle_type, session_status, notif_type, notif_status, notif_target, device_type 等。

A category-keyed label dictionary. Fetched once on app boot and used to power every dropdown and label on the client. Existing categories include user_status, vehicle_type, session_status, notif_type, notif_status, notif_target, device_type, and more.

7.3 モバイル固有の読み書きマトリクス 7.3 Mobile read/write matrix

テーブルTable モバイル読取Mobile read モバイル書込Mobile write RLS 要点RLS key points
parking_lots (+サブ)(and sub-tables)✅ 全件✅ Allstatus != 'hidden' かつ未削除status != 'hidden' and not soft-deleted
parking_sessions✅ 自分のみ✅ Self only✅ 自分のみ✅ Self onlyuser_id = auth.uid()
parking_reviews✅ approved + 自分の draft✅ approved + own drafts✅ 自分のレビュー✅ Own reviews同上Same as above
app_users✅ 自分のみ✅ Self only✅ 自分のプロフィール✅ Own profile同上Same as above
user_saved_parkings✅ 自分のみ✅ Self only✅ 自分のみ✅ Self only同上Same as above
user_notifications✅ 自分のみ✅ Self onlyread_at 更新のみread_at updates only同上Same as above
user_push_tokens✅ 自分のみ✅ Self only✅ 自分のみ (upsert)✅ Self only (upsert)同上Same as above
user_activity_logs✅ INSERT のみ✅ INSERT only自分ユーザーIDのみ許可Only the caller's user ID is allowed
user_exp/user_badges/user_badge_progress✅ 自分のみ✅ Self only❌(DBトリガで自動)❌ (auto via DB triggers)同上Same as above
user_subscriptions✅ 自分のみ✅ Self only❌(Edge 経由)❌ (via Cloudflare Workers)同上Same as above
support_tickets✅ 自分のみ✅ Self only✅ INSERT + 返信✅ INSERT + replies同上Same as above
error_reports✅ 自分のみ✅ Self only✅ INSERT のみ✅ INSERT only同上Same as above
articles / ads✅ 公開中✅ Publishedpublished_at <= now()
codes✅ 全件✅ All

7.4 データライフサイクル 7.4 Data lifecycle

データData 作成Creation 更新Update 削除Deletion
ユーザーUser サインアップ時On signup プロフィール編集Profile edits 退会 → withdrawn + 個人情報匿名化Withdrawal → withdrawn + PII anonymized
駐車セッションParking session 駐車開始時On parking start 駐車中・駐車終了時During and at end of parking ソフト削除(履歴から非表示)Soft delete (hidden from history)
レビューReview 投稿時On post 編集(一定期間内)Edit (within a grace window) ソフト削除Soft delete
通知Notification 送信時On send 既読化Mark as read 90日経過で自動アーカイブ(Cron)Auto-archived after 90 days (cron)
活動ログActivity log 行動時On activity 2年経過で集計化Aggregated after 2 years
Push トークンPush token 起動時On app boot 起動時 last_seen_at 更新last_seen_at refreshed on boot 30日アクセスなしで削除Deleted after 30 days of inactivity

7.5 データ更新ポリシー 7.5 Update policy