Data Model Diagram

This document presents the Tutor data model at the field level: the key domain tables drawn directly from the CREATE TABLE / ALTER TABLE statements in src/product/booking/schema.ts, src/product/booking/availability-schema.ts, src/lib/hosts.ts and src/lib/vendor-schema.ts. Tutor is a tutoring & education booking marketplace: tutors (hosts) publish Lessons and their weekly availability, and students (customers) book a lesson time. Tutor stores "soft enums" as plain VARCHAR columns with documented allowed values (so they can be extended without a migration), money as integer cents, and arrays/objects as JSONB.

Domain overview

MERMAID
classDiagram
    class Host {
        +int id
        +int customer_id
        +string slug
        +string status
        +numeric commission_override
    }
    class Listing {
        +int id
        +string slug
        +int owner_id
        +int category_id
        +string experience_type
        +int deposit_pct
        +string status
    }
    class AvailabilityRule {
        +int id
        +int host_id
        +int listing_id
        +smallint weekday
        +time start_time
        +time end_time
        +int slot_minutes
        +int capacity
    }
    class ExperienceSession {
        +int id
        +int listing_id
        +int instructor_id
        +timestamptz starts_at
        +int seats_total
        +int seats_booked
        +int price_per_seat
    }
    class Booking {
        +int id
        +string reference
        +int product_id
        +int session_id
        +int customer_id
        +string booking_mode
        +string status
        +string payment_status
        +int total
    }
    class BookingPayment {
        +int id
        +int booking_id
        +string kind
        +int amount
        +string status
    }
    class BookingRefund {
        +int id
        +int booking_id
        +int amount
        +string initiated_by
        +string status
    }
    class Customer {
        +int id
        +string slug
        +string email
        +string verification_status
    }
    class Coupon {
        +int id
        +string code
        +string discount_type
        +string applies_to
    }
    Customer "1" --> "0..1" Host : host profile
    Host "1" --> "0..*" Listing : owns
    Host "1" --> "0..*" AvailabilityRule : publishes
    Host "1" --> "0..*" ExperienceSession : teaches
    Listing "1" --> "0..*" AvailabilityRule : scoped by (optional)
    Listing "1" --> "0..*" ExperienceSession : scheduled as
    ExperienceSession "1" --> "0..*" Booking : reserved by
    Customer "1" --> "0..*" Booking : books
    Booking "1" --> "0..*" BookingPayment : settled by
    Booking "1" --> "0..*" BookingRefund : refunded by
    Coupon "1" --> "0..*" Booking : discounts

Listing (Lesson)

listingssrc/product/booking/schema.ts. Every listing here is a Lesson a tutor offers. Several column names (experience_type, cuisine_type, class_rules, meeting_point, menu_courses, …) are inherited from the booking engine's generic, vertical-agnostic vocabulary — the tutor pack (src/product/verticals/tutor/pack.ts) simply doesn't surface the columns it doesn't need (e.g. cuisine_type, meeting_point, menu_courses) and repurposes others (skill_level reads as study level, duration_minutes as lesson length).

Column Type Default Meaning
id SERIAL Primary key
public_id VARCHAR(40) p… Opaque public id used in URLs
slug VARCHAR(180) Unique URL slug
name VARCHAR(220) Lesson name
summary / description text '' Short tagline / full description
category_id INTEGER null master_items (subject / category taxonomy)
owner_id INTEGER null hosts (NULL = admin-owned)
experience_type VARCHAR(20) 'class' Engine-generic label for the booking "world"; the tutor pack only uses class (see Developer Guide)
hero_image / gallery VARCHAR/JSONB ''/[] Cover image + image list
video_url / videos VARCHAR/JSONB ''/[] Promo video(s)
address / city / region / country VARCHAR (Italy) Free-text location, for in-person lessons (online-only tutors leave it blank)
location_id INTEGER null locations (drives Popular Destinations)
latitude / longitude NUMERIC(9,6) null Map coordinates
duration_minutes INT 180 Typical lesson length
skill_level VARCHAR(20) 'all' all · beginner · intermediate · advanced
cuisine_type VARCHAR(80) '' Engine-generic tag column, unused by the tutor pack
whats_included / dietary_options JSONB [] "What's included" items · engine-generic column, unused by the tutor pack
what_to_bring / class_rules TEXT '' What a student should bring · lesson ground rules
languages_spoken JSONB [] Languages the lesson is taught in
cancellation_policy TEXT '' Free-text policy note
cancellation_policy_slug VARCHAR(30) 'moderate' flexible · moderate · firm · strict · non-refundable
deposit_pct INT 30 Deposit percentage at checkout
instant_booking BOOLEAN true false = Request to Book (tutor must accept)
status VARCHAR(20) 'draft' Publication status
meeting_point / itinerary / menu_courses VARCHAR/JSONB ''/[] Engine-generic columns from the tour/dining worlds, unused by the tutor pack
sort_order INT 0 Ordering
created_at / updated_at TIMESTAMPTZ NOW() Timestamps

Availability Rule (weekly hours)

availability_rulessrc/product/booking/availability-schema.ts. A tutor publishes recurring weekly hours plus a lesson length instead of hand-creating each lesson time; the engine expands these rules into bookable lesson times at read time and only writes an experience_sessions row once a student actually books one.

Column Type Default Meaning
id SERIAL Primary key
host_id INTEGER The tutor this rule belongs to
listing_id INTEGER null Scopes the rule to one Lesson; NULL = every Lesson the tutor owns
weekday SMALLINT 0=Sunday … 6=Saturday
start_time / end_time TIME Local wall-clock hours the tutor is available
slot_minutes INT 60 Lesson length generated from this rule
buffer_minutes INT 0 Gap kept free after each lesson time
capacity INT 1 Students per lesson time; 1 = one-to-one
price INT 0 Cents per lesson time; 0 = fall back to the listing's price
valid_from / valid_to DATE null Optional date window the rule applies within
is_active BOOLEAN true Active flag

Experience Session (booked lesson time)

experience_sessionssrc/product/booking/schema.ts. In slot mode a row here is materialised from an availability_rules expansion only once a student books it — it is not pre-generated inventory. bookings.session_id points here.

Column Type Default Meaning
id SERIAL Primary key
public_id VARCHAR(40) s… Opaque public id
listing_id INTEGER FK → listings (ON DELETE CASCADE)
starts_at TIMESTAMPTZ Lesson time start
ends_at TIMESTAMPTZ null Lesson time end
timezone VARCHAR(60) 'Europe/Rome' IANA timezone
seats_total INT 12 Capacity for this lesson time (1 for a 1:1 lesson)
seats_booked INT 0 Students booked (maintained on confirm/cancel)
min_seats INT 1 Below this the lesson time may be cancelled
max_per_booking INT 8 Max students per single booking
price_per_seat INT 0 Per-student price (cents)
price_private INT 0 Whole-lesson-time buyout price (cents)
currency VARCHAR(3) 'EUR' ISO currency
instructor_id INTEGER null hosts — the tutor teaching this lesson time
status VARCHAR(20) 'scheduled' scheduled · cancelled · completed
is_active BOOLEAN true Active flag

Booking

bookingssrc/product/booking/schema.ts. reference is unique. Money in cents.

Column Type Default Meaning
id SERIAL Primary key
reference VARCHAR(30) Unique human reference
public_id VARCHAR(40) b… Opaque public id
product_type VARCHAR(20) Engine-generic label mirroring listings.experience_type; the tutor pack only uses class
product_id INTEGER listings
session_id INTEGER null experience_sessions
booking_mode VARCHAR(20) 'per_person' per_person · group · private
customer_id INTEGER null customers (ON DELETE SET NULL); a student may book without an account
guest_name / guest_email / guest_phone VARCHAR '' Contact details captured at checkout
num_adults / num_children INT 1 / 0 Party size (a lesson booked for a child learner vs. an adult learner)
price_breakdown JSONB [] Line items (recomputed server-side)
subtotal / discount / fees / tax / deposit / total INT 0 Money (cents)
currency VARCHAR(3) 'EUR' ISO currency
coupon_id / coupon_code INT/VARCHAR null/'' Applied coupon
influencer_id / referral_discount INT null / 0 Affiliate attribution + referral discount (cents)
status VARCHAR(20) 'pending' pending · confirmed · cancelled · completed · no_show
payment_status VARCHAR(20) 'unpaid' unpaid · deposit_paid · paid · refunded
host_status VARCHAR(20) 'none' none · requested · accepted · declined
provider / provider_ref VARCHAR '' Payment gateway + reference
source VARCHAR(20) 'website' website · admin · ical
created_at / cancelled_at / deleted_at TIMESTAMPTZ NOW()/null Timestamps (soft-delete to Trash)

Money that actually moves is recorded in booking_payments (kind of deposit/balance/refund); cancellation refunds queue in booking_refunds for admin approval.

Host (Tutor account)

hostssrc/lib/hosts.ts. One row per tutor, 1:1 with a customers account via customer_id (UNIQUE).

Column Type Default Meaning
id SERIAL Primary key
customer_id INTEGER FK → customers (UNIQUE, ON DELETE CASCADE)
business_name VARCHAR(200) '' Public tutor/tutoring-business name
slug VARCHAR(220) Unique public slug
bio / avatar / cover_image text/VARCHAR '' Public profile
paypal_email VARCHAR(200) '' Payout email
payout_method VARCHAR(20) 'paypal' paypal · bank · stripe
commission_override NUMERIC(5,2) null Per-tutor commission % (NULL = plan/platform default)
status VARCHAR(20) 'active' pending · active · suspended
is_verified / verification_status BOOLEAN/VARCHAR(20) false/'unverified' KYC state (unverified/pending/verified/rejected)
KYC / legal / tax various '' legal_name, date_of_birth, id_type, tax_id, registered address
min_payout_cents INTEGER 5000 Minimum payout threshold
notify_prefs JSONB booking/payout/message Notification toggles

Coupon

couponssrc/product/booking/schema.ts.

Column Type Default Meaning
id SERIAL Primary key
code VARCHAR(60) Unique coupon code
description VARCHAR(200) '' Internal note
discount_type VARCHAR(10) 'percent' percent · fixed
discount_value INT 0 Percentage or fixed amount (cents)
applies_to VARCHAR(20) 'all' all · class · accommodation · specific (engine-generic values; the tutor pack uses all/class/specific)
target_ids JSONB [] Scope target ids (when applies_to='specific')
min_amount INT 0 Minimum booking total to qualify (cents)
max_discount INT 0 Cap on a percentage discount (cents)
max_redemptions INT 0 Global limit (0 = unlimited)
per_customer_limit INT 0 Per-customer limit
times_redeemed INT 0 Times used
combinable BOOLEAN false Stackable with other discounts
valid_from / valid_until DATE null Validity window
is_active BOOLEAN true Active flag

Extra (Add-on)

extrassrc/product/booking/schema.ts. Students pick these at checkout (e.g. extra worksheets, a recorded-session add-on); the chosen ones snapshot into booking_extras.

Column Type Default Meaning
id SERIAL Primary key
name VARCHAR(160) Add-on name (e.g. extra worksheet pack, recorded session)
description VARCHAR(400) '' Short description
applies_to VARCHAR(20) 'class' all · class · accommodation (engine-generic values)
price INT 0 Price (cents)
price_type VARCHAR(20) 'flat' flat · per_person · per_night · per_person_night
max_qty INT 1 Max units for a flat extra
is_active BOOLEAN true Active flag
sort_order INT 0 Ordering

Soft Enums

Enumerations are stored as VARCHAR with documented allowed values:

Field Table Allowed values
experience_type listings class · tour · dining (engine-generic; the tutor pack only uses class)
skill_level listings all · beginner · intermediate · advanced
cancellation_policy_slug listings flexible · moderate · firm · strict · non-refundable
status experience_sessions scheduled · cancelled · completed
product_type bookings class · tour · dining (engine-generic; the tutor pack only uses class)
booking_mode bookings per_person · group · private
status bookings pending · confirmed · cancelled · completed · no_show
payment_status bookings unpaid · deposit_paid · paid · refunded
host_status bookings none · requested · accepted · declined
source bookings website · admin · ical
kind booking_payments deposit · balance · refund
status booking_payments pending · paid · failed · refunded
initiated_by booking_refunds customer · host · admin · system
status booking_refunds pending · approved · refunded · rejected · failed · refund_pending
discount_type coupons percent · fixed
applies_to coupons all · class · accommodation · specific (engine-generic values)
price_type extras flat · per_person · per_night · per_person_night
status hosts pending · active · suspended
verification_status hosts / customers unverified · pending · verified · rejected
status host_earnings pending · approved · paid · rejected
monetization_mode platform_settings commission · subscription · hybrid
interval subscription_plans month · year
sender messages guest · host

These values are read from the actual CREATE TABLE / ALTER TABLE comments in the schema source; because they are plain strings, admins and developers can extend them without altering the column type.


© CreativeCape Solutions · creative-cape.com · support@creative-cape.com