Dashboard & Cloud

Firebase Auth & Firestore untuk Aplikasi IoT

TOKEN

Tutorial komprehensif menggunakan Firebase Authentication dan Cloud Firestore untuk membangun backend aplikasi IoT β€” dari autentikasi user, database real-time, hingga security rules

1. Overview: Mengapa Firebase untuk IoT?

Firebase adalah platform Backend-as-a-Service (BaaS) dari Google yang menyediakan berbagai layanan cloud tanpa perlu mengelola server sendiri. Untuk proyek IoT, Firebase sangat menarik karena menyediakan autentikasi user, database real-time, dan hosting dalam satu platform terintegrasi.

Bayangkan kamu punya proyek Smart Home β€” kamu tidak perlu membuat server API dari nol, mengelola database, atau membangun sistem login. Firebase menyediakan semuanya tinggal pakai.

Layanan Firebase yang Relevan untuk IoT

Layanan Fungsi Contoh Penggunaan IoT
AuthenticationManajemen user & loginLogin ke dashboard monitoring IoT
Cloud FirestoreNoSQL database real-timeMenyimpan data sensor, konfigurasi device
Realtime DatabaseDatabase JSON real-timeStatus device, kontrol relay real-time
Cloud FunctionsServerless functionsProses data sensor, kirim notifikasi
Cloud Messaging (FCM)Push notificationsAlert suhu tinggi ke HP user
HostingWeb hosting statisDeploy dashboard web IoT

Firestore vs Realtime Database

Firebase menyediakan dua database. Untuk kebanyakan proyek IoT modern, Cloud Firestore lebih direkomendasikan karena:

πŸ’‘ Contoh Use Case IoT

Smart Greenhouse: ESP32 mengirim data suhu dan kelembaban ke Cloud Functions via HTTP. Data disimpan di Firestore. User login ke dashboard web menggunakan Firebase Auth (Google Sign-In) dan melihat grafik real-time dari Firestore. Saat suhu melebihi threshold, Cloud Function mengirim push notification ke HP via FCM.

Diagram: Arsitektur Firebase untuk IoT
  ESP32 / Raspberry Pi
        β”‚
        β–Ό (HTTPS POST)
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ Cloud Functions   β”‚ ← Serverless backend
  β”‚ (Node.js)         β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
          β”‚
    β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
    β–Ό            β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚Firestoreβ”‚ β”‚  FCM Push    β”‚
β”‚Database β”‚ β”‚ Notification β”‚
β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
     β”‚
     β–Ό (Real-time sync)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Web/Mobile  β”‚ ← Firebase Auth (login)
β”‚  Dashboard   β”‚ ← Firestore SDK (real-time)
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2. Setup Firebase Authentication

Firebase Authentication menyediakan sistem login yang aman tanpa perlu membuat backend autentikasi dari nol. Mendukung email/password, Google, GitHub, Facebook, dan metode login lainnya.

Langkah 1: Buat Project Firebase

  1. Buka https://console.firebase.google.com
  2. Klik "Add project"
  3. Masukkan nama project (misal: "iot-smart-home")
  4. Aktifkan/nonaktifkan Google Analytics sesuai kebutuhan
  5. Klik "Create project"

Langkah 2: Register Web App

Firebase Console β€” Register Web App
Langkah Register Web App:
1. Di Firebase Console β†’ Project Settings β†’ General
2. Scroll ke bagian "Your apps"
3. Klik ikon Web () untuk register web app
4. Masukkan nama app (misal: "iot-dashboard")
5. Centang "Also set up Firebase Hosting" (opsional)
6. Klik "Register app"
7. Salin konfigurasi Firebase yang muncul

Langkah 3: Inisialisasi Firebase di Project

JavaScript β€” firebase-config.js
// Import Firebase SDK (modular v9+)
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";

// Konfigurasi dari Firebase Console
const firebaseConfig = {
  apiKey: "AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXXX",
  authDomain: "iot-smart-home.firebaseapp.com",
  projectId: "iot-smart-home",
  storageBucket: "iot-smart-home.appspot.com",
  messagingSenderId: "123456789",
  appId: "1:123456789:web:abcdef123456"
};

// Inisialisasi Firebase
const app = initializeApp(firebaseConfig);

// Inisialisasi layanan Authentication dan Firestore
export const auth = getAuth(app);
export const db = getFirestore(app);
export default app;

Instalasi SDK Firebase

Terminal β€” Instalasi Firebase SDK
# Instalasi Firebase SDK untuk web (via npm)
npm install firebase

# Atau gunakan CDN (untuk project tanpa bundler/Vite)
# <script type="module">
#   import { initializeApp } from "https://www.gstatic.com/firebasejs/10.12.0/firebase-app.js";
#   import { getAuth } from "https://www.gstatic.com/firebasejs/10.12.0/firebase-auth.js";
#   import { getFirestore } from "https://www.gstatic.com/firebasejs/10.12.0/firebase-firestore.js";
# </script>
⚠️ Keamanan API Key

Firebase API key tidak perlu disembunyikan β€” ini aman karena keamanan Firebase bergantung pada Security Rules, bukan pada API key. Namun, tetap gunakan environment variables (.env) untuk konsistensi dan kemudahan pengelolaan project.

3. Autentikasi Email & Password

Metode autentikasi paling dasar adalah email dan password. Cocok untuk proyek IoT pribadi atau tim kecil. Berikut implementasi lengkapnya:

Aktifkan Email/Password di Firebase Console

  1. Buka Firebase Console β†’ Authentication β†’ Sign-in method
  2. Klik "Email/Password"
  3. Aktifkan toggle "Enable"
  4. Klik "Save"

Registrasi User Baru

JavaScript β€” Register dengan Email/Password
import { createUserWithEmailAndPassword } from "firebase/auth";
import { auth } from "./firebase-config.js";

async function registerUser(email, password) {
  try {
    // Buat akun baru
    const userCredential = await createUserWithEmailAndPassword(auth, email, password);
    const user = userCredential.user;

    console.log("User berhasil didaftarkan:", user.uid);
    console.log("Email:", user.email);

    return user;
  } catch (error) {
    // Handle error umum
    switch (error.code) {
      case "auth/email-already-in-use":
        console.error("Email sudah terdaftar!");
        break;
      case "auth/weak-password":
        console.error("Password terlalu lemah (minimal 6 karakter)");
        break;
      case "auth/invalid-email":
        console.error("Format email tidak valid");
        break;
      default:
        console.error("Error:", error.message);
    }
    throw error;
  }
}

// Contoh penggunaan di form
document.getElementById("registerForm").addEventListener("submit", async (e) => {
  e.preventDefault();
  const email = document.getElementById("email").value;
  const password = document.getElementById("password").value;
  await registerUser(email, password);
});

Login User

JavaScript β€” Login dengan Email/Password
import { signInWithEmailAndPassword, signOut, onAuthStateChanged } from "firebase/auth";
import { auth } from "./firebase-config.js";

// Login dengan email dan password
async function loginUser(email, password) {
  try {
    const userCredential = await signInWithEmailAndPassword(auth, email, password);
    console.log("Login berhasil!", userCredential.user.email);
    return userCredential.user;
  } catch (error) {
    switch (error.code) {
      case "auth/user-not-found":
        console.error("User tidak ditemukan");
        break;
      case "auth/wrong-password":
        console.error("Password salah");
        break;
      case "auth/too-many-requests":
        console.error("Terlalu banyak percobaan login. Coba lagi nanti.");
        break;
      default:
        console.error("Error login:", error.message);
    }
    throw error;
  }
}

// Logout
async function logoutUser() {
  await signOut(auth);
  console.log("User berhasil logout");
}

// Monitor status auth (penting untuk Single Page App)
onAuthStateChanged(auth, (user) => {
  if (user) {
    console.log("User login:", user.email);
    // Tampilkan dashboard, sembunyikan halaman login
    document.getElementById("dashboard").style.display = "block";
    document.getElementById("loginPage").style.display = "none";
  } else {
    console.log("User belum login");
    // Tampilkan halaman login, sembunyikan dashboard
    document.getElementById("dashboard").style.display = "none";
    document.getElementById("loginPage").style.display = "block";
  }
});
πŸ’‘ Tips: onAuthStateChanged

Fungsi onAuthStateChanged() adalah listener yang dipanggil setiap kali status login berubah. Ini sangat penting di SPA (Single Page Application) karena menentukan halaman mana yang ditampilkan. Selalu pasang listener ini di awal inisialisasi app.

4. Social Login: Google & GitHub

Social login memudahkan user untuk masuk tanpa perlu mengingat password baru. Firebase mendukung Google, GitHub, Facebook, Twitter, dan Apple Sign-In.

Aktifkan Google Sign-In

  1. Buka Firebase Console β†’ Authentication β†’ Sign-in method
  2. Klik "Google"
  3. Aktifkan toggle, masukkan email support project
  4. Klik "Save"
JavaScript β€” Google Sign-In
import { signInWithPopup, GoogleAuthProvider, GithubAuthProvider } from "firebase/auth";
import { auth } from "./firebase-config.js";

// === Google Sign-In ===
async function signInWithGoogle() {
  try {
    const provider = new GoogleAuthProvider();
    provider.addScope("email");
    provider.addScope("profile");

    const result = await signInWithPopup(auth, provider);
    const user = result.user;

    console.log("Google login berhasil!");
    console.log("Nama:", user.displayName);
    console.log("Email:", user.email);
    console.log("Photo:", user.photoURL);

    // Dapatkan Google Access Token (untuk akses Google API lain)
    const credential = GoogleAuthProvider.credentialFromResult(result);
    const token = credential.accessToken;

    return user;
  } catch (error) {
    console.error("Error Google login:", error.code, error.message);
    throw error;
  }
}

// === GitHub Sign-In ===
async function signInWithGitHub() {
  try {
    const provider = new GithubAuthProvider();
    provider.addScope("repo");

    const result = await signInWithPopup(auth, provider);
    const user = result.user;

    console.log("GitHub login berhasil!");
    console.log("Username:", user.displayName);
    console.log("Email:", user.email);

    return user;
  } catch (error) {
    if (error.code === "auth/account-exists-with-different-credential") {
      console.error("Email sudah terdaftar dengan provider lain!");
    }
    throw error;
  }
}

// Pasang event listener ke tombol
document.getElementById("btnGoogle").addEventListener("click", signInWithGoogle);
document.getElementById("btnGitHub").addEventListener("click", signInWithGitHub);
⚠️ Authorized Domains

Social login hanya bekerja dari domain yang terdaftar di Firebase Console. Buka Authentication β†’ Settings β†’ Authorized domains dan tambahkan domain kamu (misal: localhost, dashboard.iotkamu.com). Tanpa ini, popup login akan error auth/unauthorized-domain.

5. Cloud Firestore Database

Cloud Firestore adalah database NoSQL berbasis dokumen yang menyimpan data dalam koleksi dan dokumen. Strukturnya mirip JSON tetapi dengan fitur query yang lebih kuat dan skalabilitas tinggi.

Aktifkan Firestore

  1. Buka Firebase Console β†’ Build β†’ Firestore Database
  2. Klik "Create database"
  3. Pilih mode: Start in test mode (untuk development) atau Production mode
  4. Pilih lokasi server terdekat (misal: asia-southeast2 untuk Jakarta)
  5. Klik "Enable"

Konsep Data Firestore

Diagram: Struktur Data Firestore
  Collection: "devices"
  β”œβ”€β”€ Document: "device-001"
  β”‚   β”œβ”€β”€ name: "Sensor Suhu Ruang Server"
  β”‚   β”œβ”€β”€ type: "temperature"
  β”‚   β”œβ”€β”€ location: "Lantai 2, Ruang Server"
  β”‚   β”œβ”€β”€ owner_uid: "abc123"
  β”‚   └── Sub-collection: "readings"
  β”‚       β”œβ”€β”€ Doc: "2026-06-25T10:00:00"
  β”‚       β”‚   β”œβ”€β”€ suhu: 28.5
  β”‚       β”‚   └── kelembaban: 72.0
  β”‚       └── Doc: "2026-06-25T10:05:00"
  β”‚           β”œβ”€β”€ suhu: 28.7
  β”‚           └── kelembaban: 71.5
  β”‚
  β”œβ”€β”€ Document: "device-002"
  β”‚   β”œβ”€β”€ name: "Sensor Kelembaban Tanah"
  β”‚   β”œβ”€β”€ type: "soil_moisture"
  β”‚   └── location: "Kebun Belakang"
  β”‚
  └── Document: "device-003"
      β”œβ”€β”€ name: "Relay Lampu Teras"
      └── type: "relay"

  Collection = Grup dokumen (seperti "tabel")
  Document = Record data (seperti "baris")
  Field = Kolom data (string, number, boolean, array, map)
  Sub-collection = Koleksi bersarang dalam dokumen

Perbedaan utama dengan database relasional:

Aspek SQL (MySQL) Firestore (NoSQL)
StrukturTabel dengan baris dan kolomKoleksi dengan dokumen
SchemaTetap, harus didefinisikanFleksibel, bisa berbeda per dokumen
RelasiJOIN antar tabelSub-collection atau referensi
QuerySQLSDK dengan filter, sort, limit
SkalabilitasVertikal (tambah resource)Horizontal (otomatis)
Real-timePolling / externalBuilt-in real-time listener

6. CRUD Operations di Firestore

CRUD (Create, Read, Update, Delete) adalah operasi dasar database. Berikut implementasi lengkap dengan Cloud Firestore:

Create β€” Menambah Data

JavaScript β€” Create Data di Firestore
import { collection, doc, setDoc, addDoc, serverTimestamp } from "firebase/firestore";
import { db, auth } from "./firebase-config.js";

// === Metode 1: addDoc() β€” ID dokumen otomatis ===
async function addDevice(deviceData) {
  try {
    const docRef = await addDoc(collection(db, "devices"), {
      name: deviceData.name,
      type: deviceData.type,
      location: deviceData.location,
      owner_uid: auth.currentUser.uid,
      status: "online",
      created_at: serverTimestamp(),
      updated_at: serverTimestamp()
    });
    console.log("Device ditambahkan dengan ID:", docRef.id);
    return docRef.id;
  } catch (error) {
    console.error("Error menambah device:", error);
    throw error;
  }
}

// === Metode 2: setDoc() β€” ID manual ===
async function addReading(deviceId, readingData) {
  try {
    const readingId = new Date().toISOString(); // ID berdasarkan timestamp
    const readingRef = doc(db, "devices", deviceId, "readings", readingId);

    await setDoc(readingRef, {
      suhu: readingData.suhu,
      kelembaban: readingData.kelembaban,
      timestamp: serverTimestamp()
    });
    console.log("Data sensor ditambahkan:", readingId);
  } catch (error) {
    console.error("Error menambah data:", error);
    throw error;
  }
}

// Contoh penggunaan
await addDevice({
  name: "Sensor Suhu Gudang",
  type: "temperature",
  location: "Gudang Utama"
});

await addReading("device-001", {
  suhu: 28.5,
  kelembaban: 72.0
});

Read β€” Membaca Data

JavaScript β€” Read Data dari Firestore
import { collection, doc, getDoc, getDocs, query, where, orderBy, limit } from "firebase/firestore";
import { db } from "./firebase-config.js";

// === Baca satu dokumen berdasarkan ID ===
async function getDevice(deviceId) {
  const docRef = doc(db, "devices", deviceId);
  const docSnap = await getDoc(docRef);

  if (docSnap.exists()) {
    console.log("Data device:", docSnap.data());
    return { id: docSnap.id, ...docSnap.data() };
  } else {
    console.log("Device tidak ditemukan!");
    return null;
  }
}

// === Baca semua device milik user yang sedang login ===
async function getUserDevices() {
  const q = query(
    collection(db, "devices"),
    where("owner_uid", "==", auth.currentUser.uid),
    orderBy("created_at", "desc"),
    limit(50)
  );

  const querySnapshot = await getDocs(q);
  const devices = [];

  querySnapshot.forEach((doc) => {
    devices.push({ id: doc.id, ...doc.data() });
  });

  console.log(`Ditemukan ${devices.length} device`);
  return devices;
}

// === Baca data sensor dengan filter ===
async function getHighTempReadings(deviceId, minTemp) {
  const q = query(
    collection(db, "devices", deviceId, "readings"),
    where("suhu", ">", minTemp),
    orderBy("suhu", "desc"),
    limit(10)
  );

  const snapshot = await getDocs(q);
  return snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
}

Update & Delete

JavaScript β€” Update & Delete Data
import { doc, updateDoc, deleteDoc, serverTimestamp } from "firebase/firestore";
import { db } from "./firebase-config.js";

// === Update data device ===
async function updateDevice(deviceId, newData) {
  const deviceRef = doc(db, "devices", deviceId);

  await updateDoc(deviceRef, {
    ...newData,
    updated_at: serverTimestamp()
  });

  console.log("Device berhasil diupdate");
}

// Contoh: update status dan lokasi device
await updateDevice("device-001", {
  status: "offline",
  location: "Lantai 3, Ruang Lab"
});

// === Hapus device (termasuk sub-collection) ===
async function deleteDevice(deviceId) {
  // PERINGATAN: Sub-collection tidak otomatis terhapus!
  // Hapus sub-collection "readings" terlebih dahulu
  const readings = await getDocs(collection(db, "devices", deviceId, "readings"));
  const deletePromises = readings.docs.map(d => deleteDoc(d.ref));
  await Promise.all(deletePromises);

  // Hapus dokumen device
  await deleteDoc(doc(db, "devices", deviceId));
  console.log("Device dan semua data sensornya berhasil dihapus");
}

// === Batch write: operasi sekaligus ===
import { writeBatch } from "firebase/firestore";

async function batchUpdateStatus(deviceIds, status) {
  const batch = writeBatch(db);

  deviceIds.forEach(id => {
    const deviceRef = doc(db, "devices", id);
    batch.update(deviceRef, { status, updated_at: serverTimestamp() });
  });

  await batch.commit(); // Commit semua sekaligus
  console.log(`${deviceIds.length} device diupdate sekaligus`);
}

7. Firestore Security Rules

Security Rules menentukan siapa yang boleh membaca, menulis, atau menghapus data. Tanpa rules yang benar, siapa saja bisa mengakses data sensor IoT kamu. Ini adalah lapisan keamanan paling penting di Firebase.

⚠️ Security Rules Bukan Opsional!

API key Firebase bersifat publik β€” siapa saja yang melihat source code web kamu bisa mengetahui API key-nya. Security Rules adalah satu-satunya pertahanan untuk melindungi data kamu. Jangan pernah menggunakan "test mode" di produksi!

Firestore β€” firestore.rules
rules_version = "2";
service cloud.firestore {
  match /databases/{database}/documents {

    // Helper function: cek apakah user sudah login
    function isAuth() {
      return request.auth != null;
    }

    // Helper function: cek apakah user adalah pemilik dokumen
    function isOwner(userId) {
      return request.auth.uid == userId;
    }

    // === Collection: devices ===
    match /devices/{deviceId} {
      // Baca: hanya pemilik device yang bisa melihat
      allow read: if isAuth() && isOwner(resource.data.owner_uid);

      // Buat: user yang login, owner_uid harus miliknya, wajib ada field tertentu
      allow create: if isAuth()
        && request.resource.data.owner_uid == request.auth.uid
        && request.resource.data.keys().hasAll(["name", "type", "owner_uid"])
        && request.resource.data.name is string
        && request.resource.data.name.size() > 0;

      // Update: hanya pemilik, owner_uid tidak bisa diubah
      allow update: if isAuth()
        && isOwner(resource.data.owner_uid)
        && request.resource.data.owner_uid == resource.data.owner_uid;

      // Hapus: hanya pemilik
      allow delete: if isAuth() && isOwner(resource.data.owner_uid);

      // Sub-collection: readings (data sensor)
      match /readings/{readingId} {
        // Baca: hanya pemilik parent device
        allow read: if isAuth() && isOwner(
          get(/databases/$(database)/documents/devices/$(deviceId)).data.owner_uid
        );

        // Tulis data baru: hanya pemilik, validasi tipe data
        allow create: if isAuth()
          && isOwner(get(/databases/$(database)/documents/devices/$(deviceId)).data.owner_uid)
          && request.resource.data.suhu is number
          && request.resource.data.kelembaban is number;

        // Data sensor TIDAK BOLEH diubah atau dihapus (integritas data)
        allow update, delete: if false;
      }
    }
  }
}

Testing Security Rules

Terminal β€” Test Security Rules
# Instalasi Firebase CLI
npm install -g firebase-tools

# Login ke Firebase
firebase login

# Jalankan emulator untuk test security rules secara lokal
firebase emulators:start --only firestore

# Deploy security rules ke production
firebase deploy --only firestore:rules

8. Real-Time Listeners

Fitur terbaik Firestore untuk IoT adalah real-time listener. Data yang berubah di database akan otomatis ter-update di semua client yang mendengarkan. Tidak perlu polling β€” Firestore melakukan push update ke client.

JavaScript β€” Real-Time Listener
import { collection, doc, onSnapshot, query, where, orderBy, limit } from "firebase/firestore";
import { db } from "./firebase-config.js";

// === Listener untuk satu dokumen (real-time) ===
function watchDevice(deviceId) {
  const deviceRef = doc(db, "devices", deviceId);

  const unsubscribe = onSnapshot(deviceRef, (docSnap) => {
    if (docSnap.exists()) {
      const data = docSnap.data();
      console.log("Status device berubah:", data.status);

      // Update UI secara real-time
      document.getElementById("deviceName").textContent = data.name;
      document.getElementById("deviceStatus").textContent = data.status;
      document.getElementById("deviceStatus").className =
        data.status === "online" ? "badge-success" : "badge-danger";
    }
  }, (error) => {
    console.error("Error listening device:", error);
  });

  // Kembalikan fungsi unsubscribe untuk berhenti mendengarkan
  return unsubscribe;
}

// === Listener untuk data sensor terbaru ===
function watchLatestReadings(deviceId) {
  const q = query(
    collection(db, "devices", deviceId, "readings"),
    orderBy("timestamp", "desc"),
    limit(10)
  );

  const unsubscribe = onSnapshot(q, (snapshot) => {
    const readings = [];
    snapshot.forEach((doc) => {
      readings.push({ id: doc.id, ...doc.data() });
    });

    console.log(`Data sensor terbaru (${readings.length} records):`, readings);

    // Update grafik di dashboard
    updateChart(readings);

    // Update gauge suhu
    if (readings.length > 0) {
      const latestSuhu = readings[0].suhu;
      document.getElementById("gaugeSuhu").textContent = latestSuhu + "Β°C";

      // Alert jika suhu kritis
      if (latestSuhu > 35) {
        showAlert("Suhu kritis! " + latestSuhu + "Β°C");
      }
    }
  });

  return unsubscribe;
}

// === Menggunakan listener ===
const unsubDevice = watchDevice("device-001");
const unsubReadings = watchLatestReadings("device-001");

// Berhenti mendengarkan saat tidak diperlukan (hemat kuota)
// unsubDevice();
// unsubReadings();
πŸ’‘ Hemat Kuota Firestore

Firestore menghitung setiap dokumen yang dibaca sebagai 1 read operation (termasuk dari listener). Jika listener mendengarkan 100 dokumen dan masing-masing berubah 1x, itu = 200 read operations. Gunakan limit() dan where() untuk membatasi data yang didengarkan. Unsubscribe listener saat halaman tidak aktif.

9. Quiz: Uji Pemahamanmu!

Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Firebase Auth dan Firestore:

Pertanyaan 1: Mengapa Firebase API key TAK PERLU disembunyikan di source code?

a) Karena API key sudah dienkripsi oleh Firebase
b) Karena keamanan Firebase bergantung pada Security Rules, bukan API key
c) Karena Firebase memblokir akses dari IP yang tidak dikenal
d) Karena API key otomatis berubah setiap hari

Pertanyaan 2: Apa perbedaan antara addDoc() dan setDoc() di Firestore?

a) addDoc() untuk update, setDoc() untuk create
b) addDoc() membuat ID otomatis, setDoc() menggunakan ID manual
c) addDoc() untuk collection, setDoc() untuk field
d) Tidak ada perbedaan, keduanya sama

Pertanyaan 3: Fungsi apa yang digunakan untuk memantau perubahan data secara real-time di Firestore?

a) getDoc()
b) watchDoc()
c) onSnapshot()
d) subscribe()

Pertanyaan 4: Dalam Security Rules, request.auth.uid merujuk ke apa?

a) UID dari Firebase project
b) UID dari user yang sedang melakukan request (sudah login)
c) UID dari device IoT yang sedang mengirim data
d) UID dari dokumen Firestore

Pertanyaan 5: Mengapa onSnapshot() perlu di-unsubscribe saat halaman tidak aktif?

a) Untuk menghemat kuota baca Firestore
b) Untuk menghindari error di browser
c) Untuk menghapus data dari cache
d) Tidak perlu di-unsubscribe, Firebase menanganinya otomatis
← Sebelumnya Nginx Reverse Proxy Selanjutnya β†’ Deploy ke VPS