Ana içeriğe geç

Akedemi DB

Akademi Eğitim Platformu Akedemi DB Dökümanı

academy

CREATE TABLE academy (
academyId INT AUTO_INCREMENT PRIMARY KEY,
companyId INT NULL,
name VARCHAR(255) NOT NULL,
slug VARCHAR(100) NOT NULL UNIQUE,
shortDescription TEXT,
aboutDescription TEXT,
logoUrl VARCHAR(512),
bannerUrl VARCHAR(512), -- landing hero
slogan VARCHAR(255),
status ENUM('draft','published','archived') DEFAULT 'draft',
settings TEXT, -- Diğer Ayarlar olursa
customCss TEXT, -- Custom CSS için
customText TEXT, -- Metinsel düzenlemeler için
createdBy BIGINT NOT NULL,
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NULL, -- soft delete

INDEX idx_slug (slug),
INDEX idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

academy_domains

CREATE TABLE academy_domains (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
academy_id BIGINT NOT NULL,
domain VARCHAR(255) NOT NULL UNIQUE,
is_primary BOOLEAN DEFAULT FALSE,

verification_method ENUM('cname','txt') DEFAULT 'cname',
verification_value VARCHAR(255), -- TXT kaydı değeri veya beklenen CNAME
cname_target VARCHAR(255), -- academy-123.ucca.ai
verified BOOLEAN DEFAULT FALSE,
ssl_status ENUM('pending','active','failed') DEFAULT 'pending',
last_verified_at TIMESTAMP NULL,

created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

FOREIGN KEY (academy_id) REFERENCES academies(id) ON DELETE CASCADE,
INDEX idx_domain (domain),
INDEX idx_verified (verified)
);

academy_socialnetwork

CREATE TABLE `academy_networks`(
`academyId` INT(11) NOT NULL,
`network` VARCHAR(50) NOT NULL DEFAULT '',
`address` VARCHAR(255) DEFAULT '',
`orderIndex` INT(11) DEFAULT 0,
`createdAt` INT(11) DEFAULT -1,
`createdBy` INT(11) DEFAULT -1,
`updatedAt` INT(11) DEFAULT -1,
`updatedBy` INT(11) DEFAULT -1,
PRIMARY KEY (`academyId`, `network`)
);

academy_course_category

CREATE TABLE `academy_course_category`(
`categoryId` INT(11) NOT NULL,
`academyId` INT(11) NOT NULL,
`parent` INT(11) DEFAULT -1,
`title` VARCHAR(255) DEFAULT '',
`slug` VARCHAR(255) DEFAULT '',
`description` VARCHAR(500) DEFAULT '',
`thumbnail` VARCHAR(255) DEFAULT '',
`orderIndex` INT(11) DEFAULT -1,
`createdAt` INT(11) DEFAULT 0,
`createdBy` INT(11) DEFAULT 0,
`updatedAt` INT(11) DEFAULT 0,
`updatedBy` INT(11) DEFAULT 0,
PRIMARY KEY (`categoryId`, `academyId`)
);

academy_course

CREATE TABLE `academy_course` (
`academyId` int(11) NOT NULL,
`courseId` int(11) NOT NULL,
`categoryId` int(11) DEFAULT NULL,
`tags` varchar(500) DEFAULT '[]',
PRIMARY KEY (`academyId`,`courseId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

academy_seo

  • Meta title/description, OpenGraph tags (sosyal medya paylaşımı için).
CREATE TABLE academy_seo_settings (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
academy_id BIGINT NOT NULL,

-- Ana meta bilgiler (her landing page için olmazsa olmaz)
meta_title VARCHAR(120) NULL, -- Google genellikle 60-70 karakter gösterir
meta_description VARCHAR(320) NULL, -- ~155-160 karakter ideal
meta_keywords VARCHAR(255) NULL, -- artık çok etkili değil ama bazı sistemler hâlâ kullanıyor

-- Open Graph & Twitter Cards (sosyal medya paylaşımı)
og_title VARCHAR(120) NULL,
og_description VARCHAR(320) NULL,
og_image_url VARCHAR(512) NULL,
og_image_alt VARCHAR(255) NULL,
og_type VARCHAR(50) DEFAULT 'website', -- website, article, video.movie vs.

twitter_card_type ENUM('summary','summary_large_image','app','player') DEFAULT 'summary_large_image',
twitter_title VARCHAR(120) NULL,
twitter_description VARCHAR(320) NULL,
twitter_image_url VARCHAR(512) NULL,

-- Robots & indexleme kontrolü
robots_noindex BOOLEAN DEFAULT FALSE,
robots_nofollow BOOLEAN DEFAULT FALSE,
canonical_url VARCHAR(512) NULL, -- custom domain varsa buraya yazılır

-- Structured Data (Schema.org) – JSON-LD olarak üretilecek
schema_type ENUM('Organization','WebSite','WebPage','Course','EducationalOrganization') DEFAULT 'WebSite',
schema_json JSON NULL, -- tam JSON-LD payload'ı (Course için @context, @type:Course vb.)

-- Diğer ileri seviye ayarlar
hreflang_settings JSON NULL, -- çok dilli destek için { "tr": "https://...", "en": "https://..." }
sitemap_priority DECIMAL(3,1) DEFAULT 0.7, -- 0.0 - 1.0
sitemap_changefreq ENUM('always','hourly','daily','weekly','monthly','yearly','never') DEFAULT 'weekly',

-- Yönetim & tarihçe
last_updated_by BIGINT NULL,
last_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

-- Constraints
FOREIGN KEY (academy_id) REFERENCES academies(id) ON DELETE CASCADE,
UNIQUE KEY uk_academy_seo (academy_id),

-- Performans için sık kullanılan alanlara index
INDEX idx_noindex (robots_noindex)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

academy_landing_pages !!! Burası önemli eğitim için footerda gösterecek sayfaları buradan oluşturabiliriz.

Tasarıma göre detaylandıralacak

  • Hero section: Logo, banner (video background opsiyonel), slogan.
  • Kurs listesi: Card/grid view, filtre (tamamlanan/devam eden), arama.
  • Kayıt/ Giriş butonu: SSO ile entegre.
  • Hakkında bölümü: Akademi açıklaması, eğitmenler, başarı hikayeleri.
  • Footer: İletişim, gizlilik politikası.
  • Referance
  • Column Container + HTML
  • Testimotion
  • Event Managment
  • Pages

academy_access

  • Erişim Yöntemi
    • Sadece Davetliler () -> burada departman bazlı ayarlamalar yapılabilir. biraz daha detay düşünülebilir, bazı eğitimleri departman veya liste bazlı açılabilir, (Role Based Access Control RBAC)
    • Herkese Açık ()
    • Domain Kısıtlamalı (*.mobildev.com, gibi sadece o domainden gelenlere )
  • Erişim Onaylama (Onay Gerekli / Değil)

academy_invitation

  • 360 user tablosu kullanılabilir user için ya da consumer tarafı kullanılabilir
  • Davetiye Şablon / Sender Yönetimi
CREATE TABLE academy_invitations (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
academy_id BIGINT NOT NULL,
token VARCHAR(64) NOT NULL UNIQUE,
expires_at TIMESTAMP NOT NULL,
max_uses INT DEFAULT 1,
uses_count INT DEFAULT 0,
created_by BIGINT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

FOREIGN KEY (academy_id) REFERENCES academies(id) ON DELETE CASCADE
);

academy_security

-- Sistem hazır roller de olabilir (admin, learner, manager vs.)
CREATE TABLE academy_roles (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
academy_id BIGINT NOT NULL,
name VARCHAR(100) NOT NULL, -- 'sales_rep', 'manager', 'compliance_officer'
description TEXT,
is_system BOOLEAN DEFAULT FALSE, -- platformun default rolleri mi?
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

FOREIGN KEY (academy_id) REFERENCES academies(id) ON DELETE CASCADE,
UNIQUE KEY uk_academy_role_name (academy_id, name)
);


-- Departman / Grup / Team (kurumun kendi organizasyon yapısı)
CREATE TABLE academy_groups (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
academy_id BIGINT NOT NULL,
name VARCHAR(150) NOT NULL, -- 'Satış Ekibi', 'IT Departmanı', 'Yönetim'
description TEXT,
parent_id BIGINT NULL, -- hiyerarşik departmanlar için
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

FOREIGN KEY (academy_id) REFERENCES academies(id) ON DELETE CASCADE,
FOREIGN KEY (parent_id) REFERENCES academy_groups(id) ON DELETE SET NULL
);


-- Erişim Kuralı (hangi kaynaklara kim erişebilir)
-- Polymorphic-like: course bazlı veya academy-wide
CREATE TABLE academy_access_rules (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
academy_id BIGINT NOT NULL,

-- Hedef kaynak (ne korunuyor?)
resource_type ENUM('academy', 'course', 'module', 'category') NOT NULL,
resource_id BIGINT NULL, -- course.id, module.id vs. (NULL ise tüm akademi)

-- Kim erişebilir?
access_type ENUM('allow', 'deny') DEFAULT 'allow',
target_type ENUM('all', 'role', 'group', 'user') NOT NULL,
target_id BIGINT NULL, -- academy_roles.id, academy_groups.id, users.id

-- Ek koşullar (gelecek için)
conditions JSON NULL, -- {"min_grade": 80, "must_complete": ["kurs-a"]}

created_by BIGINT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

-- Bir resource için çakışan rule olmasın diye unique constraint
UNIQUE KEY uk_resource_rule (academy_id, resource_type, resource_id, target_type, target_id, access_type),

INDEX idx_resource (resource_type, resource_id)
);


-- Alt ikisi tek bir tabloda da birleştirilebilir !
CREATE TABLE academy_allowed_domains (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
academy_id BIGINT NOT NULL,
domain VARCHAR(255) NOT NULL, -- 'mobildev.com', 'example.org'
description VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

FOREIGN KEY (academy_id) REFERENCES academies(id) ON DELETE CASCADE,
UNIQUE KEY uk_academy_domain (academy_id, domain)
);

CREATE TABLE academy_allowed_emails (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
academy_id BIGINT NOT NULL,
email VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

FOREIGN KEY (academy_id) REFERENCES academies(id) ON DELETE CASCADE,
UNIQUE KEY uk_academy_email (academy_id, email)
);


-- Düzenleme vs işlemleri için
CREATE TABLE academy_user_roles (
user_id BIGINT NOT NULL,
academy_id BIGINT NOT NULL,
role_id BIGINT NOT NULL,
assigned_by BIGINT NULL,
assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

PRIMARY KEY (user_id, academy_id, role_id),
FOREIGN KEY (academy_id) REFERENCES academies(id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES academy_roles(id) ON DELETE CASCADE
);

-- Kullanıcının akademi içindeki grupları (departman/ekip)
CREATE TABLE academy_user_groups (
user_id BIGINT NOT NULL,
academy_id BIGINT NOT NULL,
group_id BIGINT NOT NULL,
joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

PRIMARY KEY (user_id, academy_id, group_id),
FOREIGN KEY (academy_id) REFERENCES academies(id) ON DELETE CASCADE,
FOREIGN KEY (group_id) REFERENCES academy_groups(id) ON DELETE CASCADE
);

-- IP Kısıtlamaları sadece yetki verilmiş ip adreslerinden içeriklere erişim sağlanabilmeli.
CREATE TABLE academy_ip_restrictions (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
academy_id BIGINT NOT NULL,
cidr VARCHAR(50) NOT NULL, -- 192.168.1.0/24
description VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

FOREIGN KEY (academy_id) REFERENCES academies(id) ON DELETE CASCADE,
UNIQUE KEY uk_academy_cidr (academy_id, cidr)
);

academy_course_permrequest

Eğer bir kullanıcı roller bazında eğitime izin verlmemişse kullanıcı bu kursa izin talebinde bulunabilir !

academy_analytic

datalayer eventleri araştırılması gerekiyor.

academy_contact

adres vs

academy_contact_inform

academy_faq

FAQ Modüler ayarlanmalı ve eğitim içerikleri, blog yazıları, event gibi içeriklerde de eklenebilir olmalı o yüzden ortak tabloya bağla !

!! academy_target_audiences

CREATE TABLE academy_target_audiences (
academy_id BIGINT NOT NULL,
target_type ENUM('all','department','role','group') NOT NULL,
target_id BIGINT NULL, -- departments.id, roles.id vs.
PRIMARY KEY (academy_id, target_type, target_id),
FOREIGN KEY (academy_id) REFERENCES academies(id) ON DELETE CASCADE
);

Events with Academy

Events ile ilişki kur !

academy_integrations

Burası biraz daha ilerisi için, SSO, Webhook gibi ayarlar için olabilir

CREATE TABLE academy_integrations (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
academy_id BIGINT NOT NULL,
integration_type VARCHAR(50) NOT NULL, -- sso_saml, webhook_completion, scorm_export...
config JSON NOT NULL, -- app tarafında hassas alanları encrypt edin
enabled BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

FOREIGN KEY (academy_id) REFERENCES academies(id) ON DELETE CASCADE,
CHECK (JSON_VALID(config))
);

Learning Path By Roles !

-- Learning Path (bir rol veya rol grubu için öğrenme yolculuğu)
CREATE TABLE academy_learning_paths (
pathId BIGINT AUTO_INCREMENT PRIMARY KEY,
academyId BIGINT NOT NULL,
name VARCHAR(255) NOT NULL, -- "Satış Temsilcisi Onboarding Path"
slug VARCHAR(150) NOT NULL,
description TEXT,

isActive BOOLEAN DEFAULT TRUE,
isMandatory BOOLEAN DEFAULT FALSE, -- Akademi genelinde zorunlu mu?
estimated_duration_days INT NULL, -- tahmini tamamlanma süresi

settings JSON NOT NULL DEFAULT (JSON_OBJECT()), -- { "auto_assign_on_role_add": true, "notify_hr_on_complete": true }

created_by BIGINT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

FOREIGN KEY (academy_id) REFERENCES academies(id) ON DELETE CASCADE,
UNIQUE KEY uk_academy_path_slug (academy_id, slug)
);

CREATE TABLE academy_learning_path_items (
itemId BIGINT AUTO_INCREMENT PRIMARY KEY,
pathId BIGINT NOT NULL,
academyId BIGINT NOT NULL,
courseId BIGINT NOT NULL,

orderIndex INT NOT NULL DEFAULT 0, -- sıralama (0,1,2,... paralel için aynı order olabilir)
isRequired BOOLEAN DEFAULT TRUE,
isParallelAllowed BOOLEAN DEFAULT FALSE, -- aynı seviyede başka kurslarla birlikte alınabilir mi?

-- Önkoşul kurs(lar) – bu kurs başlamadan önce tamamlanması gerekenler
prerequisites JSON NULL, -- ["course-slug-1", "course-slug-2"] veya course id array

-- Ek ayarlar
deadlineOffsetDays INT NULL, -- path başladıktan kaç gün sonra deadline?
settings JSON NULL, -- { "min_score": 75, "retry_allowed": true }

createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,


UNIQUE KEY uk_path_course (learning_path_id, course_id),
INDEX idx_path_order (learning_path_id, order_index)
);

CREATE TABLE academy_learning_path_roles (
pathId BIGINT NOT NULL,
roleId BIGINT NOT NULL, -- academy_roles.id
PRIMARY KEY (learning_path_id, role_id)
);

CREATE TABLE academy_learning_path_users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
userId BIGINT NOT NULL,
academyId BIGINT NOT NULL,
pathId BIGINT NOT NULL,

assignedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
assignedBy BIGINT NULL, -- admin/HR veya otomatik

status ENUM(
'active', 'completed', 'paused', 'expired', 'dropped'
) DEFAULT 'active',

progress_percentage DECIMAL(5,2) DEFAULT 0.00,
startedAt TIMESTAMP NULL,
completedAt TIMESTAMP NULL,
dueDate TIMESTAMP NULL, -- path için genel deadline

-- İlerleme detayları (JSON veya ayrı tablo)
item_progress JSON NULL, -- { "course-slug-1": { "status": "completed", "completed_at": "..."} }

UNIQUE KEY uk_user_path (user_id, academy_id, learning_path_id),
INDEX idx_user_status (user_id, status)
);