Seria: Po godzinach w IT / rekordy siłowe / część 2
Jak działa strona z rekordami: arkusz, Worker, D1 i zwykły HTML
Druga część mini-serii o rekordach siłowych: tym razem o tym, jak połączyłem arkusz, Apps Script, Workera, D1 i statyczną stronę w jeden prosty przepływ danych.
Co chciałem osiągnąć
W pierwszym wpisie pokazałem, skąd wziął się pomysł na stronę z rekordami siłowymi. Zaczęło się od prostej tabelki dla mnie i znajomych. Chcieliśmy mieć miejsce, gdzie można szybko pokazać rekordy bez udostępniania arkusza i bez ryzyka, że ktoś przypadkiem zmieni wartości.
Na początku wystarczył arkusz. Później doszła prosta strona. Ale ręczne poprawianie HTML-a po każdej zmianie wyniku szybko przestało mieć sens.
Dlatego drugim krokiem było ułożenie całego przepływu danych tak, żeby rekordy nadal dało się wygodnie wpisywać w arkuszu, ale żeby strona sama pobierała aktualne wyniki.
Nie chciałem budować dużej aplikacji. Nie chciałem stawiać własnego serwera, konfigurować całego backendu ani robić panelu logowania od zera. Chodziło o mały projekt, który można zrobić prosto, serverlessowo i darmowo poza kosztem domeny. W moim przypadku domena to około 40 zł rocznie.
Ogólny pomysł
Całość działa mniej więcej tak: arkusz jest miejscem edycji danych, Apps Script wysyła rekord dalej, Worker przyjmuje dane i zapisuje je w D1, a statyczna strona pobiera aktualne rekordy i wyświetla tabelę.
Każdy element ma swoją prostą rolę. Dzięki temu nie trzeba edytować strony po każdej zmianie wyniku, a sam projekt nadal zostaje mały i zrozumiały.
Google Sheets jako miejsce edycji
Arkusz nadal jest najwygodniejszym miejscem do wpisywania takich danych. Można szybko dodać osobę, poprawić wynik, sprawdzić tabelę i nie trzeba do tego osobnej aplikacji.
W tym projekcie Google Sheets nie jest publiczną bazą danych. Nie udostępniam arkusza wszystkim osobom, które mają zobaczyć rekordy. Arkusz jest miejscem zarządzania danymi, a nie miejscem ich publicznego wyświetlania.
To ważne rozróżnienie. Strona pokazuje rekordy, ale nie daje możliwości ich edycji. Edycja zostaje po mojej stronie, w arkuszu.
Apps Script jako automat w arkuszu
Sam arkusz przechowuje dane, ale potrzebowałem jeszcze sposobu, żeby wygodnie wysłać je dalej. Tutaj wchodzi Google Apps Script.
W praktyce Apps Script robi kilka rzeczy:
- dodaje własne menu w arkuszu,
- otwiera popup do dodawania rekordów,
- pozwala wybrać osobę, datę i ćwiczenia,
- sprawdza podstawowe dane,
- wysyła wynik do Workera.
Dzięki temu nie trzeba ręcznie kopiować danych z arkusza do strony. Użytkownik wpisuje rekord w formularzu, a reszta dzieje się automatycznie.
Worker jako mały pośrednik techniczny
Cloudflare Worker działa tutaj jako mały pośrednik techniczny.
Nie jest to klasyczny serwer, który trzeba samemu utrzymywać. Nie instaluję systemu, nie konfiguruję VPS-a, nie pilnuję procesu aplikacji. Worker działa po stronie Cloudflare i reaguje na konkretne zapytania.
W tym projekcie Worker ma dwa główne zadania. Gdy Apps Script wysyła nowy rekord, Worker odbiera go, sprawdza i zapisuje w bazie. Gdy strona z rekordami się ładuje, pobiera z Workera aktualne wyniki i wyświetla je w tabeli.
Można powiedzieć, że Worker jest miejscem, w którym arkusz spotyka się ze stroną.
D1 jako mała baza danych
Do przechowywania danych użyłem Cloudflare D1.
W uproszczeniu: D1 jest małą bazą danych, która dobrze pasuje do takich projektów. Nie trzeba stawiać osobnego serwera bazodanowego, a Worker może z niej bezpośrednio korzystać.
W tym projekcie baza przechowuje dwa typy informacji:
- aktualne rekordy,
- historię zmian.
Aktualne rekordy są potrzebne do wyświetlenia tabeli na stronie. Historia jest przydatna, bo jeśli ktoś poprawi wynik, stary wpis nie musi od razu znikać bez śladu.
Strona nadal jest zwykłym HTML-em
Najfajniejsze w tym rozwiązaniu jest to, że sama strona nadal pozostaje prosta.
Nie musiałem robić dużej aplikacji frontendowej. Strona jest statyczna, ale ma mały fragment JavaScriptu, który pobiera dane z Workera.
Po wejściu na stronę dzieje się kilka rzeczy:
- przeglądarka ładuje zwykły plik HTML,
- JavaScript wysyła zapytanie do Workera,
- Worker zwraca rekordy z D1,
- strona buduje tabelę,
- w komórkach pojawia się wynik i data.
Efekt dla użytkownika jest prosty: widzi tabelę rekordów. Pod spodem dane nie są już jednak wpisane ręcznie w HTML-u. Strona pobiera je dynamicznie.
Dlaczego strona nie zapisuje danych
Warto zaznaczyć jedną rzecz: publiczna strona może tylko czytać rekordy.
Nie ma na niej tokenu do zapisywania danych. To ważne, bo gdyby taki token znalazł się w kodzie strony, każdy mógłby go podejrzeć w przeglądarce.
Zapisywanie rekordów odbywa się z arkusza przez Apps Script. Token potrzebny do zapisu jest schowany po stronie skryptu, a nie w publicznym HTML-u.
To nadal nie jest rozbudowany system uprawnień, ale dla takiego małego projektu jest to sensowny podział:
- strona publiczna czyta dane,
- arkusz z formularzem zapisuje dane,
- Worker pilnuje, żeby zapis był możliwy tylko z poprawnym tokenem.
Problem, który wyszedł po drodze: CORS
Jednym z ciekawszych problemów był CORS.
Najbardziej mylące było to, że endpoint Workera działał po otwarciu bezpośrednio w przeglądarce. Po wejściu na adres Workera widziałem dane. Wszystko wyglądało dobrze.
A jednak strona nie mogła tych danych pobrać.
Problem nie był w bazie. Nie był też w samym Workerze. Blokowała to przeglądarka, bo odpowiedź z Workera nie zawierała informacji, że strona z mojej domeny może odczytać te dane.
To właśnie CORS — mechanizm bezpieczeństwa w przeglądarce, który pilnuje, z jakich domen można odczytywać odpowiedzi.
Rozwiązaniem było dodanie odpowiednich nagłówków w Workerze. Dopiero wtedy strona mogła pobrać rekordy i wyświetlić je u siebie.
Co daje taki układ
Ten projekt jest mały, ale pokazuje bardzo przydatny schemat.
Zamiast budować dużą aplikację, można połączyć kilka prostych elementów:
- arkusz jako miejsce edycji danych,
- skrypt jako automatyzację,
- Workera jako pośrednika,
- bazę jako źródło prawdy,
- statyczną stronę jako widok.
To podejście można wykorzystać nie tylko do rekordów siłowych. Bardzo podobnie można zrobić tabelę rekordów klubu, ranking wyników testów, prostą listę zgłoszeń, panel z danymi treningowymi albo małe narzędzie do publikowania wyników.
Najważniejsze jest to, że nie trzeba od razu zaczynać od dużego systemu. Można zacząć od arkusza, dodać jeden mały automat, później bazę i dopiero na końcu dynamiczną stronę.
Co dalej
W kolejnym wpisie pokażę dokładniej arkusz, który działa jak prosty panel administracyjny: zakładki, konfigurację, log zmian i popup do dodawania rekordów.
To właśnie tam zwykła tabelka zaczyna zmieniać się w narzędzie.