Multi-Tenant Branch & Multi-Level Approval Engine
Role-Based Access Control (RBAC) & Step-by-Step Approval Pipeline
Pemisahan data operasional antar cabang regional ISP berbasis Role-Based Access Control (RBAC) & Scoped Tenant Guard serta pipeline persetujuan multi-level otomatis (Sales -> NOC Kelayakan -> Finance Margin -> Dispatch).
Diagram Alur Data & Arsitektur Sistem
Visual InteraktifArsitektur Isolasi Cabang RBAC & Pipeline Persetujuan Multi-Level
Isolasi data berbasis Role-Based Access Control (RBAC) dan workflow persetujuan bertingkat
Regional Branch
Sales / CS Cabang
RBAC Guard
Verify Roles & Branch Scope
PostgreSQL Engine
Scoped Branch Queries
Workflow Engine
Step: NOC -> Finance
HQ Dispatch
Ready for Field Execution
Problem & Latar Belakang Kebutuhan
ISP dengan puluhan kantor cabang regional (misal: Cabang Jakarta Selatan, Bandung, Surabaya) membutuhkan isolasi data ketat agar staf cabang tidak dapat mengakses data pelanggan atau pendapatan cabang lain, sekaligus memerlukan alur persetujuan terpadu untuk permintaan diskon paket khusus atau perubahan rute kabel FO utama.
Implementasi Branch RBAC Guard & Workflow State Machine di NestJS
Setiap request HTTP NestJS diverifikasi hak aksesnya melalui RBAC Guard dan Branch Scoped Interceptor. NestJS mengevaluasi peran pengguna (Superadmin, Branch Manager, NOC Engineer, Finance Lead) dan mengunci query database ke branch_id yang berwenang. Approval engine mengimplementasikan state machine terdistribusi di mana setiap transisi status memerlukan hak akses peran pengguna (RBAC) yang terverifikasi.
Aspek Role-Based Access Control (RBAC) & Branch Tenant Isolation
Tabel-tabel inti menerapkan constraint foreign key branch_id terindeks dengan scoped repository wrapper di NestJS: query otomatis mengikat branch_id sesuai klaim token JWT pengguna, kecuali bagi peran Superadmin HQ yang memiliki hak akses global lintas cabang.
Keamanan, Idempotensi & Kepatuhan SLA
Mencegah cross-branch data breach secara mendasar melalui verifikasi token JWT bertingkat yang mengikat klaim branch_id dan hierarki peran (Branch Manager, Area Lead, HQ Superadmin).
// Branch RBAC Guard & Multi-Level Approval Engine di NestJS
@Injectable()
export class BranchRbacGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<string[]>('roles', [
context.getHandler(),
context.getClass(),
]);
const request = context.switchToHttp().getRequest();
const user = request.user;
if (!user || !user.branchId) {
throw new UnauthorizedException('Konteks cabang dan kredensial pengguna tidak valid');
}
// Superadmin HQ memiliki akses bypass lintas cabang
if (user.role === 'superadmin') return true;
// Validasi izin peran (RBAC)
if (requiredRoles && !requiredRoles.includes(user.role)) {
throw new ForbiddenException('Akses ditolak: peran Anda tidak berwenang mengeksekusi aksi cabang ini');
}
return true;
}
}
@Injectable()
export class OrderApprovalWorkflowService {
constructor(@InjectRepository(ServiceOrder) private orderRepo: Repository<ServiceOrder>) {}
async advanceApprovalStep(orderId: string, user: AuthenticatedUser, step: 'NOC' | 'FINANCE'): Promise<ServiceOrder> {
const order = await this.orderRepo.findOneBy({ id: orderId });
if (!order) throw new NotFoundException('SPK Order tidak ditemukan');
if (step === 'NOC') {
if (user.role !== 'noc_engineer') throw new ForbiddenException('Hanya NOC yang berwenang approve kelayakan fiber');
order.nocApprovedAt = new Date();
order.status = 'NOC_VERIFIED';
} else if (step === 'FINANCE') {
if (user.role !== 'finance_lead') throw new ForbiddenException('Hanya Finance yang berwenang approve diskon');
order.financeApprovedAt = new Date();
order.status = 'READY_FOR_DISPATCH';
}
return this.orderRepo.save(order);
}
}Live Simulator & Execution Sandbox
PostGIS GiST R-Tree ST_DWithin query executed in 3.8ms. Matched ODP-FATMAWATI-42 (84.2m).
Estimated optical attenuation: -17.4 dBm. Port 4 of 8 available. Redis lock acquired with 24h TTL.
HMAC-SHA256 verified. Redis Redlock acquired. Invoice INV-2026-0982 settled with zero ledger variance.
ST_DWithin R-Tree matched ODP in 4.1ms (dist: 84.2m). Optical loss -17.4 dBm. Splitter port locked with 24h Redis TTL.
Eksplorasi Fitur Terkait Lainnya
Lihat Semua Fitur →PostGIS Spatial R-Tree & ODP Fiber Allocation
Validasi geospasial real-time titik koordinat pelanggan, kalkulasi jarak kabel drop optik, estimasi degradasi redaman (dBm), dan auto-lock port splitter ODP tanpa full-table scan.
Sales Order SPK & Automated Provisioning Lifecycle
Otomasi penerbitan Surat Perintah Kerja (SPK) pasang baru pelanggan, validasi KTP/NIK, reservasi port ODP selama 24 jam, dan pembuatan akun PPPoE/RADIUS otomatis di NestJS.
Multi-Gateway Webhook & Double-Entry Reconcile
Pengolahan webhook multi-gateway (Midtrans, Xendit, Bank Direct VA) dengan transactional outbox pattern dan double-entry ledger untuk rekonsiliasi bebas selisih.
SLA Ticketing & CS Incident Assignment Management
Sistem manajemen tiket gangguan pelanggan berbasis web portal yang diinput oleh tim Customer Service (CS), dikelompokkan berdasarkan kategori insiden, lalu di-assign ke tim teknis terkait dengan pelacakan batas waktu resolusi SLA.