Project: Okul Database · Hub: Okul Database — Guides

Data Scientist Quick Start Guide

Everything you need to start querying the Okul.com.tr database. Read this first.


What Is This Platform?

Okul.com.tr is Turkey’s K-12 school directory and B2B marketplace. Two channels:

ChannelWhoWhat They Do
D2CParents and students (users table)Search for schools, submit inquiry forms (leads)
B2BSchool management firms (customers table)Purchase product subscriptions, manage school profiles

The same database serves both. Key distinction: users.customer_id IS NOT NULL = the user is a B2B portal member.


The 7 Tables You’ll Use Most

TableWhyKey Filter
school_filtersSchool analytics — 100+ cols, no join neededdeleted_at IS NULL
leadsLead pipeline, conversion funneldeleted_at IS NULL AND (is_test=0 OR is_test IS NULL)
schoolsCore entity when you need the source of truthdeleted_at IS NULL AND status='1'
customer_agreementsRevenue, contractsdeleted_at IS NULL AND status='active'
paymentsFinancial transactionsdeleted_at IS NULL AND status='success' AND paid_at IS NOT NULL
usersUser demographics and activitydeleted_at IS NULL AND is_active='1'
school_interactionsCRM activity logdeleted_at IS NULL AND is_latest=1

5 Rules That Will Save You

Rule 1: ALWAYS filter soft deletes

WHERE deleted_at IS NULL

Almost every table has this column. Missing it means silently including deleted records.

Rule 2: Use school_filters, not raw schools

-- BAD: joining 10 tables for basic school attributes
SELECT s.name, st.type, l.name as city, p.name as product ...
FROM schools s JOIN schools_types st ... JOIN locations l ... JOIN products p ...
 
-- GOOD: everything already there
SELECT name, school_type_name, city_name, product_name
FROM school_filters WHERE deleted_at IS NULL

Rule 3: Exclude test leads

WHERE is_test = 0 OR is_test IS NULL

Test leads inflate all lead counts. Always exclude.

Rule 4: Know what “converted” means

-- A lead is enrolled when:
stage_id = 11    -- "Kayıt" (Enrolled)
OR stage_id = 38 -- "Manuel Kayıt" (Manual Enrollment)
OR school_answered_deal_status = 2453  -- "Kayıt gerçekleşti"

See ref-lead-stages for all stage meanings.

Rule 5: Revenue = status='success' payments only

WHERE status = 'success' AND paid_at IS NOT NULL

There are 10 payment status values. Only success = actual money collected.


Domain Map — Where to Look

QuestionTableReference
How many active schools?school_filters WHERE is_active=1table-school-filters
Which schools are paying customers?school_filters WHERE is_customer=1table-school-filters
Lead count / conversion rate?leadstable-leads + ref-lead-stages
Monthly revenue?payments WHERE status='success'table-payments
Active contracts?customer_agreements WHERE status='active'table-customer-agreements
User registrations?userstable-users
School engagement over time?school_daily_logstable-school-daily-logs
CRM activity?school_interactions WHERE is_latest=1table-school-interactions
Why did deals fail?leads.deal_cause_of_reasonref-interaction-values
School rating/sentiment?school_commentsdomain-schools
Geographic breakdown?school_filters.city_name/county_nameref-locations
School type breakdown?school_filters.school_type_idref-school-types
Private vs public schools?school_filters.sector_id (1=public, 2=private)ref-sectors
What facilities does a school have?school_facilities JOIN facilitiesref-services-facilities
University programs?universitiesfacultiesfaculty_programsdomain-content-education
Turkish province names?school_filters.city_name (no join needed)ref-locations
What does config ID 1 mean?configs WHERE type=? AND item_id=1ref-configs

Turkey-Specific Context

TermMeaning
Devlet (sector_id=1)Public / state-funded school
Özel (sector_id=2)Private school
Anaokulu (school_type_id=1)Kindergarten, ages 3-6
İlkokul (school_type_id=2)Primary school, grades 1-4
Ortaokul (school_type_id=3)Middle school, grades 5-8
Lise (school_type_id=4)High school, grades 9-12
YÖKYükseköğretim Kurulu — Turkish higher education authority
IYSİleti Yönetim Sistemi — Turkey’s email/SMS consent registry (like GDPR)
KVKKTurkish GDPR equivalent (users.kvkk_accepted_at)
ERPLOGO ERP — accounting system used by B2B customers
PipedriveExternal CRM synced to pipedrive_* tables; has lag
PYInternal project management system; py_profile_point = profile quality score

JSON Columns — Handle With Care

TableColumnContents
customer_agreementsproductsJSON array of purchased products
customer_agreementsproduct_argeR&D product details
customer_agreementsmissing_inputsList of missing contract fields
notificationsoptionsNotification configuration
payment_transactionsgateway_responseRaw iyzico/bank API response
pipedrive_dealsdetailsRaw Pipedrive deal JSON
-- Parse JSON (MySQL 5.7+ required)
SELECT JSON_UNQUOTE(JSON_EXTRACT(products, '$[0].name')) FROM customer_agreements;

Timestamp Patterns

Most tables follow this pattern:

ColumnMeaning
created_atRecord creation
updated_atLast modification
deleted_atSoft delete timestamp (NULL = not deleted)
paid_atPayment completion (NULL = not yet paid)
customer_viewed_atWhen B2B customer first viewed a lead (NULL = unseen)
approved_atApproval timestamp (comments, agreements)

Common Gotchas Summary

Full list: guide-common-gotchas

GotchaFix
Forgetting deleted_at IS NULLAdd to every query
Using schools with 20 joinsUse school_filters instead
Including test leadsAdd is_test = 0 OR is_test IS NULL
Treating Pipedrive tables as real-timeThey have sync lag; use leads for live data
source_action being NULL before April 2026Filter by created_at >= '2026-04-02' when needed
configs FK resolutionJoin on type + item_id, not just item_id