データモデル 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.
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]
PLPR[parking_lot_pricing_rules]
PLH[parking_lot_hours]
PLDO[parking_lot_date_overrides]
%% parking_lot_attributes (028) と parking_lot_payment_methods (057) は tags に統合済み
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]
HB[home_banners]
ER[error_reports]
ST[support_tickets]
end
subgraph Search["🔎 検索関連"]
UD[user_destinations]
end
subgraph Sys["⚙️ マスター"]
CD[codes]
SP[subscription_plans]
end
PL --> PLI
PL --> PLT
PL --> PLPR
PL --> PLH
PL --> PLDO
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
AU --> UD
BD --> UBP
BD --> UB
LD --> UE
US --> SP
7.2 主要テーブル定義(モバイル視点) 7.2 Core table definitions (mobile-centric view)
parking_lots core
駐車場の中核テーブル。座標の SoT は PostGIS の location (geography 4326)。lat/lng は表示用にトリガーで派生。shape_type で point/line/area を切替、code (citext) は自然キー。周辺検索は nearby_parking_lots() RPC を使用。
The core lot table. location is the coordinate SoT; lat/lng are trigger-derived. shape_type selects point/line/area, code (citext) is the natural key. Nearby search uses the nearby_parking_lots() RPC.
| カラムColumn | 型Type | 備考Notes |
|---|---|---|
id | uuid | PK |
code | citext NOT NULL | 自然キー (URL / 連携ID)Natural key (URL / integration ID) |
name | text NOT NULL | — |
address | text | 表示用住所Display address |
location | geography(Point, 4326) | 座標 SoT (PostGIS)Coordinate SoT (PostGIS) |
lat / lng | double precision | 表示用。実体は locationDisplay-only; source is location |
area | geometry | shape_type='area' 用ポリゴンPolygon for shape_type='area' |
shape_type | text NOT NULL (default 'point') | point / line / area |
parent_id | uuid | 親駐車場 (バリアント分割用)Parent lot (for variants) |
variant_label | text | バリアント識別ラベルVariant label |
total_spaces | int | 収容台数Capacity |
operating_hours | text | 表示用文字列。詳細は parking_lot_hoursDisplay string; detail in parking_lot_hours |
structure | text | flat / multistory / underground 等flat / multistory / underground, etc. |
entry_method | text | gate / flap / barrier_free 等gate / flap / barrier_free, etc. |
entry_difficulty | text | 入庫難易度のコードEntry-difficulty code |
max_height_m / max_width_m / max_length_m / max_weight_t | numeric | 車両制限Vehicle limits |
min_clearance_cm | int | 最低地上高Minimum clearance |
max_tire_width_mm | int | タイヤ幅制限Tire-width limit |
max_parking_duration_min | int | 連続駐車可能時間 (分)Max continuous parking (minutes) |
receipt_available | boolean | 領収書発行可否Receipt available |
operator_code | text | 運営会社コード (codes.operator)Operator code (codes.operator) |
place_id | text | Google Places IDGoogle Places ID |
status | text NOT NULL (default 'active') | codes.parking_lot_status: pending / active / on_hold / withdrawn |
source | text (default 'manual') | データ取得元Data origin |
raw_text | text | 取込元の生データ (デバッグ用)Raw ingest text (debug) |
created_at / updated_at | timestamptz | — |
deleted_at | timestamptz | ソフトデリートSoft delete |
parking_lot_pricing_groups core 2026-04-24 new
駐車場内の料金ポリシー集約単位。複数の parking_spots が同一 group を参照することで料金の共有編集が可能。(parking_lot_id, code) で一意。
Pricing-policy aggregation unit inside a lot. Multiple spots can share a group so pricing can be edited in bulk. Unique on (parking_lot_id, code).
| カラム | 型 | 備考 |
|---|---|---|
id | uuid | PK |
parking_lot_id | uuid NOT NULL | FK → parking_lots |
code | citext NOT NULL | 自然キー (lot 内一意)Natural key, unique within a lot |
name | text NOT NULL | 表示名 (例: 普通車スタンダード)Display name (e.g. "Standard – sedan") |
is_default | boolean (default false) | 既定 groupDefault group |
display_order | int (default 0) | — |
created_at / updated_at | timestamptz | — |
parking_spots core 2026-04-24 new
駐車場内の個別車室。parking_sessions.parking_spot_id は NOT NULL なので、セッション作成時には spot を必ず確定させる必要がある。(parking_lot_id, code) で partial UNIQUE (soft delete 考慮)。
Individual parking spot. parking_sessions.parking_spot_id is NOT NULL, so a session always pins to a specific spot. Partial UNIQUE on (parking_lot_id, code) respecting soft delete.
| カラム | 型 | 備考 |
|---|---|---|
id | uuid | PK |
parking_lot_id | uuid NOT NULL | FK → parking_lots |
pricing_group_id | uuid NOT NULL | FK → parking_lot_pricing_groups |
code | citext NOT NULL | 自然キー (例: A-12)Natural key (e.g. A-12) |
vehicle_type_max | text | 最大対応車種Max vehicle type accepted |
is_ev_charger | boolean | EV 充電器ありHas EV charger |
ev_connector_type | text | CHAdeMO / CCS / Tesla 等CHAdeMO / CCS / Tesla, etc. |
accessibility | text | バリアフリー区分Accessibility class |
width_mm / length_mm / height_mm | int | 区画寸法Spot dimensions |
floorplan_x / floorplan_y | numeric | 場内マップ用座標Floor-plan XY |
location | geography(Point) | spot 単位の座標Spot-level GPS |
is_reservable | boolean | — |
is_active | boolean (default true) | — |
meta | jsonb (default {}) | — |
created_at / updated_at / deleted_at | timestamptz | — |
parking_lot_hours core 2026-04-24 updated
駐車場の時間窓。2026-04-24 に window_type カラムを追加、1 行 = 1 種別の時間窓として正規化しました。
モバイルアプリは詳細画面で「営業中」「今すぐ入庫可」「今すぐ出庫可」バッジを表示する際に、Mobile BFF 経由で派生値 (derived.is_open_now / can_enter_now / can_exit_now) を受け取ります。
Time-window rows for a parking lot. 2026-04-24 added window_type. The mobile app receives derived flags
(derived.is_open_now / can_enter_now / can_exit_now) from the Mobile BFF rather than evaluating rules client-side.
| カラムColumn | 型Type | 備考Notes |
|---|---|---|
window_type | code (text) | business / entry / exit / after_hours_exit(codes.parking_hours_window_type) |
day_type | code (text) | weekday / saturday / sunday / holiday / holiday_eve / all |
day_of_week | smallint | 0=Sun〜6=Sat |
is_24h / is_closed | boolean | — |
open_time / close_time | text NOT NULL | HH:MM 文字列。24:00 表記許容のため text 型HH:MM as text (allows 24:00) |
effective_from / effective_to | date | 期間限定ルール |
parking_lot_date_overrides core 2026-04-24 new
特定日のオーバーライド (花火大会・元旦特別営業など)。Mobile BFF は駐車場詳細 API のレスポンスに date_overrides[] を含め、当日の active_override を derived に載せます。
アプリ側では「今日は花火大会のため 12:00 以降のみ入庫可」等のバナー表示に利用。
Per-day override rows. The Mobile BFF returns date_overrides[] and sets derived.active_override for the current day so the app can show banners like "fireworks night — entry after 12:00".
| カラム | 型 | 備考 |
|---|---|---|
parking_lot_id + override_date | uuid + date | UNIQUE |
label | text | 例: 隅田川花火大会 |
hours | jsonb | キー: business / entry / exit / after_hours_exit |
pricing | jsonb (array) | NULL=通常 / []=無料 / 配列=置換 |
判定の優先順: 日付オーバーライド → 祝日行 (jp_holidays 参照) → 曜日行 → day_type → all。
詳細は 2026-04-24 ADR。
parking_lot_pricing_rules core
料金エンジンのルール。pricing_group_id を必ず持ち、rule_order で優先順、category / day_type / time_start / time_end で条件絞り込み、cap_* で上限を表現する。金額は minor unit の bigint (JPY は 1 倍)。
Fee-engine rules. Each row belongs to a pricing_group_id and is ordered by rule_order; matching uses category / day_type / time_start / time_end; caps via the cap_* family. Money is bigint in minor units (×1 for JPY).
| カラムColumn | 型Type | 備考Notes |
|---|---|---|
id | uuid | PK |
parking_lot_id | uuid NOT NULL | FK → parking_lots |
pricing_group_id | uuid NOT NULL | FK → parking_lot_pricing_groups (2026-04-24 階層化で必須化)(required by the 2026-04-24 hierarchy migration) |
rule_order | int NOT NULL (default 0) | 小さい順に評価Lower numbers evaluated first |
category | text NOT NULL | 時間制 / 最大料金 / 一回 / フラット 等e.g. hourly / max-fee / once / flat |
day_type | text NOT NULL (default 'all') | codes.day_type: weekday / saturday / sunday / holiday / holiday_eve / all |
time_start / time_end | text | 時間帯 (HH:MM 文字列。24:00 表記可)Time window as HH:MM text (allows 24:00) |
per_minutes | int | 課金単位 (分)Billing unit in minutes |
price_minor | bigint | 単位あたり minor 通貨 (JPY なら円)Price per unit, minor currency |
cap_type | text | once / per_24h / per_window 等 |
cap_duration_hours | int | 最大料金の対象時間 (時間単位)Cap window in hours |
cap_price_minor | bigint | 最大料金 (minor 通貨)Cap amount, minor currency |
cap_repeat | boolean (default true) | cap を繰り返し適用するかReapply cap each window |
cap_scope | text | 日跨ぎ / 入庫起点 等のスコープCap scope (e.g. calendar day / entry-relative) |
created_at | timestamptz | — |
parking_sessions core
モバイルアプリの中心エンティティ。parking_spot_id は NOT NULL で、セッションは必ず特定の spot に紐付く。金額は total_amount_minor (bigint, minor unit)。geo_verified / geo_distance_m で開始時の位置検証、client_request_id で冪等性、fee_mismatch_flag / user_entered_fee_minor でユーザー手入力金額との突合を行う。updated_at / deleted_at は無く、ソフトデリートではなく status='cancelled' + cancelled_reason で運用。
The mobile app's central entity. parking_spot_id is NOT NULL — every session pins to a specific spot. Amount is bigint in minor units. geo_verified / geo_distance_m validate start location, client_request_id enforces idempotency, fee_mismatch_flag reconciles user-entered fees. No updated_at / deleted_at; cancellation is via status='cancelled' + cancelled_reason.
| カラムColumn | 型Type | 備考Notes |
|---|---|---|
id | uuid | PK |
user_id | uuid NOT NULL | FK → app_users |
parking_lot_id | uuid NOT NULL | FK → parking_lots |
parking_spot_id | uuid NOT NULL | FK → parking_spots (2026-04-24 階層化で必須化)(required by the 2026-04-24 hierarchy migration) |
started_at | timestamptz NOT NULL | 入庫時刻Entry time |
ended_at | timestamptz | 出庫時刻 (NULL=駐車中)Exit time (NULL = still parked) |
planned_end_at | timestamptz | 予定終了時刻 (session_notifications の planned_end_minus が参照)Planned end (driver of planned_end_minus session notifications) |
status | text NOT NULL (default 'parking') | codes.session_status: parking / completed / cancelled |
cancelled_reason | text | cancel 時の理由 codesCancellation reason code |
vehicle_type | text | codes.vehicle_type: sedan / kei / large / bike / minivan / high_roof |
total_amount_minor | bigint | 最終確定額 (minor 通貨。JPY は円)Final billed amount in minor units (yen for JPY) |
user_entered_fee_minor | int | ユーザーが手入力した金額 (突合用)User-entered fee, used to flag mismatch |
fee_mismatch_flag | boolean (default false) | 計算額と手入力額の乖離検知True when calculated vs entered diverge |
memo | text | メモFree-form memo |
bad_reason | text | 不正/不審セッションの分類Bad-session classification |
start_lat / start_lng | double precision | 入庫時 GPSEntry-time GPS snapshot |
end_lat / end_lng | double precision | 出庫時 GPSExit-time GPS snapshot |
geo_verified | boolean | 位置検証成功 (gamification cap で参照)Geo verification result (gamification gate) |
geo_distance_m | numeric | 入庫地点と lot 位置の距離 (m)Distance from start GPS to lot location (m) |
client_request_id | uuid | 冪等性キーIdempotency key |
created_at | timestamptz | — |
個人評価 (good / bad) は別テーブル parking_lot_ratings でユーザー × 駐車場の M:N として保持する (セッションのカラムでは無い)。レビュー本文は parking_reviews。
Personal ratings (good / bad) live in parking_lot_ratings (user × lot M:N), not as a session column. Full reviews live in parking_reviews.
parking_reviews
駐車場レビュー (UGC)。status='approved' のみ公開表示・集計対象 (parking_lot_avg_rating view が参照)。オーナー返信は owner_reply 系列で保持。画像はこのテーブルに保存せず、別途 assets + parking_session_photos を経由する。
User reviews (UGC). Only status='approved' is publicly visible and counted (parking_lot_avg_rating view). Owner replies live in the owner_reply* columns. Images are not stored on this table — use assets + parking_session_photos.
| カラムColumn | 型Type | 備考Notes |
|---|---|---|
id | uuid | PK |
parking_lot_id | uuid NOT NULL | FK → parking_lots |
user_id | uuid | 投稿ユーザー (退会で NULL 可)Posting user (nullable to allow withdrawn users) |
user_name | text NOT NULL | 投稿時の表示名スナップショット (退会後も表示)Display-name snapshot at post time |
rating | int NOT NULL | 1–5 |
comment | text | — |
status | text NOT NULL (default 'pending') | codes.review_status: pending / approved / rejected / hidden |
admin_note | text | 運営側の社内メモInternal admin note |
reviewed_by / reviewed_at | uuid / timestamptz | 審査担当 admin と審査時刻Reviewer admin + reviewed time |
is_flagged | boolean (default false) | 通報フラグFlagged for review |
flag_reason | text | — |
owner_reply | text | オーナー返信本文Owner reply body |
owner_replied_at / owner_replied_by | timestamptz / uuid | — |
exp_awarded_at | timestamptz | EXP 付与済みかの記録 (二重付与防止)When XP was granted (prevents double-grant) |
created_at / updated_at / deleted_at | timestamptz | — |
app_users core
エンドユーザー。auth_user_id で auth.users と 1:1 紐付け、RLS は auth_user_id = auth.uid() で自己行のみ。退会は status='withdrawn' + PII 匿名化で運用 (deleted_at 列は無い)。アバター / 通知設定 / locale は別テーブルで管理する (下表参照)。
End users. Linked 1:1 to auth.users via auth_user_id; RLS limits access to auth_user_id = auth.uid(). Withdrawals are status='withdrawn' + PII anonymization (no deleted_at). Avatar / notification prefs / locale live in separate tables.
| カラムColumn | 型Type | 備考Notes |
|---|---|---|
id | uuid | PK |
auth_user_id | uuid | FK → auth.users (RLS の主軸) |
display_name | text NOT NULL | — |
handle | text | @ハンドル (UNIQUE)Public handle (UNIQUE) |
email | text NOT NULL | — |
vehicle_type | text (default 'sedan') | codes.vehicle_type: sedan / kei / large / bike / minivan / high_roof |
premium | boolean (default false) | プレミアム契約中フラグPremium subscription flag |
status | text NOT NULL (default 'active') | codes.user_status: active / withdrawn / suspended / blocked |
profile_visibility | text NOT NULL (default 'friends') | public / friends / private |
device_fingerprints | text[] | 既知デバイス指紋 (referral 不正検知)Known device fingerprints (referral abuse detection) |
signup_ip | inet | 登録時 IPSignup IP |
referral_code_used | text | 登録時に使った招待コードReferral code used at signup |
last_active_at | timestamptz | — |
created_at | timestamptz | — |
付随テーブル: user_notification_prefs (通知種別ごとの push / in_app / email ON-OFF)、user_consents (同意履歴)、user_device_permissions (OS パーミッション現在値)、user_vehicles (登録車両 N 件)、user_search_presets / user_search_preferences、user_referral_codes、user_destinations、user_streaks。
アバター画像は assets テーブルに entity_type='app_user' + entity_id=app_users.id で関連付ける。
Companion tables: user_notification_prefs (per-type push / in_app / email toggles), user_consents, user_device_permissions, user_vehicles, user_search_presets / user_search_preferences, user_referral_codes, user_destinations, user_streaks.
Avatar images are stored in assets with entity_type='app_user' + entity_id=app_users.id.
user_notification_prefs notifications
通知種別ごとに push / in_app / email の ON-OFF を保持する。app_users.notification_prefs jsonb 列は存在しない。
Per-notification-type push / in_app / email toggles. There is no app_users.notification_prefs jsonb column.
| カラム | 型 | 備考 |
|---|---|---|
id | uuid | PK |
user_id | uuid NOT NULL | FK → app_users |
notif_type | text NOT NULL | codes.notif_type: system / info / promo / review_reminder, ... |
push_enabled | boolean (default true) | — |
in_app_enabled | boolean (default true) | — |
email_enabled | boolean (default false) | — |
updated_at | timestamptz | — |
user_push_tokens
FCM デバイストークン。起動時に upsert し、Push 送信時に参照します。
FCM device tokens. Upserted on app boot and read when sending push notifications.
| カラムColumn | 型Type | 備考Notes |
|---|---|---|
id | uuid | PK |
user_id | uuid | FK |
device_id | text | デバイス一意IDUnique device ID |
fcm_token | text | FCM v1 トークンFCM v1 token |
device_type | code (text) | ios / android(device_type マスター)ios / android (via the device_type master) |
app_version | text | — |
last_seen_at | timestamptz | — |
| 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 |
|---|---|---|
id | uuid | PK |
user_id | uuid | FK |
notif_type | code (text) | system/promo/fee_alert/session/review, etc. |
notif_category | code (text) | カテゴリグループ(UIタブ分類)Category group (UI tab bucket) |
title | text | — |
body | text | — |
deep_link | text | タップで遷移する画面(parky://)Target screen opened on tap (parky://) |
payload | jsonb | 任意の付帯情報Arbitrary attached data |
sent_at | timestamptz | 送信時刻Sent-at time |
read_at | timestamptz | 既読時刻(NULL=未読)Read-at time (NULL = unread) |
delivered_at | timestamptz | 端末到達Delivered to device |
status | code (text) | notif_status: queued/sent/delivered/failed |
user_saved_parkings
| カラムColumn | 型Type |
|---|---|
user_id, parking_lot_id | uuid (PK 複合)uuid (composite PK) |
created_at | timestamptz |
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 |
|---|---|---|
id | uuid | PK |
user_id | uuid | FK |
activity_type | text | session_start / session_end / review_post / search, etc. |
metadata | jsonb | イベント詳細Event detail |
occurred_at | timestamptz | — |
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
subscription_plans:Free / Plus 等のマスター: master of plans such as Free / Plususer_subscriptions:契約行。IAPレシート検証後に Cloudflare Workers が INSERT/UPDATE。status: trial/active/grace/cancelled/expired: subscription rows. An Cloudflare Workers INSERT/UPDATEs after IAP receipt verification.status: trial/active/grace/cancelled/expired
articles / ads
メディア記事と広告のマスター。モバイルは read-only。
Master tables for media articles and ads. The mobile app is read-only.
home_banners 2026-04-24 new
ホーム画面上部に表示される誘導・広告バナー。GET /v1/mobile/views/home-feed の banners[] として配信される。
area_places / sponsors は座標付きの地理的スポット用の VIEW であり、バナー(広告・誘導カード)とは別概念。
Horizontal banner slots rendered at the top of the home screen. Delivered via GET /v1/mobile/views/home-feed as banners[].
Distinct from area_places / sponsors, which are geographic points on the map.
| カラムColumn | 型Type | 備考Notes |
|---|---|---|
id | uuid | PK |
slot_key | text | home_top / home_middle / home_bottom |
title / subtitle | text | — |
image_asset_id | uuid | FK → assets。R2 上の画像FK → assets. Image on R2 |
image_url | text | 外部画像 URL(asset と排他想定)External image URL (mutually exclusive with asset) |
link_type | text | external / deep / none |
link_url | text | external は https URL、deep は parky://…external: https URL; deep: parky://… |
display_order | int | 同一 slot 内の表示順Order within a slot |
is_active | boolean | — |
starts_at / ends_at | timestamptz | 配信期間。RLS で範囲外を非表示Delivery window; RLS hides rows outside this range |
user_destinations 2026-04-24 new
Wherto 目的地入力欄のオートコンプリート履歴。GET /v1/mobile/views/destinations で最近候補を上位表示するためのユーザー個別テーブル。
Mapbox Search Box API(契約済の場合)から取得した place_id を持てば次回以降の重複判定に利用される。
User-scoped autocomplete history for the Wherto destination input. GET /v1/mobile/views/destinations surfaces recent picks first. When a Mapbox Search Box place_id is attached, it deduplicates subsequent selections.
| カラムColumn | 型Type | 備考Notes |
|---|---|---|
id | uuid | PK |
user_id | uuid | FK → app_users |
name | text | 目的地の表示名(駅名・施設名等)Display name (station, POI) |
address | text | — |
lat / lng | double precision | — |
place_id | text | Mapbox 等の外部 place ID。(user_id, place_id) で UNIQUEExternal place ID (e.g. Mapbox). UNIQUE by (user_id, place_id) |
use_count | int | 選択回数。重複選択で +1Selection count; incremented on collision |
last_used_at | timestamptz | — |
support_tickets / error_reports ops
support_tickets:ユーザーが送信、管理者が対応。ステータス:open/in_progress/waiting_user/resolved/closed: submitted by users and handled by admins. Status: open/in_progress/waiting_user/resolved/closederror_reports:駐車場情報の誤り報告。ステータス:submitted/triaging/resolved/rejected: reports of incorrect parking-lot information. Status: submitted/triaging/resolved/rejected
codes master
カテゴリ付きラベル辞書。起動時に一括フェッチし、クライアントのドロップダウン・ラベル表示に使用。実 DB 検証済の主要カテゴリ:
A category-keyed label dictionary. Fetched once on app boot to power every dropdown / label. Verified categories from the live DB:
| category_id | codes |
|---|---|
user_status | active / withdrawn / suspended / blocked |
vehicle_type | sedan / kei / large / bike / minivan / high_roof |
session_status | parking / completed / cancelled |
review_status | pending / approved / rejected / hidden |
parking_lot_status | pending / active / on_hold / withdrawn |
parking_hours_window_type | business / entry / exit / after_hours_exit |
day_type | weekday / saturday / sunday / holiday / holiday_eve / all |
tag_category | facility / marketing / payment / other |
notif_type | system / info / promo / review_reminder / ... |
notif_status | draft / scheduled / sending / sent / failed |
7.3 モバイル固有の読み書きマトリクス 7.3 Mobile read/write matrix
| テーブルTable | モバイル読取Mobile read | モバイル書込Mobile write | RLS 要点RLS key points |
|---|---|---|---|
parking_lots / parking_lot_pricing_groups / parking_spots (+ hours / pricing_rules / images / tags)(+ hours / pricing_rules / images / tags) | ✅ 全件✅ All | ❌ | status='active' かつ deleted_at IS NULLstatus='active' and deleted_at IS NULL |
parking_sessions | ✅ 自分のみ✅ Self only | ✅ 自分のみ✅ Self only | user_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 only | ✅ read_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 | ✅ 公開中✅ Published | ❌ | published_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 | status='cancelled' + cancelled_reason でキャンセル管理 (deleted_at は無し)Cancelled via status='cancelled' + cancelled_reason (no deleted_at) |
| レビュー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
- 楽観的更新Optimistic updates:レビュー・メモ・保存等はクライアントで即時反映、失敗時にロールバック+トースト通知: reviews, memos, saves, etc. are reflected on the client immediately, rolled back with a toast on failure
- 悲観的確定Pessimistic commit:駐車終了の料金確定は必ずサーバーRPCを待つ: final pricing at end-of-parking always waits on the server RPC
- 冪等性Idempotency:全てのRPCは
client_request_idを受け取り、重複リクエストを排除: every RPC accepts aclient_request_idand de-duplicates repeat requests - ソフトデリートSoft delete:ユーザー直接操作の削除は
deleted_atカラム利用(CLAUDE.md準拠): user-initiated deletions use thedeleted_atcolumn (per CLAUDE.md)