Skip to main content
Tripfy Africa uses MySQL 8.0+ with the utf8mb4 character set and the InnoDB storage engine. All schema changes are managed through Laravel migrations located in database/migrations/. Engine: MySQL 8.0+  ·  Charset: utf8mb4_unicode_ci  ·  Storage engine: InnoDB

Core tables

Stores every registered traveler account. A user record is the root identity for bookings, transactions, reviews, and guide profiles.
ColumnTypeNotes
idbigint unsignedPrimary key
firstnamevarchar(255)
lastnamevarchar(255)
usernamevarchar(255)Nullable
emailvarchar(191)Unique
email_verified_attimestampNullable
passwordvarchar(255)Bcrypt hash
phonevarchar(255)Nullable
countryvarchar(255)Nullable
country_codevarchar(255)Nullable
balancedecimal(11,2)Wallet balance, default 0.00
imagevarchar(255)Nullable
image_drivervarchar(50)Storage driver (local / S3 / etc.)
roletinyint0 = traveller, 1 = vendor/guide
statusboolean1 = active, 0 = suspended
identity_verifytinyint0 not applied · 1 applied · 2 approved · 3 rejected
address_verifytinyintSame enum as identity_verify
two_fabooleanTwo-factor auth enabled
email_verificationbooleanEmail OTP required
sms_verificationbooleanSMS OTP required
providervarchar(191)OAuth provider (google / facebook)
language_idintFK → languages.id
referral_idintSelf-referential referral
last_logindatetime
last_seendatetime
deleted_attimestampSoft-delete support
created_at / updated_attimestamp
CREATE TABLE `users` (
  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
  `role` tinyint NOT NULL DEFAULT 0 COMMENT '0=traveller, 1=vendor',
  `firstname` varchar(255) DEFAULT NULL,
  `lastname` varchar(255) DEFAULT NULL,
  `username` varchar(255) DEFAULT NULL,
  `email` varchar(191) NOT NULL,
  `password` varchar(255) NOT NULL,
  `balance` decimal(11,2) DEFAULT 0.00,
  `status` boolean NOT NULL DEFAULT 1,
  `deleted_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `users_email_unique` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
A guide is a registered tour operator with their own profile, rating, and packages. Each guide record is independent of the users table but is linked via vendor_infos.
ColumnTypeNotes
idbigint unsignedPrimary key
namevarchar(255)Guide display name
codevarchar(255)Unique public code
slugvarchar(255)URL-friendly identifier
designationvarchar(255)Job title / role
emailvarchar(255)Unique login email
phonevarchar(255)Nullable
imagevarchar(255)Nullable
drivervarchar(255)Storage driver
statustinyint1 = active, 0 = inactive
years_of_experienceintNullable
tour_completedintNullable
ratingdecimal(10,2)Calculated average
created_bybigint unsignedAdded by migration 2026_01_01_000001
created_at / updated_attimestamp
Extends a guide’s account with subscription plan details and listing quota tracking.
ColumnTypeNotes
idbigint unsignedPrimary key
vendor_idintFK → users.id (the vendor user account)
active_planintFK → plans.id
current_plan_purchase_datedateNullable
current_plan_expiry_datedateNullable
posted_listingintTotal package listings created
current_plan_posted_listingintListings created under the current plan
badge_idintNullable
auto_renew_current_plantinyint1 = enabled, 0 = disabled
avg_ratingdecimal(10,2)Vendor average rating, updated by migration 2026_01_01_000001
facebook_linkvarchar(255)Nullable social link
twitter_linkvarchar(255)Nullable social link
linkedin_linkvarchar(255)Nullable social link
instagram_linkvarchar(255)Nullable social link
Tour packages created and owned by guides. Packages are the core product unit that travelers browse and book.
ColumnTypeNotes
idbigint unsignedPrimary key
uidvarchar(255)Unique public identifier
owner_idintFK → users.id (vendor who owns the package)
titlevarchar(255)
slugvarchar(255)Unique URL slug
category_idbigint unsignedFK → package_categories.id
destination_idbigint unsignedFK → destinations
pricedecimal(10,2)Base price
discount_pricedecimal(10,2)Nullable
max_personsintDefault 1
durationintTrip length in days
amenitiesjsonArray of amenity IDs
imagesUrljsonArray of image paths
thumbnailvarchar(255)
statustinyint1 = active, 0 = inactive
is_featuredtinyint1 = featured
avg_ratingdecimal(3,2)Denormalised average
total_reviewsintDenormalised count
meta_title / meta_description / meta_keywordsvariousSEO fields
A FULLTEXT index covers title and description to power the search bar.
Records every booking made by a traveler for a package.
ColumnTypeNotes
idbigint unsignedPrimary key
uidvarchar(255)Unique booking reference
package_idbigint unsignedFK → packages.id
user_idbigint unsignedFK → users.id (traveler)
guide_idbigint unsignedFK → guides.id
total_personintDefault 1
total_pricedecimal(10,2)
datedateTour date
timetimeNullable
statusenumpending · confirmed · completed · cancelled · refunded
payment_statusenumpending · paid · failed · refunded
payment_methodvarchar(50)Gateway code
transaction_idvarchar(255)External reference
cancelled_attimestampNullable
cancellation_reasontextNullable
confirmed_attimestampNullable
completed_attimestampNullable
One review per user per package. Adding a review updates the avg_rating and total_reviews counters on the packages row.
ColumnTypeNotes
idbigint unsignedPrimary key
package_idbigint unsignedFK → packages.id
user_idbigint unsignedFK → users.id
guide_idbigint unsignedFK → guides.id
ratingint1–5; CHECK (rating BETWEEN 1 AND 5)
commenttextNullable
imagesjsonArray of uploaded image paths
statustinyint1 = published, 0 = hidden
A unique composite key on (package_id, user_id) prevents duplicate reviews.

Commerce tables

Audit ledger for every financial movement on the platform (bookings, deposits, payouts, refunds, commissions).
ColumnTypeNotes
idbigint unsignedPrimary key
user_idbigint unsignedFK → users.id
transactional_idintPolymorphic FK
transactional_typevarcharPolymorphic type (e.g. App\Models\Booking)
amountdoubleTransaction amount
balancedoubleUser balance after transaction
amount_in_basedoubleAmount in platform base currency
chargedecimal(11,2)Fee applied
trx_typevarchar+ credit or - debit
remarksvarcharHuman-readable description
trx_idvarcharUnique transaction reference
Records wallet top-up requests from users via payment gateways.
ColumnTypeNotes
idbigint unsignedPrimary key
user_idbigint unsignedFK → users.id
payment_method_idbigint unsignedFK → gateways.id
payment_method_currencyvarcharCurrency code used
amountdecimal(18,8)Amount in base currency
percentage_chargedecimal(18,8)
fixed_chargedecimal(18,8)
payable_amountdecimal(18,8)Actual amount charged to user
btc_amount / btc_walletvariousFor crypto gateways
trx_idvarcharTransaction reference
statustinyint0 pending · 1 success · 2 request · 3 rejected
notetextAdmin note
Records guide withdrawal requests from their platform balance.
ColumnTypeNotes
idbigint unsignedPrimary key
user_idbigint unsignedFK → users.id
payout_method_idbigint unsignedFK → payout_methods.id
payout_currency_codevarchar
amountdecimal(18,8)Requested amount
chargedecimal(18,8)Fee deducted
net_amountdecimal(18,8)Amount received after fees
amount_in_base_currencydecimal(18,8)
trx_idvarchar(50)Reference
statusboolean0 = pending, 1 = processed
feedbacktextAdmin feedback
Configuration record for each supported payment gateway (Stripe, Razorpay, manual, etc.).
ColumnTypeNotes
idbigint unsignedPrimary key
codevarchar(191)Unique gateway code
namevarchar(191)Display name
sort_byintDisplay order
imagevarchar(191)Logo path
statustinyint0 inactive · 1 active
parameterstextJSON of API keys / credentials
currenciestextSupported currency list
environmentenumtest or live
is_sandboxtinyint1 = sandbox mode
is_manualtinyint1 = manual bank-transfer gateway
Discount coupons that can be applied at checkout.The Coupon model (app/Models/Coupon.php) manages coupon validation. Key fields include the coupon code, discount type (percentage or fixed), minimum order amount, usage limits, and expiry date.

Content tables

blogs stores each article’s metadata and SEO settings. Localised content (title, body) lives in the companion blog_details table.
ColumnTypeNotes
idbigint unsignedPrimary key
category_idintFK → blog_categories.id
blog_imagevarcharCover image path
blog_image_drivervarcharStorage driver
statusboolean1 = published
page_titlevarchar
meta_title / meta_keywords / meta_descriptionvariousSEO
blog_categories has only id, name (varchar 100), and slug (varchar 100).blog_comments links blog_id and user_id with a comment string and a status flag (1 published, 0 unpublished).
pages holds static page shells (home, about, contact, etc.). The page_details table stores the localised section content for each page, keyed by page_id and language_id.
languages holds each supported locale (code, name, is_default, status). The contents / content_details tables store every translatable UI string, keyed by a data_key and language_id.

System tables

Separate admin accounts with role-based access control, independent of the users table.
ColumnTypeNotes
idbigint unsignedPrimary key
namevarchar(100)
usernamevarchar(50)Unique
emailvarchar(191)Unique
passwordvarchar(191)
image / image_drivervarcharAvatar
admin_accesstextJSON permissions
statustinyint1 = active
last_loginvarchar(50)
last_seendatetime
Default admin: [email protected] (set by database/seeders/AdminSeeder.php).
Single-row site-wide configuration table. Settings include branding, currency, notification toggles, reCAPTCHA, analytics, and more.
ColumnNotes
site_titlePlatform name shown in the browser tab
primary_color / secondary_colorHex values; changing these and saving regenerates tripfy.css
base_currency / currency_symbole.g. USD / $
sender_email / sender_email_nameDefault From address for outgoing email
registration1 = public registration open
push_notification / email_notification / sms_notificationChannel toggles
email_verification / sms_verificationRequire verification on sign-up
google_recaptcha1 = reCAPTCHA active on public forms
is_maintenance_mode1 = shows maintenance page
is_force_ssl1 = redirect all HTTP to HTTPS
tawk_id / tawk_statusTawk.to live chat
logo / favicon / admin_logoAsset paths with driver columns
Editable templates for every platform notification event. Each row covers email, SMS, in-app, and push channels.
ColumnTypeNotes
idbigint unsignedPrimary key
language_idbigint unsignedFK → languages.id
namevarcharHuman-readable template name
email_fromvarcharSender address for this template
template_keyvarcharUnique identifier (e.g. NEW_BOOKING_RECEIVED)
subjecttextEmail subject line
short_keystextJSON map of [[variable]] placeholders
email / sms / in_app / pushtextChannel-specific body
statustextJSON: {"mail":"1","sms":"1","in_app":"1","push":"1"}
notify_forboolean0 = user notification · 1 = admin notification
Templates added by migration 2026_01_01_000001_tripfy_africa_fixes.php:
  • NEW_BOOKING_RECEIVED — sent to guide when a traveler books
  • BOOKING_ACCEPTED — sent to traveler when guide accepts
  • BOOKING_REJECTED — sent to traveler when guide declines
  • TOUR_COMPLETED — sent to traveler prompting a review
Subscription plan definitions for guide accounts. Linked via vendor_infos.active_plan.The Plan model (app/Models/Plan.php) and PlanPurchase model (app/Models/PlanPurchase.php) handle plan-to-vendor associations and billing history.

Logging tables

The ActivityLog model (app/Models/ActivityLog.php) records significant user and admin actions for auditing. Common fields include user_id, log_type, message, and created_at.
Records every successful login with geolocation and device data.
ColumnTypeNotes
idbigint unsignedPrimary key
user_idbigint unsignedFK → users.id
longitude / latitudevarcharGeolocation
country_code / countryvarchar
locationvarcharCity / region string
ip_addressvarchar
browser / osvarcharUser agent parsed values
get_devicevarcharDevice type
Help-desk ticketing. Each ticket has a thread of messages (support_ticket_messages) and optional file attachments (support_ticket_attachments).
ColumnTypeNotes
idbigint unsignedPrimary key
user_idbigint unsignedFK → users.id
ticketvarcharUnique ticket number
subjecttext
statustinyint0 open · 1 answered · 2 replied · 3 closed
last_replytimestampNullable

Entity relationships

Key relationship rules

  • One-to-many: A guide creates many packages; a user makes many bookings; a booking generates many transactions.
  • One-to-one: A guide has one vendor_infos record.
  • Polymorphic: transactions.transactional_id / transactional_type can reference any model (Booking, Deposit, Payout).
  • Cascade deletes: Foreign keys on packages, bookings, and transactions are defined with ON DELETE CASCADE so removing a parent record cleans up child rows automatically.
  • Soft deletes: The users table has a deleted_at column; records are never hard-deleted from production.

Build docs developers (and LLMs) love