This is the exhaustive catalog of the backend domain model. For the conceptual shape — how the
inventory is a published mirror of the CRM and where the transactional rows sit — read
The data model first; this page is the reference you look things up in.
Source of truth: backend/app/Models/*.php and backend/app/Enums/**/*.php; every file:line below
is relative to backend/. Named columns only — never values.
Artifact
Count
Eloquent model classes
85 (app/Models/*.php)
PHP enums
125 (73 int-backed, 52 string-backed)
Migration files
295 (92 are Schema::create)
CRM-mirror models (carry a source_id)
27
Models holding personal PII
19
Single-Table Inheritance on users. User (User.php:14, extends Voyager’s User) is the base;
nine persona models add a role_id global scope and share the users table with no $table:
Broker, Shopper, ShopperAdmin, SalesManager, Editor, Moderator, Viewer, Financer.
SalesMan is the exception — a User subclass that points at its own sales_team table
(SalesMan.php:18).
Single-Table Inheritance on media_files. MediaFile is the base; Image, Video,
Document extend it with a media_type global scope and no own tables.
Pivot models. DestinationUserRequest extends Pivot (destination_user_request) and
AddonUnit extends Pivot (addon_unit).
Separate auth model. OmanPreRegistrationBroker extends Authenticatable — its own credential
store for the Oman broker pre-registration portal.
CRM-mirror pattern. Per adr/03-crm-integration.md: CRM rows are fetched, stored with
is_published=false, admin-enriched, then flipped to true; only published rows ship to public
APIs. Mirror models carry a source_id (or *_source_id).
Assignment graph = the ACL backbone. Personas link to inventory
(Country/Destination/Project/Unit) through one polymorphic pivot table assignables
(morphedByMany(..., 'assignable', foreignPivotKey: 'user_id')) — who can see which inventory.
Legend: CRM = CRM-mirror (source_id). PII = holds personal data. STI = shares a parent’s table.
Model
Table
Key relations
CRM
PII
Country
countries
hasMany UnitType/Destination; morphMany Metadata/SearchableLog; morphOne Section
—
—
Destination
destinations
belongsTo Country; hasMany Project/Location/Promotion/Testimonial/EducationalHub/PaymentNotifier; belongsToMany News/Offer/BrokerageCompany; morphMany Facility/FAQ/Video
✔
—
Project
projects
belongsTo Destination; hasMany Unit (+ published-for-broker/sales-man scopes)/ProjectPhase
✔
—
ProjectPhase
project_phases
belongsTo Project; hasMany Unit
—
—
Unit
units
belongsTo Project/UnitType/ProjectPhase/SalesOfferBasePdf; belongsToMany Tag/Addon/Masterplan; hasMany PaymentTerm/UnitSale/UnitUser
✔
—
UnitType
unit_types
belongsTo Country; hasMany Unit/AnalyticsBrokerSale/LaunchProjectUnitType
✔
—
Addon
addons
belongsToMany Unit (via AddonUnit); morphMany Metadata
—
—
AddonUnit (Pivot)
addon_unit
Addon ↔ Unit
—
—
Masterplan
masterplans
belongsToMany Unit; morphMany Metadata
—
—
Facility
facilities
morphTo model (Destination/Unit/Launch)
—
—
Location
locations
belongsTo Destination
—
—
Tag
tags
belongsToMany Unit/Section
—
—
AccessCard
access_cards
belongsTo Shopper/Unit
—
—
PaymentTerm
payment_terms
belongsTo Unit
—
—
Currency
currencies
belongsTo Country
✔
—
ConstructionUpdate
construction_updates
morphTo model (Destination/Unit)
—
—
Model
Table
Notes
PII
MediaFile
media_files
STI parent of Image/Video/Document; SoftDeletes
—
Image / Video / Document
media_files (STI)
media_type global scope discriminator
—
Metadata
metadata
morphTo model; typed key/value
—
Section
sections
belongsToMany Tag; morphTo model
—
Page
pages
morphMany Metadata/CustomPageSection/FAQ/Video
—
CustomPage
custom_pages
morphMany CustomPageSection (ordered); is_published
—
CustomPageSection
custom_page_sections
morphTo page
—
News
news
belongsToMany Destination; is_event/is_featured
—
Offer
offers
belongsToMany Destination
—
Promotion
promotions
belongsTo Destination
—
Testimonial
testimonials
belongsTo Destination
—
EducationalHub
educational_hubs
belongsTo Destination
—
FrequentlyAskedQuestion
frequently_asked_questions
morphTo model (Destination/Page/Launch)
—
IssueType
issue_types
reference list
—
ContactInfo
contact_info
address/phone/email
✔
Model
Table
Notes
CRM
PII
User
users
base (Voyager User); name/email/phone; morphMany Notification/UnitUser; saved Unit
✔
✔
Broker
users (role broker)
hasMany BrokerCountrySourceId/BrokerCommissionSchema/SalesInvoice; belongsTo BrokerageCompany/SalesManager; assignables
✔
✔
Shopper
users (role user)
morphMany UserRequest/UnitUser; hasMany AccessCard/UnitSale
✔
✔
ShopperAdmin
shopper_admins
admin over shopper surface
—
✔
SalesMan
sales_team
self-ref manager_id; assignables; own table
—
✔
SalesManager
users (role sales_manager)
self-ref tree; hasMany Broker; assignables
—
✔
Editor / Moderator / Viewer / Financer
users (STI)
admin staff accounts; assignables
—
✔
UserOtp
user_otps
morphTo; action/channel/recipient/otp/expires_at
—
✔
ExpirationToken
expiration_tokens
morphTo; token store
—
—
Notification
notifications
morphTo notifiable; data→json
—
—
UnitUser
unit_user
saved-units pivot-as-model
—
—
Model
Table
Notes
CRM
PII
BrokerageCompany
brokerage_companies
belongsTo Country; hasMany Broker; belongsToMany Destination (lead limits)
✔
—
BrokerCommissionSchema
broker_commission_schemas
belongsTo Broker/Destination; commission tiers
—
—
BrokerCountrySourceId
brokers_source_ids
maps a broker to per-country CRM source_id
✔
—
BrokerDomain
broker_domains
belongsTo BrokerageCompany; white-label domains
—
—
BrokerWhitelistedEmail
broker_whitelisted_emails
belongsTo BrokerageCompany; email
—
✔
SalesInvoice
sales_invoices
belongsTo Broker/AnalyticsBrokerSale; morphMany Document; commission invoice
✔
—
Model
Table
Notes
CRM
PII
OmanPreRegistrationBrokerApplication
oman_pre_registration_broker_applications
belongsToMany OmanSalesConsultant; hasOne OmanPreRegistrationBroker; hasMany ..Document; heavy PII (DOB, national ID, addresses, licences)
✔
✔ (heavy)
OmanPreRegistrationBrokerDocument
oman_pre_registration_broker_documents
belongsTo application; identity/licence scans
✔
✔
OmanPreRegistrationBroker (Authenticatable)
oman_pre_registration_brokers
credential store: email/password/broker_type
—
✔
OmanSalesConsultant
oman_sales_consultants
belongsToMany applications; name/email
—
✔
OmanPreRegistrationTemplate
oman_pre_registration_templates
contract/registration-form templates
—
—
OmanPreRegistrationEmailTemplate
oman_pre_registration_email_templates
keyed email templates
—
—
Model
Table
Notes
CRM
PII
UnitSale
unit_sale
belongsTo Unit/User/Broker; morphMany Transaction; status→UnitSaleStatus, payment_method→PaymentMethods
✔
(customer by customer_source_id)
UnitAddonSale
unit_addon_sale
belongsTo Unit/User/Currency; morphMany Transaction
✔
—
Transaction
transactions
morphTo model (UnitSale/UnitAddonSale/EOIRequest); status→TransactionStatus, type→TransactionTypes
—
—
SalesOfferBasePdf
sales_offer_base_pdfs
hasMany Unit; belongsTo User (created_by)
—
—
SalesOfferPdfGeneration
sales_offer_pdf_generations
belongsTo Unit; status→SalesOfferPdfGenerationStatus; expires_at
—
—
BankAccount
bank_accounts
hasMany Launch (bank + instapay); account_number/receiver_name/type
—
✔ (financial)
Model
Table
Notes
CRM
PII
Launch
launches
belongsTo Destination; belongsToMany Project/UnitType/BrokerageCompany; hasMany EOIRequest; belongsTo BankAccount (bank + instapay)
—
—
LaunchProject
launch_projects
belongsTo Project/Launch; hasMany LaunchProjectUnitType
✔
—
LaunchProjectUnitType
launch_project_unit_types
belongsTo UnitType/LaunchProject
✔
—
EOIRequest
eoi_requests
morphTo (submitting agent); belongsTo Launch; morphMany Transaction; name/phone/email/paid_amount
✔
✔
EOISalesAgent
eoi_sales_agents
eoi_source_id/phone/email
✔
✔
Model
Table
Notes
PII
UserRequest
user_requests (was lead_requests)
belongsToMany Destination; belongsTo UnitType/DateDM; morphTo model (Broker/Shopper/SalesMan); lead/service/resale/referral
(via morph)
DestinationUserRequest (Pivot)
destination_user_request
Destination ↔ UserRequest
—
DateDM
dates_dm
date-dimension table for analytics (*_at_dm FKs)
—
PaymentNotifier
payment_notifiers
belongsTo Destination; name/email/type
✔
DestinationMissingUnitsContentReportRecipient
destination_missing_units_content_report_recipients
belongsTo Destination; email
✔
SearchableLog
searchable_logs
morphTo (Country/Destination); search analytics
—
UnitsFilterLog
units_filter_logs
filter-usage analytics
—
All carry source_id, populated from the CRM by the analytics sync. The broker set was renamed from
leads/lead_meetings/sales.
Model
Table
Notes
PII
AnalyticsBrokerLead
analytics_broker_leads
belongsTo DateDM; lead by source_id (no raw name/phone)
—
AnalyticsBrokerMeeting
analytics_broker_meetings
belongsTo DateDM; lead_source_id
—
AnalyticsBrokerSale
analytics_broker_sales
belongsTo 4×DateDM/Destination/UnitType/Broker; selling_price/crm_status/is_international
—
AnalyticsSalesManLead
analytics_salesman_leads
belongsTo DateDM; raw name+phone
✔
AnalyticsSalesManMeeting
analytics_salesman_meetings
belongsTo DateDM
—
AnalyticsSalesManSale
analytics_salesman_sales
belongsTo DateDM/Destination/UnitType; splits; customer_source_id
—
AnalyticsSalesManSaleSplit
analytics_salesman_sale_splits (was ..._sale_shares)
belongsTo SalesMan/AnalyticsSalesManSale; commission split
—
SalesManCountrySourceId
salesman_source_ids
maps salesman → per-country CRM source; self-ref manager tree
—
Where the PII lives (19 models)
All ten persona accounts (User, Broker, Shopper, ShopperAdmin, SalesMan, SalesManager,
Editor, Moderator, Viewer, Financer) plus ContactInfo, UserOtp, EOIRequest,
EOISalesAgent, AnalyticsSalesManLead, PaymentNotifier, BrokerWhitelistedEmail,
DestinationMissingUnitsContentReportRecipient, OmanSalesConsultant, and the three Oman
pre-registration models (identity docs, DOB, national ID — the heaviest ), plus BankAccount
(financial). Sale/analytics-sale rows reference customers by customer_source_id, not raw PII.
73 int-backed, 52 string-backed. Status-machine enums (🔴) drive a lifecycle and are cast onto
a model column.
Enum
Backing
Cases
Cast on
UnitSaleStatus
string
draft, pending_info, download_form, pending_finish, done, canceled
UnitSale.status
TransactionStatus
string
pending, success, failure, canceled
Transaction.status
TransactionTypes
string
thawani, paymob, wspg
Transaction.type
SalesOfferPdfGenerationStatus
string
Pending, Processing, Completed, Failed
SalesOfferPdfGeneration.status
SalesInvoiceStatus
string
pending, approved, rejected
SalesInvoice.status
SalesInvoiceCommissionStatus
int
UNPAID=0, PAID=1
SalesInvoice.commission_payment_status
OmanBrokerApplicationStatusEnums
string
12 (pending_info … contract_expired)
OmanPreRegistrationBrokerApplication.status
OmanBrokerApplicationDocumentStatusEnums
string
pending, accepted, rejected, expired
..Document.document_status
BrokerRegistrationStatusEnums
string
registration_done, otp_verify_done, password_reset_done
broker registration
ReservedSaleStatusEnums
string
pending_odh_review, partially_reserved, reserved, closed, lost
reserved-sale flow
DealStatusEnums
string
7 (lead_submitted … invoice_approved)
broker deal funnel
LeadStatusEnums
int
NEW=1, CONTRACTED=2, RESERVED=3, CANCELLED=7
lead status
AnalyticsLeadStatusEnums
string
8
analytics funnel selector
MeetingStatusEnums
int
APPROVED=1, REJECTED=2
meeting status
BrokerCommissionAnalyticsStatus
int
LATE=1, PENDING=2, CACHED=3
commission analytics
EOIPaymentStatusEnums
int
7 (PENDING_PAYMENT … REQUIRES_ACTION)
EOI payment lifecycle
LeadAdminVerificationDecisionEnums
int
NOT_VERIFIED=1, APPROVED=2, REJECTED=3
lead verification
LeadExpirationStatusEnums (SalesMan)
int
ACTIVE, NOT_RESPONSIVE, LOST, DISQUALIFIED, MET_UNREACHABLE
sales-man lead expiry
LeadStateEnums (SalesMan)
int
OPEN=0, QUALIFIED=1, DISQUALIFIED=2
sales-man lead state
External CRM state-machines (map the CRM’s own status codes, per market): EgyptCRMLeadStatusEnums
(8), EgyptCRMSaleStatusEnums (15), OmanCRMLeadStatusEnums (16), OmanCRMSaleStatusEnums (8),
MontenegroCRMLeadStatusEnums (10), MonetengroCRMSaleStatusEnums (8) — all 🔴. (Repo misspells
“Monetengro” in two Montenegro filenames.)
Enum
Backing
Cases
PaymentMethods
string
CASH, BANK_TRANSFER, CREDIT_DEBIT_CARD, CHEQUE, UNIT_TRANSFER (CRM option-set codes)
ConstructionStatus
string
off_plan, built
FinishingStatus
string
core_shell, finished
UnitDirection
string
8 (N, S, E, W, NE, NW, SE, SW)
MediaType
string
image, video, document (STI discriminator)
CurrencyEnums
string
EGP, USD, GBP, EUR, CHF, OMR, AED
CountryEnums
string
egypt, oman, montenegro
DestinationSlugEnums
string
7 (el-gouna, makadi-heights, o-west, byoum, lustica-bay, hawana-salalah, jebel-sifah)
UserRequestsEnums
string
lead, unit_service, unit_resale, referral
NotificationTypeEnums
string
lead, sale, sales_invoice, unit, eoi
BankAccountTypeEnum
string
bank, instapay
UnitSaleTypeEnum
string
online, offline
SourceOfSale
int
BROKER=1, DIRECT=2
PortalWebEnums
int
SHOPPER=1, BROKER=2, SALES_MAN=3
LeadQualityEnums
int
HOT, WARM, COLD, NA, IRRELEVANT
SalesManagerTitleEnums
int
CEO, HEAD, DIRECTOR, SALES_MANAGER, SALES_AGENT
EOIAttachmentsTypeEnums
int
FRONT, BACK, CHEQUE, PASSPORT, INSTAPAY
EOICustomerIdentificationNumberTypeEnums
int
NATIONAL_ID=1, PASSPORT=2
EOIPaymentMethodEnums
string
PAYMENT_LINK, CHEQUE, INSTAPAY
OmanBrokerRegistrationTypeEnums
string
ambassador, local_company, international_company
Plus Oman-registration enums (document types, rejection reasons, issuing authorities, template keys),
add-on package/payment types, installment types, and Montenegro bed/bath enums — see
app/Enums/** for the exhaustive set.
Enum
Backing
Cases
RoleEnums
int
SHOPPER=2, BROKER=3
VoyagerRoles
string
admin, user, broker, moderator, editor, financer, sales_manager, viewer, sales_man (STI global scopes)
AuthTokenAbilities
string
6 Sanctum abilities (access-shopper-api … access-sales-man-api)
OtpActionEnums
string
broker_register, shopper_register, shopper_login, pre_registration_broker
OtpChannelEnums
string
mail, phone
RegisterationMethod / BrokerRegisteredFrom
int
CRM=1, PORTAL=2
TimeRangeEnums
string
last_quarter, last_year
These map external CRM marketing source/medium option-set codes; near-duplicate integer lists per
market (read the files for exact codes):
Enum
Cases
Enum
Cases
EgyptCRMIntegratedSourcesEnums
42
OmanCRMIntegratedSourcesEnums
40
MonetengroCRMIntegratedSourcesEnums
13
EgyptCRMIntegratedMediumEnums
18
OmanCRMIntegratedMediumEnums
18
MonetengroCRMIntegratedMediumEnums
6
Per-market (Egypt / Oman / Montenegro) vocabularies for the sales-man lead/pipeline forms —
channels, lead sources, desired products, unit types/categories, feedback, disqualification reasons,
objections/concerns, and pipeline phases. Notable: ChannelEnums (31), LeadSourceEnums (25),
OmanLeadSourceEnums (32), UnitTypeEnums (33), EgyptDesiredProductEnums (23). All are int-backed
except LeadSaleMainSourceEnums (string: Direct, Indirect, Referral).
295 migration files, 92 Schema::create — one per table, chronological (2022 catalog core →
2026). The renamed from notes above (lead_requests→user_requests,
..._sale_shares→..._sale_splits, ..._contract_templates→..._templates) come from that
timeline; the migration files are write-once (never edit an existing one — add an additive one).