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