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)
);