Tourify’s MySQL schema is managed entirely by Laravel migrations inDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/astrxnomo/tourify/llms.txt
Use this file to discover all available pages before exploring further.
backend/database/migrations/. Eleven application tables cover authentication, tourism content, user interactions, and push notifications. Three of those tables — images, favorites, and reviews — use polymorphic relationships so they can belong to multiple entity types without duplicating columns.
Entity reference
roles
roles
Seeded at deploy time. The default role for every new user registration is
Eloquent:
id = 2 (regular user).| Column | Type | Constraints |
|---|---|---|
id | bigint unsigned | PK, auto-increment |
name | varchar | unique |
label | varchar | — |
description | text | nullable |
created_at | timestamp | — |
updated_at | timestamp | — |
Role → hasMany(User::class)users
users
Created by the base Laravel migration. The
Eloquent:
push_token column is added by a separate migration (2026_05_04_add_push_token_to_users_table).| Column | Type | Constraints |
|---|---|---|
id | bigint unsigned | PK, auto-increment |
role_id | bigint unsigned | FK → roles.id, default 2, cascade delete |
name | varchar | — |
email | varchar | unique |
password | varchar | bcrypt-hashed |
remember_token | varchar(100) | nullable |
push_token | varchar | nullable |
created_at | timestamp | — |
updated_at | timestamp | — |
User → belongsTo(Role), hasMany(Favorite), hasMany(Review), hasMany(Notification), hasMany(EventRegistration)cities
cities
Top-level geographic entity. Deleting a city cascades to its places and events.
Eloquent:
| Column | Type | Constraints |
|---|---|---|
id | bigint unsigned | PK, auto-increment |
name | varchar | — |
description | text | nullable |
country | varchar | — |
created_at | timestamp | — |
updated_at | timestamp | — |
City → hasMany(Place), hasMany(Event), morphMany(Image, 'imageable')categories
categories
Used to classify places (e.g. museum, park, restaurant).
Eloquent:
| Column | Type | Constraints |
|---|---|---|
id | bigint unsigned | PK, auto-increment |
name | varchar | — |
description | text | nullable |
created_at | timestamp | — |
updated_at | timestamp | — |
Category → hasMany(Place)places
places
A point of interest within a city, classified by a category.
Eloquent:
| Column | Type | Constraints |
|---|---|---|
id | bigint unsigned | PK, auto-increment |
city_id | bigint unsigned | FK → cities.id, cascade delete |
category_id | bigint unsigned | FK → categories.id, cascade delete |
name | varchar | — |
description | text | — |
address | varchar | — |
latitude | decimal(10,7) | nullable |
longitude | decimal(10,7) | nullable |
created_at | timestamp | — |
updated_at | timestamp | — |
Place → belongsTo(City), belongsTo(Category), hasMany(Event), morphMany(Image, 'imageable'), morphMany(Review, 'reviewable'), morphMany(Favorite, 'favorable')events
events
A time-bound event anchored to a city. Optionally linked to a specific place — if the place is deleted the FK is set to
Eloquent:
null rather than cascading.| Column | Type | Constraints |
|---|---|---|
id | bigint unsigned | PK, auto-increment |
city_id | bigint unsigned | FK → cities.id, cascade delete |
place_id | bigint unsigned | FK → places.id, nullable, set null on delete |
title | varchar | — |
description | text | — |
date | timestamp | — |
created_at | timestamp | — |
updated_at | timestamp | — |
Event → belongsTo(City), belongsTo(Place), hasMany(EventRegistration), morphMany(Image, 'imageable'), morphMany(Review, 'reviewable'), morphMany(Favorite, 'favorable')event_registrations
event_registrations
Join table between users and events. A unique constraint on
Unique index:
(user_id, event_id) prevents duplicate registrations.| Column | Type | Constraints |
|---|---|---|
id | bigint unsigned | PK, auto-increment |
user_id | bigint unsigned | FK → users.id, cascade delete |
event_id | bigint unsigned | FK → events.id, cascade delete |
created_at | timestamp | — |
updated_at | timestamp | — |
(user_id, event_id)Eloquent: EventRegistration → belongsTo(User), belongsTo(Event)favorites — polymorphic
favorites — polymorphic
Stores any favorited item for a user. The
Unique index:
favorable_type / favorable_id pair resolves to a Place, Event, or City. A unique constraint prevents saving the same item twice.| Column | Type | Constraints |
|---|---|---|
id | bigint unsigned | PK, auto-increment |
user_id | bigint unsigned | FK → users.id, cascade delete |
favorable_type | varchar | Eloquent morph type (e.g. App\Models\Place) |
favorable_id | bigint unsigned | PK of the related model |
created_at | timestamp | — |
updated_at | timestamp | — |
(user_id, favorable_id, favorable_type)Eloquent: Favorite → belongsTo(User), morphTo('favorable')reviews — polymorphic
reviews — polymorphic
User ratings and optional comments attached to places or events.
Eloquent:
| Column | Type | Constraints |
|---|---|---|
id | bigint unsigned | PK, auto-increment |
user_id | bigint unsigned | FK → users.id, cascade delete |
reviewable_type | varchar | Eloquent morph type |
reviewable_id | bigint unsigned | PK of the related model |
rating | tinyint unsigned | 1–5 |
comment | text | nullable |
created_at | timestamp | — |
updated_at | timestamp | — |
Review → belongsTo(User), morphTo('reviewable')notifications
notifications
In-app notifications delivered to a specific user. Optionally linked to a source entity via nullable morphs (
Eloquent:
notifiable_type / notifiable_id). The is_read flag is a boolean cast.| Column | Type | Constraints |
|---|---|---|
id | bigint unsigned | PK, auto-increment |
user_id | bigint unsigned | FK → users.id, cascade delete |
notifiable_type | varchar | nullable morph type |
notifiable_id | bigint unsigned | nullable morph PK |
title | varchar | — |
message | text | nullable |
is_read | boolean | default false |
created_at | timestamp | — |
updated_at | timestamp | — |
Notification → belongsTo(User), morphTo('notifiable')images — polymorphic
images — polymorphic
One or more images attached to a city, place, or event via standard (non-nullable) morphs.
Eloquent:
| Column | Type | Constraints |
|---|---|---|
id | bigint unsigned | PK, auto-increment |
url | varchar | — |
imageable_type | varchar | Eloquent morph type |
imageable_id | bigint unsigned | PK of the related model |
created_at | timestamp | — |
updated_at | timestamp | — |
Image → morphTo('imageable')Polymorphic relationships
Laravel’s polymorphic relationships allow a single table to belong to multiple model types using a_type / _id column pair. Tourify uses three:
Images (imageable)
Table:
Columns:
Targets:
imagesColumns:
imageable_type, imageable_idTargets:
City, Place, EventFavorites (favorable)
Table:
Columns:
Targets:
favoritesColumns:
favorable_type, favorable_idTargets:
Place, Event, CityReviews (reviewable)
Table:
Columns:
Targets:
reviewsColumns:
reviewable_type, reviewable_idTargets:
Place, Event_type column stores the fully-qualified Eloquent class name (e.g. App\Models\Place). When loading a polymorphic relation, Laravel uses this string to determine which table to join.
Example — querying a place’s reviews:
Entity relationship diagram
Cascade delete behavior:
Deleting a City cascades to all its Places and Events.
Deleting a Place cascades to its Reviews, Favorites, and Images (via ON DELETE CASCADE on the polymorphic FKs at the application level), and sets
Deleting a User cascades to their Favorites, Reviews, Notifications, and EventRegistrations.
Deleting a City cascades to all its Places and Events.
Deleting a Place cascades to its Reviews, Favorites, and Images (via ON DELETE CASCADE on the polymorphic FKs at the application level), and sets
place_id to null on any associated Events rather than deleting them.Deleting a User cascades to their Favorites, Reviews, Notifications, and EventRegistrations.