11 - Architecture Decisions (ADR Ringkas)
Dokumen ini menyimpan keputusan arsitektur penting agar tidak hilang saat refactor berikutnya.ADR-001: Context Split (Central vs Tenant vs Shared)#
Pisahkan codebase berdasarkan context:Central untuk auth global, tenant registry, billing platform/public.
Tenant untuk runtime tenant-scoped.
Shared untuk reusable logic lintas context.
navigasi file lebih jelas.
onboarding dev lebih cepat.
risiko mixing responsibility berkurang.
ADR-002: Auth Identity Tetap Central#
User identity, token issuance, refresh token, session auth core tetap di central DB.
satu sumber identitas global.
konsisten untuk multi-tenant login flow.
endpoint auth tetap di central route.
tenant context dipilih setelah login via select-tenant.
ADR-003: Authz Resolver Dual Context#
AuthorizationResolver resolve authz dari:tenant RBAC table saat user ada di tenant context.
central RBAC table untuk platform admin.
tenant bisa punya role/permission berbeda per SOP tenant.
platform admin tetap independen.
GET /auth/me memuat authz.roles dan authz.permissions kontekstual.
ADR-004: Tenant Model Connection via Trait#
Model tenant menggunakan trait HasTenantClusterConnection.
Resolver koneksi otomatis lewat TenantClusterResolver::resolveConnectionForCurrentTenant().
penggunaan Eloquent tetap natural (Model::query()).
mengurangi boilerplate resolve connection di tiap service/controller.
dev cukup memastikan middleware tenant context aktif.
ADR-005: Tenant Context Middleware as Source of Runtime Context#
SetTenantContext jadi sumber context runtime tenant/user.
ValidateTenantToken enforce tenant token integrity.
konsisten untuk authz, RLS, dan query isolation.
route tenant wajib middleware stack tenant.
ADR-006: RLS-Driven Isolation#
Set postgres session config app.current_tenant_id dan app.current_user_id di central + cluster tenant.
RLS policy menjadi garis pertahanan utama isolasi data.
menurunkan risiko kebocoran karena query lupa filter tenant.
explicit filter tenant di query tidak selalu wajib, tapi tetap boleh untuk clarity.
ADR-007: Event Discovery via bootstrap/app.php#
Listener diregister lewat event discovery:withEvents(discover: [app/Listeners])
kurangi registrasi listener manual yang mudah drift.
listener baru cukup ditempatkan di folder app/Listeners sesuai namespace.
ADR-008: Provisioning Default Data via Domain Event#
provisioning default subscription dan taxonomy dijalankan via listener saat TenantCreated.
pisahkan orchestration provisioning dari controller CRUD runtime.
onboarding tenant konsisten.
controller tenant master data tetap fokus ke CRUD lokal tenant.
ADR-009: Route Composition by Context#
api-v1.php hanya include central.php dan tenant.php.
detail route dipecah per file domain context.
maintainability route jangka panjang.
perubahan endpoint harus dilakukan di file context yang tepat.
ADR-010: API Envelope Standardized#
semua API response memakai ApiResponse envelope standar.
observability (request_id) konsisten.
controller wajib gunakan helper trait/ApiResponse.
ADR-011: Tenant Provisioning Centralized via Orchestrator#
semua provisioning tenant dijalankan lewat TenantProvisioningOrchestrator.
daftar provisioner berasal dari config/tenancy.php (provisioning.provisioners).
listener provisioning dijalankan asynchronous dan afterCommit agar tidak blocking register flow.
mencegah duplikasi path provisioning antar service/listener.
memudahkan scale provisioning per domain (taxonomy, uom, color, dst) dengan pola seragam.
memastikan transaksi register tenant selesai commit sebelum write ke tenant cluster.
command re-run standar: tenant:provision.
onboarding lebih stabil untuk proses berat.
extension point provisioning terdokumentasi dan testable.
Decision Dependency Map#
Class and File References#
app/Http/Controllers/Api/V1/Central/Auth/MeController.php
app/Services/Central/Auth/AuthorizationResolver.php
app/Traits/HasTenantClusterConnection.php
app/Support/Tenancy/TenantClusterResolver.php
app/Http/Middleware/Tenant/Context/SetTenantContext.php
app/Http/Middleware/Tenant/Context/ValidateTenantToken.php
app/Http/Middleware/Tenant/Context/RequireTenantContext.php
Event discovery + listeners: app/Services/Central/Tenancy/Provisioning/TenantProvisioningOrchestrator.php
app/Services/Central/Tenancy/Provisioning/TenantProvisioner.php
app/Console/Commands/ProvisionTenantCommand.php
Diubah pada 2026-03-03 22:25:30