Lewati ke konten utama

BAB 65. MULTI-TENANT READINESS

65.1 Tujuan

Mempersiapkan TemuBelajar agar setiap sekolah bertindak sebagai tenant independen yang tidak dapat mengakses data tenant lain, sekaligus memungkinkan konfigurasi berbeda antar tenant.


65.2 Hierarki Tenant Context

Setiap request pengguna memiliki konteks berlapis:

flowchart TD
U["👤 User"] --> SCH["🏫 School (Tenant)"]
SCH --> AY["📅 Academic Year"]
AY --> CLS["🎓 Classroom"]
CLS --> PERM["🔑 Role & Permission"]
PERM --> DATA["📊 Data Access"]

style SCH fill:#4f63d2,color:#fff
style PERM fill:#7c3aed,color:#fff

65.3 TenantMiddleware

// app/Http/Middleware/TenantMiddleware.php

class TenantMiddleware
{
public function handle(Request $request, Closure $next): Response
{
$user = auth()->user();
$school = $user->school;

// 1. Resolve tenant
if (!$school) {
abort(403, 'Tenant tidak ditemukan.');
}

// 2. Validate tenant aktif
if (!$school->is_active) {
abort(403, 'Tenant tidak aktif.');
}

// 3. Set prefix untuk cache agar tidak tabrakan antar tenant
Cache::setPrefix("school_{$school->id}_");

// 4. Set prefix untuk storage path
Storage::setPrefix("schools/{$school->id}/");

// 5. Inject tenant ke container
app()->instance('tenant', $school);
app()->instance('tenant_id', $school->id);

return $next($request);
}
}

65.4 Scope Isolasi per Tenant

KomponenIsolasiMekanisme
DataPer school_idGlobal Scope di Eloquent
CachePer school_{id}_ prefixCache prefix per tenant
QueuePer school_{id} channelQueue channel naming
NotificationPer user + schoolFCM topic per school
ReportPer school exportFiltered query + path
AnalyticsPer school dashboardQuery scoped by school
File Storageschools/{id}/ pathStorage prefix per tenant

65.5 Tenant Scope pada Semua Model Utama

// Semua model ini otomatis terisolasi per tenant

students → school_id (HasSchool trait)
teachers → school_id (HasSchool trait)
requests → school_id (HasSchool trait)
bookings → school_id (HasSchool trait)
meetings → school_id (HasSchool trait)
ratings → school_id (HasSchool trait)
chat_rooms → school_id (HasSchool trait)
leaderboards → school_id (HasSchool trait)
notifications → school_id (HasSchool trait)
audit_logs → school_id (HasSchool trait)

65.6 Konfigurasi per Tenant

// app/Modules/Schools/Models/School.php

class School extends Model
{
protected $casts = [
'settings' => 'array',
];

// Contoh settings per tenant
// {
// "max_active_requests": 3,
// "matching_radius_meters": 100,
// "allow_cross_classroom": true,
// "notification_enabled": true,
// "leaderboard_public": false,
// "rating_anonymous": false
// }
}

65.7 Roadmap Enterprise Tenant

Untuk kebutuhan enterprise (dinas pendidikan, yayasan besar):

FiturKeterangan
Dedicated DatabaseDatabase terpisah per tenant
Custom BrandingLogo, warna, nama app per sekolah
Custom Domainsmkn1.temubelajar.id
Tenant AnalyticsDashboard analitik eksklusif
Tenant BillingSistem berlangganan per sekolah
SLA GuaranteeJaminan uptime per tenant