BMI
BPRS Baktimakmur Indah
Enterprise System Architect & Deployment Tool
Environment: Production | aaPanel | MySQL
Revisi Struktur File (SaaS Standard)
Struktur berikut menghilangkan redundansi antara build artifacts dan source code. Dipisah secara ketat antara area Public (Frontend) dan Private (Backend/ML).
/www/wwwroot/ao.baktimakmur.com (Area Public - Frontend)
- public/ Static Assets
- src/
- App.js Entry Point
- components/
- pages/
- services/ API Calls
- utils/
- package.json
- .env.production
- nginx.conf Reverse Proxy
/www/wwwroot/app-collection/ao (Area Private - Backend API)
- app/ Core Logic
- api/
- dependencies.py
- auth.py
- loans.py
- monitoring.py
- predictions.py
- core/
- config.py
- security.py
- db.py
- models/ SQLAlchemy ORM
- customer.py
- loan.py
- user.py
- ml_model.py
- api/
- ml/ Machine Learning
- models/ .pkl files
- pipeline.py
- inference.py
- alembic/ DB Migrations
- main.py FastAPI Entry
- gunicorn_conf.py
- requirements.txt
- .env
/www/wwwroot/app-collection/ao/supervisor
- gunicorn_ao.conf
Script Database Produksi
Langkah 1: Hapus tabel lama (jika ada) & Buat Skema Baru.
Langkah 2: Insert Data Master (Cabang, Role, User).
Part A: Create Tables Schema
-- Engine & Charset
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS=0;
-- 1. Hapus Tabel (Drop & Clean) --
DROP TABLE IF EXISTS payments;
DROP TABLE IF EXISTS predictions;
DROP TABLE IF EXISTS notifications;
DROP TABLE IF EXISTS loans;
DROP TABLE IF EXISTS customers;
DROP TABLE IF EXISTS user_role;
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS roles;
DROP TABLE IF EXISTS branches;
DROP TABLE IF EXISTS ml_models;
DROP TABLE IF EXISTS datasets;
-- 2. Buat Tabel (Create Schema) --
-- Tabel Cabang
CREATE TABLE branches (
id INT AUTO_INCREMENT PRIMARY KEY,
code VARCHAR(10) NOT NULL UNIQUE,
name VARCHAR(100) NOT NULL,
city VARCHAR(100) NOT NULL,
is_active TINYINT(1) DEFAULT 1
) ENGINE=InnoDB;
-- Tabel Roles (Jabatan)
CREATE TABLE roles (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE,
description VARCHAR(255)
) ENGINE=InnoDB;
-- Tabel Users (AO/Admin)
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(100) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
full_name VARCHAR(150) NOT NULL,
email VARCHAR(150),
phone VARCHAR(30),
branch_id INT,
is_active TINYINT(1) DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (branch_id) REFERENCES branches(id)
) ENGINE=InnoDB;
-- Relasi User-Role
CREATE TABLE user_role (
user_id INT NOT NULL,
role_id INT NOT NULL,
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
) ENGINE=InnoDB;
-- Tabel Nasabah
CREATE TABLE customers (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
national_id VARCHAR(30) UNIQUE,
name VARCHAR(150) NOT NULL,
birth_date DATE,
phone VARCHAR(30),
email VARCHAR(150),
address TEXT,
business_type VARCHAR(100),
monthly_income DECIMAL(18,2),
assets_value DECIMAL(18,2),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
-- Tabel Pembiayaan (Loans)
CREATE TABLE loans (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
customer_id BIGINT NOT NULL,
branch_id INT NOT NULL,
product_name VARCHAR(100),
principal_amount DECIMAL(18,2) NOT NULL,
profit_rate DECIMAL(5,2) NOT NULL,
tenor_months INT NOT NULL,
start_date DATE NOT NULL,
end_date DATE,
collateral_desc TEXT,
status ENUM('active','settled','defaulted','cancelled') DEFAULT 'active',
credit_score DECIMAL(6,2),
default_probability DECIMAL(5,4),
segment ENUM('low','medium','high'),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (customer_id) REFERENCES customers(id),
FOREIGN KEY (branch_id) REFERENCES branches(id)
) ENGINE=InnoDB;
-- Tabel Pembayaran (Installments)
CREATE TABLE payments (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
loan_id BIGINT NOT NULL,
schedule_date DATE NOT NULL,
paid_date DATE,
amount_due DECIMAL(18,2) NOT NULL,
amount_paid DECIMAL(18,2) DEFAULT 0,
status ENUM('on_time','late','default') DEFAULT 'on_time',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (loan_id) REFERENCES loans(id)
) ENGINE=InnoDB;
-- Tabel Notifikasi
CREATE TABLE notifications (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
loan_id BIGINT NOT NULL,
type ENUM('late_alert','default_alert','general') NOT NULL,
message VARCHAR(255) NOT NULL,
sent_to VARCHAR(150),
sent_at TIMESTAMP NULL,
status ENUM('pending','sent','failed') DEFAULT 'pending',
FOREIGN KEY (loan_id) REFERENCES loans(id)
) ENGINE=InnoDB;
-- Tabel ML Model Metadata
CREATE TABLE ml_models (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
version VARCHAR(50),
description VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
-- Tabel Hasil Prediksi
CREATE TABLE predictions (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
model_id INT NOT NULL,
customer_id BIGINT,
loan_id BIGINT,
credit_score DECIMAL(6,2),
default_probability DECIMAL(5,4),
segment ENUM('low','medium','high'),
cashflow_next30 DECIMAL(18,2),
early_warning_score DECIMAL(6,2),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (model_id) REFERENCES ml_models(id),
FOREIGN KEY (customer_id) REFERENCES customers(id),
FOREIGN KEY (loan_id) REFERENCES loans(id)
) ENGINE=InnoDB;
-- Tabel Upload Dataset History
CREATE TABLE datasets (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
filename VARCHAR(200) NOT NULL,
stored_path VARCHAR(255) NOT NULL,
uploaded_by INT NOT NULL,
uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
rows_count INT,
FOREIGN KEY (uploaded_by) REFERENCES users(id)
) ENGINE=InnoDB;
SET FOREIGN_KEY_CHECKS=1;
Part B: Insert Master Data (Branches, Roles, Users)
-- SEED DATA: BRANCHES (5 Cabang)
INSERT INTO branches (code, name, city) VALUES
('KPO','Kantor Pusat Krian','Krian'),
('SPJJ','Cabang Sepanjang','Sepanjang'),
('SDA','Cabang Sidoarjo','Sidoarjo'),
('SBY','Cabang Surabaya','Surabaya'),
('MJK','Cabang Mojokerto','Mojokerto');
-- SEED DATA: ROLES
INSERT INTO roles (name, description) VALUES
('ADMIN','System Administrator'),
('DIRECTOR_MAIN','Direktur Utama'),
('DIRECTOR_RISK','Direktur Operasional & Risiko'),
('COMMISSIONER_MAIN','Komisaris Utama'),
('COMMISSIONER','Komisaris'),
('BRANCH_USER','User Cabang / AO');
-- SEED DATA: USERS
-- Catatan: Password di bawah adalah Placeholder Hash (Fake).
-- Aplikasi backend wajib memiliki endpoint untuk mengupdate password ini
-- atau generate hash baru saat first login.
-- Plaintext Reference: Admin@Baktimakmur#2026
INSERT INTO users (username, password_hash, full_name, email, phone, branch_id) VALUES
('admin', '$2b$12$PLACEHOLDER_HASH_UPDATE_ME', 'Super Admin', 'admin@baktimakmur.com', '0800000000', (SELECT id FROM branches WHERE code='KPO')),
('dirutama', '$2b$12$PLACEHOLDER_HASH_UPDATE_ME', 'Direktur Utama', 'dirutama@baktimakmur.com', '0811111111', (SELECT id FROM branches WHERE code='KPO')),
('dirrisk', '$2b$12$PLACEHOLDER_HASH_UPDATE_ME', 'Direktur Risiko', 'dirrisk@baktimakmur.com', '0812222222', (SELECT id FROM branches WHERE code='KPO')),
('komut', '$2b$12$PLACEHOLDER_HASH_UPDATE_ME', 'Komisaris Utama', 'komut@baktimakmur.com', '0813333333', (SELECT id FROM branches WHERE code='KPO')),
('komisaris', '$2b$12$PLACEHOLDER_HASH_UPDATE_ME', 'Komisaris', 'komisaris@baktimakmur.com', '0814444444', (SELECT id FROM branches WHERE code='KPO')),
('kpo_user', '$2b$12$PLACEHOLDER_HASH_UPDATE_ME', 'AO KPO', 'kpo@baktimakmur.com', '0815555555', (SELECT id FROM branches WHERE code='KPO')),
('spj_user', '$2b$12$PLACEHOLDER_HASH_UPDATE_ME', 'AO Sepanjang', 'spj@baktimakmur.com', '0816666666', (SELECT id FROM branches WHERE code='SPJJ')),
('sda_user', '$2b$12$PLACEHOLDER_HASH_UPDATE_ME', 'AO Sidoarjo', 'sda@baktimakmur.com', '0817777777', (SELECT id FROM branches WHERE code='SDA')),
('sby_user', '$2b$12$PLACEHOLDER_HASH_UPDATE_ME', 'AO Surabaya', 'sby@baktimakmur.com', '0818888888', (SELECT id FROM branches WHERE code='SBY')),
('mjk_user', '$2b$12$PLACEHOLDER_HASH_UPDATE_ME', 'AO Mojokerto', 'mjk@baktimakmur.com', '0819999999', (SELECT id FROM branches WHERE code='MJK'));
-- SEED DATA: USER_ROLE MAPPING
INSERT INTO user_role (user_id, role_id)
SELECT u.id, r.id FROM users u JOIN roles r ON r.name='ADMIN' WHERE u.username='admin';
INSERT INTO user_role (user_id, role_id)
SELECT u.id, r.id FROM users u JOIN roles r ON r.name='DIRECTOR_MAIN' WHERE u.username='dirutama';
INSERT INTO user_role (user_id, role_id)
SELECT u.id, r.id FROM users u JOIN roles r ON r.name='DIRECTOR_RISK' WHERE u.username='dirrisk';
INSERT INTO user_role (user_id, role_id)
SELECT u.id, r.id FROM users u JOIN roles r ON r.name='COMMISSIONER_MAIN' WHERE u.username='komut';
INSERT INTO user_role (user_id, role_id)
SELECT u.id, r.id FROM users u JOIN roles r ON r.name='COMMISSIONER' WHERE u.username='komisaris';
-- Semua User Cabang mendapat role BRANCH_USER
INSERT INTO user_role (user_id, role_id)
SELECT u.id, r.id FROM users u JOIN roles r ON r.name='BRANCH_USER'
WHERE u.username IN ('kpo_user','spj_user','sda_user','sby_user','mjk_user');
Diagram ERD (PlantUML Format)
Kode di bawah ini adalah representasi skema database dalam format teks PlantUML. Anda dapat menyalin kode ini ke dalam tool visualisasi PlantUML (seperti PlantText, IntelliJ IDEA Plugin, atau VS Code Extension) untuk menghasilkan gambar diagram yang rapi.
BPRS Database Schema (PlantUML)
@startuml !define table(x) entity x <{ -- } 'hide circle 'hide empty members skinparam rectangle { BackgroundColor< > #E3F2FD BorderColor< > #1976D2 } skinparam rectangle { BackgroundColor< > #FFF3E0 BorderColor< > #F57C00 } skinparam rectangle { BackgroundColor< > #F5F5F5 BorderColor< > #616161 } table "branches" < > { *id : PK < > -- *code : UNIQUE *name *city is_active } table "users" < > { *id : PK < > -- *username : UNIQUE *password_hash *full_name branch_id : FK } table "roles" < > { *id : PK < > -- *name : UNIQUE description } ' Junction Table table "user_role" < > { *user_id : FK *role_id : FK -- } branches ||--o{ users users }o--|| roles users ||--o{ user_role roles ||--o{ user_role table "customers" < > { *id : PK < > -- *national_id : UNIQUE *name *monthly_income *assets_value created_at } table "loans" < > { *id : PK < > -- *customer_id : FK *branch_id : FK *principal_amount *profit_rate *tenor_months *status credit_score segment created_at } table "payments" < > { *id : PK < > -- *loan_id : FK *schedule_date *amount_due *amount_paid status } table "notifications" < > { *id : PK < > -- *loan_id : FK type message status } customers ||--o{ loans branches ||--o{ loans loans ||--o{ payments loans ||--o{ notifications table "ml_models" < > { *id : PK < > -- *name version description } table "predictions" < > { *id : PK < > -- *model_id : FK *customer_id : FK *loan_id : FK *credit_score *default_probability segment created_at } table "datasets" < > { *id : PK < > -- *filename *stored_path *uploaded_by : FK rows_count } users ||--o{ datasets loans ||--o{ predictions customers ||--o{ predictions ml_models ||--o{ predictions @enduml
Visualisasi Schema (Canvas Interaktif)
■ Core Tables
■ ML/Analytics
■ System/Auth
Drag untuk menggeser
Code copied to Clipboard!