Développeurs

Modèle de données

Aperçu des principales entités stockées dans Supabase. Utile pour comprendre la structure interne de Batlr et pour les intégrations avancées (export, BI, sync externe).


Vue d'ensemble

restaurants
   ↓ owns
   ├── tables ──── zones
   ├── floor_plans
   ├── services (opening hours)
   ├── customers
   │      ↓ may have
   │      reservations
   │           ↓ may have
   │           ├── reservation_events (audit log)
   │           └── communication_events
   ├── waitlist_entries
   └── team_members

restaurants

ColonneTypeDescription
idUUIDPK
nametextNom commercial
address, phone, emailtextCoordonnées
settingsjsonbTous les réglages app (durée, modes paiement, etc.)
is_proboolRestaurant inclus dans abonnement Pro
subscription_statusjsonbDétails palier, trial, restaurants_assignés
pro_sourcetextapple|stripe|admin
created_at, updated_attimestamptzMétadonnées

reservations

ColonneTypeDescription
idUUIDPK
restaurant_idUUIDFK → restaurants
customer_idUUIDFK → customers (peut être null)
service_idUUIDFK → services (peut être null)
table_idUUIDFK → tables
table_numbertextNuméro affiché ("7" ou "7+8")
guest_nametextNom du client (denormalisé)
guest_phone, guest_emailtextContact denormalisé
party_sizeint1-99 (CHECK constraint)
datedateYYYY-MM-DD
timetimeHH:MM:SS
durationintMinutes (nullable, défaut = restaurant settings)
statustextConfirmed|Pending|Arrived|Seated|Completed|Cancelled|No-show
tagstext[]Noms de tags appliqués
notestextNotes internes
sourcetextSite web|Téléphone|Walk-in|App|TheFork|Google|Liste d'attente
created_byUUIDFK → team_members
seated_attimestamptzQuand le client s'est assis
arrived_countintNb de personnes arrivées (partial arrival)
skip_depositboolExempté de paiement
payment_statustextpending|card_saved|charged|refunded|...
stripe_payment_method_idtextID Stripe
stripe_checkout_session_idtextID Stripe Checkout
reconfirmation_tokentextToken unique pour reconfirmation
reconfirmation_sent_attimestamptzDate d'envoi
reconfirmation_statustextpending|confirmed|declined
reminders_sentjsonb[]Historique rappels envoyés
reminder_overridesjsonbSurcharges par réservation
created_at, updated_attimestamptzMétadonnées

Trigger d'overlap

Sur INSERT/UPDATE, un trigger SQL vérifie qu'il n'y a pas de conflit temporel avec une autre réservation sur la même table (en tenant compte des durées).


customers

ColonneTypeDescription
idUUIDPK
restaurant_idUUIDFK → restaurants (ou null si CRM partagé)
name, phone, emailtextCoordonnées
notestextNotes internes
tagstext[]VIP|Habitué|Allergie|...
classificationtextVIP|Regular|New (calculé)
visit_countintVisites complétées (calculé)
last_visittimestamptzDernière visite
no_show_countintCalculé
cancellation_countintCalculé
total_spentintCumul (cents)
created_at, updated_attimestamptzMétadonnées

tables

ColonneTypeDescription
idUUIDPK
restaurant_idUUIDFK → restaurants
floor_plan_idUUIDFK → floor_plans
zone_idUUIDFK → zones
nametextNuméro affiché
capacity_min, capacity_maxintCapacité
position_x, position_yfloatCoordonnées canvas
width, heightfloatDimensions custom (nullable)
rotationfloatDegrés
shapetextround|square|rectangular
chair_sidesintBitmask (1=top, 2=right, 4=bottom, 8=left)
capacity_overridesjsonbCapacités par combo (ex. { "7+8": 6 })
fill_groupintPriorité d'assignation auto
updated_attimestamptz

zones

ColonneTypeDescription
idUUIDPK
restaurant_idUUIDFK → restaurants
floor_plan_idUUIDFK → floor_plans
nametextNom
colortextHex
position_x, position_y, width, heightfloatRectangle
sort_orderintOrdre

floor_plans

ColonneTypeDescription
idUUIDPK
restaurant_idUUIDFK
nametext"Salle principale", "Terrasse"…
sort_orderintOrdre

Tables associées

  • daily_table_overrides — positions/hidden par date
  • daily_extra_tables — tables temporaires par date
  • daily_floor_notes — notes par date

services

ColonneTypeDescription
idUUIDPK
restaurant_idUUIDFK
nametext"Midi", "Soir", "Brunch dominical"
start_time, end_timetimeHH:MM
days_of_weekint[][1..7] (Mon-Sun)
is_specialboolService ponctuel ?
specific_datedateSi spécial : date concernée
label, messagetextAffichage client

waitlist_entries

ColonneTypeDescription
idUUIDPK
restaurant_idUUIDFK
datedateDate souhaitée
timetimeHeure préférée (nullable)
party_sizeint
service_id, preferred_floor_plan_idUUIDPréférences
guest_name, guest_email, guest_phonetextContact
notestext
statustextwaiting|notified|called|converted|expired|cancelled
notified_at, called_attimestamptzAction history
notification_tokentextToken pour page de suivi
position_in_queueintCalculé
created_at, updated_attimestamptz

team_members

ColonneTypeDescription
idUUIDPK
user_idUUIDFK → auth.users (null pour serveurs PIN-only)
restaurant_idUUIDFK
roletextAdmin|Manager|Server
display_nametextNom affiché
emailtextSi rôle Manager/Admin
pintextHash PBKDF2
pin_salttextSel du hash
allowed_tabstext[]Surcharge des permissions par défaut
is_activeboolDésactivable sans suppression
created_attimestamptz

reservation_events

Audit log immuable des changements de statut.

ColonneTypeDescription
idUUIDPK
reservation_idUUIDFK
customer_idUUIDFK
from_status, to_statustextTransition
changed_byUUIDFK → team_members
metadatajsonbContexte (raison annulation, arrived_count, …)
created_attimestamptz

communication_events

Tracking des envois email/SMS.

ColonneTypeDescription
idUUIDPK
restaurant_idUUIDFK
reservation_id, customer_id, waitlist_entry_idUUIDFK (nullable)
typetextreminder|confirmation|review_request|...
channeltextemail|sms
recipienttextEmail ou téléphone
statustextsent|delivered|bounced|complained
sent_at, delivered_at, bounced_attimestamptzTimeline
bounce_reasontext

sms_usage

Quota SMS mensuel.

ColonneTypeDescription
restaurant_idUUIDFK
monthtextYYYY-MM
sms_sentintCompteur
sms_creditsintCrédits achetés en plus

RPC get_sms_quota(restaurant_id, included) retourne remaining = (included + sms_credits - sms_sent).


RLS

Toutes les tables sont protégées par Row-Level Security. Le pattern par défaut :

  • Authenticated (staff) — accès aux données de leur restaurant via get_user_restaurant_ids()
  • Anon (widget) — accès limité aux colonnes nécessaires (pas de payment_*, pas de notes internes)

À lire ensuite