Jak powstał Destinations (cz. 3): Firebase — baza i logowanie

13.10.2026 · 3 min czytania

W części 2 otypowałem destynacje. Ale skąd się w ogóle biorą? W pierwszej wersji siedziały w zwykłej tablicy w kodzie. Czas pokazać, gdzie zamieszkały naprawdę - i jak zamknąłem panel szkoleniowca na klucz.

Dane nie mogą mieszkać w kodzie#

Tablica destynacji w pliku była OK na start, ale ma wadę: żeby dodać albo usunąć kierunek, musiałbym edytować kod i wdrażać stronę od nowa. A przecież to szkoleniowiec ma zarządzać bazą - bez dotykania kodu. Potrzebowałem więc dwóch rzeczy: prawdziwej bazy danych oraz logowania, żeby panel zarządzania nie był otwarty dla wszystkich.

Firebase: baza i logowanie bez backendu#

Jak wspominałem w części 1, wybrałem Firebase — bo daje jedno i drugie bez stawiania własnego serwera: Firestore (baza) i Firebase Auth (logowanie).

Czytanie destynacji wygląda mniej więcej tak:

import { collection, getDocs } from "firebase/firestore";
import { db } from "./firebase";
import type { Destination } from "./types";

export async function getDestinations(): Promise<Destination[]> {
  const snapshot = await getDocs(collection(db, "destinations"));
  return snapshot.docs.map((doc) => doc.data() as Destination);
}

I tu widać, jak część 2 się spłaca: dane z bazy od razu wpadają w typ Destination, więc reszta aplikacji wie, z czym ma do czynienia.

„Zaraz, klucz API w kodzie?!”#

Konfiguracja Firebase ląduje w kodzie frontendu — razem z apiKey:

const firebaseConfig = {
  apiKey: "AIza...", // to jest PUBLICZNE — i tak ma być
  authDomain: "destinations-xxxx.firebaseapp.com",
  projectId: "destinations-xxxx",
};

Jeśli czytałeś moją serię o metarze, teraz pewnie zastanawiasz się, skąd ta rozbieżność. „Przecież uczyłeś, że token API chowa się na serwerze!”. I słusznie — ale to inny przypadek.

Skoro klucz nie chroni projektu, to co go chroni? Reguły bezpieczeństwa (Security Rules) po stronie Firebase:

match /destinations/{id} {
  allow read: if true;                    // czytać może każdy (do generowania testów)
  allow write: if request.auth != null;   // pisać tylko zalogowany
}

Logowanie szkoleniowca#

Samo logowanie to zasługa Firebase Auth — konto na e-mail i hasło:

import { signInWithEmailAndPassword } from "firebase/auth";
import { auth } from "./firebase";

await signInWithEmailAndPassword(auth, email, password);

Informację o tym, kto jest zalogowany, trzymam w AuthContext — jednym miejscu, z którego cała aplikacja może zapytać „czy ktoś jest zalogowany?”.

W części 4 domknę temat: skoro wiem już, kto jest zalogowany, pokażę, jak fizycznie zamknąć panel przed niezalogowanymi — czyli chronione trasy w React Router.

Więcej z tej serii

  1. 1.Jak powstał Destinations (cz. 1): pomysł, domena i stack
  2. 2.Jak powstał Destinations (cz. 2): z JavaScriptu na TypeScript
  3. 3.Jak powstał Destinations (cz. 3): Firebase — baza i logowanie
  4. 4.Jak powstał Destinations (cz. 4): chronione trasy w React Router
  5. 5.Jak powstał Destinations (cz. 5): generatory testów i CSS do druku