Lewati ke konten

Backend Modular: Schema.gs & Code.gs

Di Google Apps Script, semua file bertipe .gs secara otomatis berbagi global scope yang sama (tanpa memerlukan perintah import atau export). Kita bisa memisahkan tanggung jawab backend menjadi 2 file modular agar kode lebih bersih dan teratur:

Editor Google Apps Script:
├── Schema.gs # Definisi skema tabel, mapping kolom, & inisialisasi sheet
├── Code.gs # Logika backend CRUD & router Web App (doGet & doPost)
└── Index.html # Frontend: Struktur HTML + Styling CSS dalam 1 file

1. Prompt untuk Membuat Schema.gs & Code.gs (Framework T-C-R-E-I)

Section titled “1. Prompt untuk Membuat Schema.gs & Code.gs (Framework T-C-R-E-I)”
[PERSONA]
Bertindaklah sebagai spesialis backend Google Apps Script.
[TASK]
- Buatkan 2 file backend modular: Schema.gs dan Code.gs untuk aplikasi absensi presensi Google Sheets.
- Pastikan Schema.gs menangani inisialisasi sheet dan validasi struktur tabel, sementara Code.gs fokus pada logika CRUD dan routing Web App.
[CONTEXT]
- Kolom database: ID, Timestamp, Nama, Status (Hadir/Izin/Sakit), Catatan.
- Operasi CRUD: Catat presensi baru (ID unik & timestamp WIB), ambil semua data untuk tabel, ubah status, dan hapus baris.
- Web App: Fungsi doGet() untuk merender Index.html dan doPost() untuk memproses form.
[OUTPUT FORMAT]
1. File Schema.gs (konfigurasi tabel dan inisialisasi sheet otomatis)
2. File Code.gs (fungsi CRUD dan router doGet/doPost yang memanggil fungsi dari Schema.gs)

2. Kode Hasil Schema.gs (Konfigurasi & Inisialisasi Database)

Section titled “2. Kode Hasil Schema.gs (Konfigurasi & Inisialisasi Database)”

File Schema.gs mendefinisikan konstanta nama sheet, struktur kolom, dan fungsi pembantu untuk memastikan sheet siap digunakan:

// ===========================================================================
// SCHEMA.GS — Konfigurasi & Inisialisasi Database Google Sheets
// ===========================================================================
const DB_CONFIG = {
SHEET_NAME: "Database_Absensi",
COLUMNS: ["ID", "Timestamp", "Nama", "Status", "Catatan"],
STATUS_OPTIONS: ["Hadir", "Izin", "Sakit"]
};
/**
* Membuka atau membuat sheet database absensi secara otomatis.
* Jika sheet belum memiliki header kolom, fungsi ini akan membuatnya.
*/
function getDatabaseSheet() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
let sheet = ss.getSheetByName(DB_CONFIG.SHEET_NAME);
if (!sheet) {
sheet = ss.insertSheet(DB_CONFIG.SHEET_NAME);
// Tambahkan header kolom pertama kali
sheet.appendRow(DB_CONFIG.COLUMNS);
sheet.getRange(1, 1, 1, DB_CONFIG.COLUMNS.length)
.setFontWeight("bold")
.setBackground("#242424")
.setFontColor("#fafafa");
}
return sheet;
}

3. Kode Hasil Code.gs (CRUD Engine & Web Router)

Section titled “3. Kode Hasil Code.gs (CRUD Engine & Web Router)”

File Code.gs memanfaatkan fungsi getDatabaseSheet() dari Schema.gs untuk menjalankan seluruh logika Create, Read, Update, Delete:

// ===========================================================================
// CODE.GS — Logika CRUD & Router Web App
// ===========================================================================
// ---------------------------------------------------------------------------
// 1. CREATE: Menambah Catatan Presensi Baru
// ---------------------------------------------------------------------------
function createAttendance(nama, status, catatan) {
const sheet = getDatabaseSheet();
const id = "ABS-" + new Date().getTime();
const timestamp = Utilities.formatDate(new Date(), "GMT+7", "yyyy-MM-dd HH:mm:ss");
sheet.appendRow([id, timestamp, nama, status, catatan || "-"]);
return { status: "success", message: "Presensi berhasil dicatat!", id: id };
}
// ---------------------------------------------------------------------------
// 2. READ: Mengambil Seluruh Riwayat Presensi
// ---------------------------------------------------------------------------
function readAttendance() {
const sheet = getDatabaseSheet();
const data = sheet.getDataRange().getValues();
if (data.length <= 1) return []; // Hanya header kolom
const rows = data.slice(1);
return rows.map((row, index) => ({
rowNumber: index + 2,
id: row[0],
timestamp: row[1],
nama: row[2],
status: row[3],
catatan: row[4]
}));
}
// ---------------------------------------------------------------------------
// 3. UPDATE: Mengubah Status Kehadiran Berdasarkan ID
// ---------------------------------------------------------------------------
function updateAttendance(id, newStatus, newCatatan) {
const sheet = getDatabaseSheet();
const data = sheet.getDataRange().getValues();
for (let i = 1; i < data.length; i++) {
if (data[i][0] === id) {
const row = i + 1;
if (newStatus) sheet.getRange(row, 4).setValue(newStatus);
if (newCatatan) sheet.getRange(row, 5).setValue(newCatatan);
return { status: "success", message: "Data presensi berhasil diperbarui!" };
}
}
return { status: "error", message: "Data tidak ditemukan." };
}
// ---------------------------------------------------------------------------
// 4. DELETE: Menghapus Baris Presensi Berdasarkan ID
// ---------------------------------------------------------------------------
function deleteAttendance(id) {
const sheet = getDatabaseSheet();
const data = sheet.getDataRange().getValues();
for (let i = 1; i < data.length; i++) {
if (data[i][0] === id) {
sheet.deleteRow(i + 1);
return { status: "success", message: "Catatan presensi berhasil dihapus!" };
}
}
return { status: "error", message: "Data tidak ditemukan." };
}
// ---------------------------------------------------------------------------
// 5. PENYAJIAN WEB APP (doGet)
// ---------------------------------------------------------------------------
function doGet(e) {
const template = HtmlService.createTemplateFromFile("Index");
template.attendanceData = readAttendance(); // Dikirim langsung ke HTML
return template.evaluate()
.setTitle("Aplikasi Presensi Karyawan")
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
// ---------------------------------------------------------------------------
// 6. ROUTER HTTP POST: Menangani Kiriman Form dari HTML
// ---------------------------------------------------------------------------
function doPost(e) {
const lock = LockService.getScriptLock();
lock.tryLock(30000);
try {
const action = e.parameter.action || "create";
if (action === "create") {
createAttendance(e.parameter.nama, e.parameter.status, e.parameter.catatan);
} else if (action === "update") {
updateAttendance(e.parameter.id, e.parameter.status, e.parameter.catatan);
} else if (action === "delete") {
deleteAttendance(e.parameter.id);
}
// Tampilkan kembali halaman Index.html dengan data terbaru
const template = HtmlService.createTemplateFromFile("Index");
template.attendanceData = readAttendance();
return template.evaluate()
.setTitle("Aplikasi Presensi Karyawan")
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
} catch (err) {
return HtmlService.createHtmlOutput("<h2 style='font-family:system-ui,sans-serif;color:#ef4444;'>Error: " + err.toString() + "</h2>");
} finally {
lock.releaseLock();
}
}

4. Keuntungan Pemisahan Schema.gs dan Code.gs

Section titled “4. Keuntungan Pemisahan Schema.gs dan Code.gs”
  1. Clean Code: Konfigurasi tabel dan nama kolom tidak tercampur dengan kode logika aplikasi.
  2. Inisialisasi Otomatis: Jika sheet database belum ada di Google Spreadsheet, getDatabaseSheet() di Schema.gs akan langsung membuatnya beserta format header yang rapi.
  3. Tanpa Perlu Import: Google Apps Script secara otomatis menggabungkan seluruh file .gs dalam satu project.

  • Membuat file Schema.gs dan Code.gs di editor Google Apps Script.
  • Memahami cara kerja inisialisasi sheet otomatis di Schema.gs.
  • Menguji fungsi createAttendance dan deleteAttendance di Code.gs.
  • Siap mempublikasikan Web App di modul Integrasi & Deploy.