✅ Kode Berhasil Disalin!

Prompt dan Source Code Aplikasi Guru BK (Berbasis Web Terpadu)

Manajemen data kedisiplinan, catatan pelanggaran, pencatatan prestasi, hingga rekapitulasi absensi seringkali menjadi tantangan tersendiri bagi tenaga pendidik. Untuk mempermudah administrasi tersebut, kami membagikan Prompt AI dan Source Code Aplikasi SIP-BK Platinum yang bisa Anda bangun dan gunakan secara 100% gratis!

Apa itu Bimbingan dan Konseling (BK)?

Bimbingan dan Konseling (BK) adalah proses interaksi berkesinambungan antara konselor (Guru BK) dan konseli (Siswa). Tujuannya adalah untuk membantu siswa mengoptimalkan potensi diri, memecahkan masalah pribadi maupun akademik, serta merencanakan masa depan. Di era digital saat ini, seorang Guru BK dituntut untuk memiliki sistem pencatatan yang cepat, akurat, dan rahasia mengenai rekam jejak kedisiplinan dan capaian siswa.

Mengapa Menggunakan Google Apps Script?

Google Apps Script (GAS) adalah platform cloud berbasis JavaScript dari Google. Manfaat utamanya untuk Guru BK:

  • 100% Gratis: Tidak perlu membayar biaya langganan server atau hosting bulanan.
  • Database Excel: Data tersimpan rapi di Google Sheets milik Anda. Sangat mudah diedit, disortir, dan di-backup.
  • Keamanan Privasi: Data siswa sangat rahasia. Dengan GAS, data sepenuhnya berada di bawah kendali dan keamanan ekosistem akun Google pribadi Anda.

Mengapa Menggunakan Blogger?

Blogger umumnya dikenal sebagai platform untuk menulis artikel. Namun, bagi para developer, Blogger bisa diubah menjadi User Interface (UI) Aplikasi Web yang sangat canggih.

  • Akses Universal: Dapat diakses melalui HP Android, iPhone, Tablet, maupun Laptop 24/7.
  • Hosting Frontend Gratis: Memanfaatkan bandwidth Google tanpa batas.
  • Tampilan Premium: Mendukung integrasi React JS dan Tailwind CSS untuk menciptakan aplikasi dengan performa secepat kilat.

1. Buat Mandiri (Prompt AI Detail dan Lengkap)

Jika Anda ingin membuat atau memodifikasi aplikasi ini secara mandiri menggunakan bantuan AI (seperti ChatGPT, Claude, atau Gemini), silakan gunakan prompt super detail di bawah ini. Prompt ini telah dirancang secara khusus agar AI menghasilkan kode yang stabil dan aman (bebas error XML) saat dipasang di Blogger.

Prompt Pembangunan Aplikasi BK
Bertindaklah sebagai Senior Fullstack Developer. Buatkan saya Source Code "Aplikasi Sistem Informasi Guru Bimbingan Konseling (SIP-BK)". 

Saya butuh 2 bagian kode:
1. BACKEND (Google Apps Script):
Buatkan fungsi doGet dan doPost untuk menjadikan Google Sheets sebagai database API. Fungsi harus bisa menarik data, menyimpan data tunggal, bulk import, dan hapus data.
Otomatis buatkan Sheet (Data_Siswa, Data_Pelanggaran, Data_Konseling, Data_Prestasi, Data_HomeVisit, Data_Absensi, Data_Panggilan, Data_Config) jika belum ada. Gunakan `Date.now() + Math.floor(Math.random() * 1000)` untuk generate ID. Gunakan `getDisplayValues()` untuk performa tinggi.

2. FRONTEND (Template Blogger XML):
Buat antarmuka menggunakan React JS (UMD via CDN), Babel Standalone, dan Tailwind CSS. 
ATURAN WAJIB FRONTEND:
- Format harus berupa satu file HTML/XML yang siap di-paste ke Tema Blogger.
- SEMUA tag script library eksternal wajib menggunakan penutup eksplisit (contoh: <script src="..."></script>), jangan gunakan self-closing tag!
- Buat fitur: Dashboard statistik, Absensi Harian, Master Siswa (Bisa Import Excel via sheetjs), Buku Kasus, Pantauan Siswa, Surat Panggilan, Buku Konseling, Prestasi, dan Home Visit.
- Integrasikan jsPDF, jsPDF-autotable, html2canvas, dan jsbarcode untuk mencetak Laporan PDF dan Surat Panggilan secara langsung dari browser.
- Desain harus premium, modern, warna dominan biru elegan (slate-900 & blue-600), dan Mobile Friendly. Tambahkan animasi pre-loader sebelum React dirender.

2. Copy Paste (Source Code Backend GAS)

Bagi Anda yang ingin langsung memiliki aplikasi ini tanpa harus repot menyusun *prompt* AI, kami sudah menyiapkannya! Cukup salin kode backend Google Apps Script secara lengkap di bawah ini dan paste di halaman Google Apps Script baru Anda.

PENTING: Setelah menempelkan kode, klik menu Deploy > New Deployment (Web App) dengan setelan akses "Anyone" (Siapa saja).

Code.gs (Backend SIP-BK Platinum)
/* BACKEND - SIP BK PLATINUM (FINAL V9 - CORS & ID FIXED) */

function getDatabase() {
  const props = PropertiesService.getScriptProperties();
  let dbId = props.getProperty("SIP_BK_DB_ID");

  if (!dbId) {
    const newSs = SpreadsheetApp.create("Database_SIP_BK_Platinum");
    dbId = newSs.getId();
    props.setProperty("SIP_BK_DB_ID", dbId); 
    setupDatabase(newSs); 
    return newSs;
  }
  
  try {
    return SpreadsheetApp.openById(dbId);
  } catch (e) {
    const fallbackSs = SpreadsheetApp.create("Database_SIP_BK_Platinum_Recovery");
    props.setProperty("SIP_BK_DB_ID", fallbackSs.getId());
    setupDatabase(fallbackSs); 
    return fallbackSs;
  }
}

function doGet(e) {
  try {
    if (e && e.parameter && e.parameter.action === 'getInitialData') {
      const ss = getDatabase(); 
      const data = {
        config: getConfig(ss),
        students: getSheetData(ss, "Data_Siswa"),
        violations: getSheetData(ss, "Data_Pelanggaran"),
        counselings: getSheetData(ss, "Data_Konseling"),
        achievements: getSheetData(ss, "Data_Prestasi"),
        homeVisits: getSheetData(ss, "Data_HomeVisit"),
        attendances: getSheetData(ss, "Data_Absensi"),
        callLetters: getSheetData(ss, "Data_Panggilan")
      };
      return ContentService.createTextOutput(JSON.stringify(data)).setMimeType(ContentService.MimeType.JSON);
    }
    return ContentService.createTextOutput(JSON.stringify({ status: "API Aktif." })).setMimeType(ContentService.MimeType.JSON);
  } catch (error) {
    return ContentService.createTextOutput(JSON.stringify({ error: true, message: error.message })).setMimeType(ContentService.MimeType.JSON);
  }
}

function doPost(e) {
  try {
    if (!e || !e.postData || !e.postData.contents) throw new Error("Tidak ada data payload.");
    const body = JSON.parse(e.postData.contents);
    const action = body.action;
    let result = { success: true };
    const ss = getDatabase(); 

    if (action === 'addDataToSheet') result.data = addDataToSheet(ss, body.sheetName, body.dataObj);
    else if (action === 'deleteDataFromSheet') result.data = deleteDataFromSheet(ss, body.sheetName, body.id);
    else if (action === 'saveConfig') result.data = saveConfig(ss, body.newConfig);
    else if (action === 'importBulkStudents') result.data = importBulkStudents(ss, body.dataArray);
    else if (action === 'saveBulkAttendance') result.data = saveBulkAttendance(ss, body.attendanceDataArray);
    else result = { success: false, message: "Aksi tidak dikenali." };

    return ContentService.createTextOutput(JSON.stringify(result)).setMimeType(ContentService.MimeType.JSON);
  } catch (error) {
    return ContentService.createTextOutput(JSON.stringify({ success: false, error: true, message: error.message })).setMimeType(ContentService.MimeType.JSON);
  }
}

function getConfig(ss) {
  const sheet = ss.getSheetByName("Data_Config");
  if (!sheet) return {};
  const data = sheet.getDataRange().getDisplayValues(); 
  let config = {};
  for(let i=1; i<data.length; i++) config[data[i][0]] = data[i][1];
  return config;
}

function getSheetData(ss, sheetName) {
  const sheet = ss.getSheetByName(sheetName);
  if (!sheet || sheet.getLastRow() < 2) return []; 
  const rawData = sheet.getDataRange().getDisplayValues(); 
  const headers = rawData.shift(); 
  return rawData.map(row => {
    let obj = {};
    headers.forEach((header, index) => { obj[header] = row[index]; });
    return obj;
  });
}

function saveConfig(ss, newConfig) {
  const sheet = ss.getSheetByName("Data_Config");
  if(sheet.getLastRow() > 1) sheet.getRange(2, 1, sheet.getLastRow()-1, 2).clearContent();
  let rows = [];
  for (const [key, value] of Object.entries(newConfig)) rows.push([key, value]);
  if(rows.length > 0) sheet.getRange(2, 1, rows.length, 2).setValues(rows);
  return getConfig(ss);
}

function addDataToSheet(ss, sheetName, dataObj) {
  const sheet = ss.getSheetByName(sheetName);
  const headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
  const rowData = headers.map(header => {
    if (header === 'id') return dataObj['id'] || (Date.now() + Math.floor(Math.random() * 1000)); 
    let val = dataObj[header];
    return (val === undefined || val === null) ? "" : val;
  });
  sheet.appendRow(rowData);
  return true;
}

function importBulkStudents(ss, dataArray) {
  const sheet = ss.getSheetByName("Data_Siswa");
  if (!dataArray || dataArray.length === 0) return false;
  const rows = dataArray.map((row, index) => [ row.id || (Date.now() + index), row.name || "", row.class || "", row.nis || "", "Aktif", 0 ]);
  sheet.getRange(sheet.getLastRow() + 1, 1, rows.length, rows[0].length).setValues(rows);
  return true;
}

function saveBulkAttendance(ss, attendanceDataArray) {
  const sheet = ss.getSheetByName("Data_Absensi");
  if (!attendanceDataArray || attendanceDataArray.length === 0) return false;
  const rows = attendanceDataArray.map((row, index) => [ row.id || (Date.now() + index), row.date || "", row.studentId || "", row.studentName || "", row.class || "", row.status || "Hadir" ]);
  sheet.getRange(sheet.getLastRow() + 1, 1, rows.length, rows[0].length).setValues(rows);
  return true;
}

function deleteDataFromSheet(ss, sheetName, id) {
  const sheet = ss.getSheetByName(sheetName);
  if(!sheet) return false;
  const data = sheet.getDataRange().getValues();
  const idIndex = data[0].indexOf('id');
  if (idIndex === -1) return false;
  
  for (let i = 1; i < data.length; i++) {
    if (String(data[i][idIndex]) === String(id)) { 
      sheet.deleteRow(i + 1); 
      return true; 
    }
  }
  return false;
}

function setupDatabase(ss) {
  const schema = {
    "Data_Siswa": ["id", "name", "class", "nis", "status", "points"],
    "Data_Pelanggaran": ["id", "studentId", "studentName", "date", "type", "points", "note"],
    "Data_Konseling": ["id", "studentId", "studentName", "date", "time", "status", "topic"],
    "Data_Prestasi": ["id", "studentId", "studentName", "date", "title", "level", "note"],
    "Data_HomeVisit": ["id", "studentId", "studentName", "date", "parentName", "result", "petugas"],
    "Data_Absensi": ["id", "date", "studentId", "studentName", "class", "status"],
    "Data_Panggilan": ["id", "studentId", "studentName", "date", "letterNo", "reason"]
  };
  for (let sheetName in schema) {
    if (!ss.getSheetByName(sheetName)) {
      let s = ss.insertSheet(sheetName);
      s.appendRow(schema[sheetName]);
      s.getRange("A1:" + String.fromCharCode(64 + schema[sheetName].length) + "1").setBackground("#1e293b").setFontColor("white").setFontWeight("bold");
    }
  }
  if (!ss.getSheetByName("Data_Config")) {
    let s = ss.insertSheet("Data_Config");
    s.appendRow(["Key", "Value"]);
    s.getRange("A1:B1").setBackground("#1e293b").setFontColor("white").setFontWeight("bold");
    
    const defaults = [
      ["tempatTtd", "Kerinci"], ["schoolName", "SMP NEGERI 3 KERINCI"], ["schoolAddress", "Jl. Lempur Tengah, Kec. Gunung Raya, Kab. Kerinci"],
      ["guruName", "Reni Emelisa, S. Pd., Gr."], ["guruNip", "199310112024212043"], ["kepsekName", "Hamdani, S. Pd."], ["kepsekNip", "197108142005021005"],
      ["logoDaerah", "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/Circle_-_black_simple.svg/1024px-Circle_-_black_simple.svg.png"], 
      ["logoSekolah", "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/Circle_-_black_simple.svg/1024px-Circle_-_black_simple.svg.png"] 
    ];
    s.getRange(2, 1, defaults.length, 2).setValues(defaults);
  }
}

3. Download Tema Frontend (Blogger XML)

Untuk bagian Frontend (Tampilan Visual), Anda tidak perlu menulis kode manual sama sekali. Cukup download file XML yang sudah kami sediakan secara Direct Download melalui tombol pelangi di bawah ini, lalu ikuti panduan instalasinya.

Langkah-Langkah Instalasi (Penting!)

  1. Setelah menekan tombol di atas, klik ikon Download di Google Drive untuk menyimpan file XML ke komputer atau perangkat Anda.
  2. Buka *dashboard* akun Blogger Anda.
  3. Masuk ke menu Tema (Theme).
  4. Klik tombol panah bawah di samping tombol Sesuaikan (Customize), lalu pilih Edit HTML.
  5. Buka file XML yang Anda download tadi menggunakan Notepad atau Text Editor. Copy semua isinya (Ctrl+A lalu Ctrl+C).
  6. Di editor HTML Blogger, hapus semua kode yang lama (Ctrl+A lalu Delete), kemudian Paste kode yang baru saja Anda salin.
  7. Cari teks URL_WEB_APP_ANDA_DISINI di dalam baris kode tersebut. Ganti teks tersebut dengan URL Deployment Apps Script milik Anda.
  8. Klik ikon Save (Simpan) di pojok kanan atas layar Blogger Anda.

📌 Info Lokasi Database Google Drive Anda

Setelah Anda memasang URL Web App dan mengakses blog Anda untuk pertama kalinya, sistem *backend* akan secara otomatis memproduksi file database berbentuk Excel (Spreadsheet) untuk Anda.

Silakan buka Google Drive Anda, gunakan kolom pencarian, lalu ketik nama file ini:
Database_SIP_BK_Platinum

Di dalam file Spreadsheet itulah seluruh entri data siswa, rekapitulasi absensi harian, hingga histori buku kasus pelanggaran Anda tersimpan dengan aman!