Skip to content

Data Model

User ──M:N──▶ App ──1:N──▶ StoreListing
│ │
│ └──▶ StoreListingChange
├──1:N──▶ AppVersion ──1:N──▶ AppMetric
├──N:1──▶ Publisher
├──N:1──▶ StoreCategory
├──1:1──▶ SyncStatus
└──1:N──▶ AppCompetitor ──▶ App (competitor)
ChartSnapshot ──1:N──▶ ChartEntry ──▶ App
Country (reference table — internal `zz` "Global" sentinel is filtered out in the API)

The central entity. Each record represents a unique app on a specific platform.

ColumnTypeDescription
idbigintPrimary key
platformtinyintInt-backed enum: 1 (iOS) or 2 (Android). Serialized as a slug (ios / android) in all JSON responses.
external_idstringStore ID (e.g. com.example.app or 123456789)
publisher_idFKLink to the publishers table
category_idFKLink to the store_categories table
display_namestringCached app name (from the default locale)
icon_urltextCached icon URL
origin_country_codechar(2)Country where the app was first found (FK countries.code)
supported_localesjsonArray of language codes the app supports
original_release_datedateOriginal release date
is_freebooleanFree or paid
discovered_fromtinyintHow the app was discovered (enum: search, trending, publisher, etc.)
discovered_atdatetimeFirst discovery time
last_synced_atdatetimeTime of the last full sync
is_availablebooleanWhether the app is still reachable in at least one store (per-country availability lives in app_metrics.is_available)

Uniqueness constraint: (platform, external_id)

Per-locale store listing data. One record per app per version per locale.

ColumnTypeDescription
app_idFKLink to the apps table
version_idFKLink to the app_versions table (nullable)
localevarchar(10)BCP-47 locale code (e.g. en-US, tr)
titlestringApp title in this locale
subtitlestringApp subtitle (iOS only)
promotional_texttext, nullableiOS promotional text (NULL on Android)
descriptiontextFull description
whats_newtextRelease notes
screenshotsjsonArray of screenshot URLs
icon_urlstringIcon URL
video_urlstringPreview video URL
pricedecimalPrice in local currency
currencystringCurrency code
fetched_atdatetimeWhen this listing was fetched
checksumstringHash used for change detection

Uniqueness constraint: (app_id, version_id, locale)

Note: This table does not have an is_available column. If a locale is not available in a given store, that row is simply not written; per-country availability is kept in app_metrics.is_available.

Version history for each app.

ColumnTypeDescription
app_idFKLink to the apps table
versionstringVersion string (e.g. 2.1.0)
release_datedateRelease date
whats_newtextRelease notes
file_size_bytesbigintApp file size

Uniqueness constraint: (app_id, version)

Daily metric snapshot per country + app. The source of truth for cross-store comparison and per-country availability.

ColumnTypeDescription
app_idFKLink to the apps table
version_idFKLink to the app_versions table (nullable)
country_codechar(2)FK countries.code. For Android, rating is global so the zz “Global” sentinel country is used
datedateSnapshot date
ratingdecimal(3,2)Average rating (e.g. 4.56)
rating_countuintTotal rating count
rating_breakdownjsonPer-star counts {1: 100, 2: 50, ...}
rating_deltaintChange in rating_count since the previous snapshot
pricedecimal, nullableNULL = unknown, 0 = confirmed free
installs_rangestringInstall range (Android only, e.g. 10M+)
file_size_bytesbigintFile size on this date
is_availablebooleanWhether the app is present on the storefront for this country+date

Uniqueness constraint: (app_id, country_code, date)

Tracks detected changes in store listings.

ColumnTypeDescription
app_idFKLink to the apps table
version_idFKLink to the app_versions table (nullable)
localevarchar(10)BCP-47 locale code
field_changedstringtitle, subtitle, promotional_text, description, whats_new, screenshots, locale_added, locale_removed
old_valuetextPrevious value
new_valuetextNew value
detected_atdatetimeWhen the change was detected

Tracks the state of AppSyncer pipeline runs. One record per app.

ColumnTypeDescription
app_idFKLink to the apps table (unique)
statusstringpending, running, succeeded, failed, reconciling
current_stepstringLast phase that ran (identity, listings, metrics, finalize, reconciling)
progress_doneintItems completed during the run
progress_totalintItems planned
failed_itemsjsonItems eligible for retry (with a reason tag)
error_messagetext, nullableLast error message
job_idstring, nullableLaravel queue job UUID associated with the run
next_retry_atdatetime, nullableScheduled time for ReconcileFailedItemsJob
ColumnTypeDescription
namestringPublisher/developer name
external_idstringStore-specific developer ID
platformtinyintInt-backed enum (1 iOS / 2 Android), serialized as slug in JSON
urlstringPublisher store URL

Seeded from App Store and Google Play category listings.

ColumnTypeDescription
external_idstringStore-specific category ID (nullable — NULL marks the “All” sentinel record used for generic/uncategorized charts)
namestringCategory name
slugstringURL-friendly name
platformtinyintInt-backed enum (1 iOS / 2 Android), serialized as slug in JSON
typestringapp, game, or magazine
parent_idFKSelf-reference for sub-categories
priorityintDisplay ordering

Reference table of supported countries with per-platform language configuration.

ColumnTypeDescription
codechar(2)ISO country code (primary key). zz is the internal “Global” sentinel — the /countries response filters it out
namestringCountry name
emojistringFlag emoji
is_active_iosbooleanActive for iOS operations
is_active_androidbooleanActive for Android operations
ios_languagesjsonSupported iOS language codes
android_languagesjsonSupported Android language codes

Daily chart snapshots.

ColumnTypeDescription
platformtinyintInt-backed enum (1 iOS / 2 Android), serialized as slug in JSON
collectionenumtop_free, top_paid, top_grossing
category_idFKStore category (NOT NULL; general charts point at the per-platform “All” sentinel record — iOS id=1, Android id=43)
country_codechar(2)FK countries.code
snapshot_datedateChart date

Uniqueness constraint: (platform, collection, country_code, category_id, snapshot_date)

Individual app rankings within a chart.

ColumnTypeDescription
trending_chart_idFKLink to the trending_charts table
ranksmallintRank in the chart (1-200)
app_idFKLink to the apps table
pricedecimalApp price at snapshot time
currencystringCurrency code

Many-to-many relationship between users and tracked apps.

ColumnTypeDescription
user_idFKLink to the users table
app_idFKLink to the apps table

User-defined competitor relationships between apps.

ColumnTypeDescription
user_idFKLink to the users table
app_idFKPrimary app
competitor_app_idFKCompetitor app
relationshipstringRelationship type (default: direct)