Case study · 2026

Liga Astra: liga tenisowa, która sama publikuje wyniki

Amatorska liga tenisowa Klubu Astra przeniosła się z WordPressa, Arkuszy Google i osadzonych dashboardów na szybką stronę statyczną z małym panelem administracyjnym, dzięki któremu każdy zapisany wynik aktualizuje publiczne tabele i ranking klubowy.

Klient
Klub sportowy, liga amatorska
Status
Działa
Zakres
Projekt i budowa strony, model danych, panel administracyjny, newsletter, przejście z WordPressa

Zobacz stronę: liga.tenisgrodzisk.pl (otwiera się w nowej karcie) liga.tenisgrodzisk.pl

Strona główna Ligi Astra na ekranie komputera: nagłówek Amatorska liga tenisowa Klubu Astra na tle kortu o zmierzchu, przyciski do tabel i rankingu klubowego oraz liczniki zawodników, rozegranych meczów i lig.
Strona główna Ligi Astra na telefonie: logo klubu, przycisk menu, nagłówek ligi i dwa przyciski jeden pod drugim.

Problem

Strona ligi działała na WordPressie, ale prawie nic w niej nie korzystało z WordPressa. Każda podstrona ligowa pokazywała pięć okienek z jednego Arkusza Google, wyciętych według wpisanych na sztywno zakresów komórek. Rankingi pochodziły z dwóch kolejnych arkuszy, strona główna i strony z historią były dashboardami Looker Studio, a wyniki przesyłano przez osadzony Formularz Google.

Takie rozwiązanie rodziło konkretne problemy:

  • Zawierało błędy w danych. Audyt działającej witryny ujawnił wiersze z nieistniejącymi zawodnikami, tabelę ligową sprzeczną z wprowadzonymi wynikami i kolumnę rankingu, która każdemu odwiedzającemu pokazywała błąd arkusza.
  • Było niewidoczne dla wyszukiwarek. Treści z osadzonych arkuszy nie da się zaindeksować, a na telefonach same tabele przewijały się niezależnie od reszty strony. A tabela ligi to dokładnie to, czego zawodnicy szukają.
  • Nie miało pamięci. Każda runda nadpisywała poprzednią, więc historia istniała tylko w dashboardach.
  • Było kruche. Każda zmiana składu wymagała ręcznej podmiany linków do arkuszy w WordPressie, a do 25 z 41 zaindeksowanych stron w ogóle nie dało się dojść z menu.

Podejście

Zanim cokolwiek zaproponowaliśmy, spisaliśmy, z czego tak naprawdę składa się obecny serwis, podstrona po podstronie. Tańszą opcję, czyli zostawienie arkuszy i pobieranie z nich danych podczas generowania widoku, wyceniliśmy i odrzuciliśmy, bo przeniosłaby do nowej wersji wszystkie dotychczasowe problemy.

Klub wybrał bazę danych jako jedno źródło prawdy. Resztę ukształtowały trzy decyzje:

  • Wprowadzenie błędnych danych ma być niemożliwe, a nie tylko mało prawdopodobne. Mecz musi wskazywać dwóch prawdziwych zawodników, a tabela jest liczona z wyników, a nie wpisywana obok nich, więc nigdy nie może im przeczyć.
  • Publiczna strona zostaje statyczna. Odwiedzający dostają proste, szybkie strony. Baza danych nie jest bezpośrednio dostępna z internetu; strona jest z niej przebudowywana, gdy coś się zmienia.
  • Przebudowujemy tylko to, z czego ludzie korzystają. Odtworzyliśmy 16 stron z menu, a pozostałe stare adresy przekierowujemy.
Strona ligi przed i poDwie kolumny. Przed: wyniki przesyłane przez Formularz Google, jedna zakładka arkusza na ligę nadpisywana co rundę, pięć osadzonych okienek na stronie ligi, dashboardy Looker Studio jako jedyna historia, wszystko pokazywane na stronach WordPressa. Po: wyniki wpisywane na telefonie po podaniu kodu, panel administracyjny dla organizatora, jedna baza ligi, która liczy tabele, statyczna strona przebudowywana z tej bazy i cotygodniowy mail z wynikami zatwierdzany przez organizatora.PrzedWyniki przesyłane przez Formularz GoogleJedna zakładka arkusza na ligę,nadpisywana co rundęPięć osadzonych okienek na stronie ligiDashboardy Looker Studio jako jedynearchiwum wynikówWokół tego strona w WordPressieNieindeksowalne, niewygodne na telefonie ipodatne na wzajemnie sprzeczne dane.PoWyniki wpisywane na telefonie z krótkimkodemPanel administracyjny dla organizatoraBaza ligi: tabele liczone z wynikówStatyczna strona generowana bezpośrednio zbazyCotygodniowy mail z wynikami, zatwierdzanyprzez organizatoraDane w tabelach muszą zgadzać się z wynikami.jedno źródłoprawdy ozawodnikachi wynikachStrona ligi przed i poDwie kolumny. Przed: wyniki przesyłane przez Formularz Google, jedna zakładka arkusza na ligę nadpisywana co rundę, pięć osadzonych okienek na stronie ligi, dashboardy Looker Studio jako jedyna historia, wszystko pokazywane na stronach WordPressa. Po: wyniki wpisywane na telefonie po podaniu kodu, panel administracyjny dla organizatora, jedna baza ligi, która liczy tabele, statyczna strona przebudowywana z tej bazy i cotygodniowy mail z wynikami zatwierdzany przez organizatora.PrzedWyniki przesyłane przez Formularz GoogleJedna zakładka arkusza na ligę, nadpisywana corundęPięć osadzonych okienek na stronie ligiDashboardy Looker Studio jako jedyne archiwumwynikówWokół tego strona w WordPressieNieindeksowalne, niewygodne na telefonie i podatne nawzajemnie sprzeczne dane.jedno źródło prawdy ozawodnikach i wynikachPoWyniki wpisywane na telefonie z krótkim kodemPanel administracyjny dla organizatoraBaza ligi: tabele liczone z wynikówStatyczna strona generowana bezpośrednio z bazyCotygodniowy mail z wynikami, zatwierdzany przezorganizatoraDane w tabelach muszą zgadzać się z wynikami.
Przeczytaj diagram jako tekst
  1. Przed: Wyniki przesyłane przez Formularz Google, potem Jedna zakładka arkusza na ligę, nadpisywana co rundę, potem Pięć osadzonych okienek na stronie ligi, potem Dashboardy Looker Studio jako jedyne archiwum wyników, potem Wokół tego strona w WordPressie. Nieindeksowalne, niewygodne na telefonie i podatne na wzajemnie sprzeczne dane.
  2. jedno źródło prawdy o zawodnikach i wynikach
  3. Po: Wyniki wpisywane na telefonie z krótkim kodem, potem Panel administracyjny dla organizatora, potem Baza ligi: tabele liczone z wyników, potem Statyczna strona generowana bezpośrednio z bazy, potem Cotygodniowy mail z wynikami, zatwierdzany przez organizatora. Dane w tabelach muszą zgadzać się z wynikami.

Wdrożenie

  • Strona publiczna. Tabele lig, siatki wyników, terminarze, strony zawodników, ranking klubowy kobiet i mężczyzn, statystyki i regulamin, łącznie 32 strony. Nawigację i szerokie tabele zaprojektowaliśmy najpierw z myślą o telefonach: wysuwane menu zamiast menu otwieranego po najechaniu kursorem i siatka wyników przewijana w bok z przypiętymi nazwiskami.
  • Panel administracyjny. Po polsku, dla jednego organizatora: tworzenie rundy przez wklejenie składów (terminarz generuje się sam), edycja i łączenie zawodników, przenoszenie zawodnika między ligami z podglądem tego, co się zmieni, import starych sezonów z CSV i drukowanie pustych terminarzy na A4.
  • Wpisywanie wyników z telefonu. Osoba wpisująca wyniki otwiera jeden publiczny adres i podaje kod złożony z trzech polskich słów. Telefon zostaje zapamiętany, a kod otwiera siatkę wyników i nic więcej.
  • Publikacja. Zapisanie wyniku uruchamia przebudowę witryny, a zmiany są widoczne publicznie po około dwóch minutach. Strona diagnostyczna w panelu wyjaśnia krok po kroku, dlaczego zapisany wynik jeszcze się nie pojawił.
  • Cotygodniowy newsletter. W każdy poniedziałek podsumowanie wyników jest przygotowywane automatycznie i wysyłane mailem do organizatora, który je zatwierdza albo odrzuca. Bez tej zgody nic nie wychodzi. Listę subskrybentów odzyskaliśmy ze starej wtyczki WordPressa, zachowując status zgody każdej osoby.
  • Regulamin jako osobne podstrony. Zasady przenieśliśmy z osadzonego PDF-a na czytelne strony z linkiem do każdego punktu, więc można je znaleźć w wyszukiwarce i zacytować w wiadomości.
  • Przełączenie, które dało się cofnąć. Nowa strona najpierw działała pod prywatnym adresem. Wdrożenie sprowadzało się do zmiany dwóch nazw katalogów z opcją automatycznego cofnięcia zmian, a starą instalację WordPressa zachowaliśmy w osobnym katalogu na wszelki wypadek, zamiast ją usuwać.
  • Kontrola przy każdej zmianie. Testy automatyczne sprawdzają poprawność danych, parser wyników i zgodność eksportu z PHP ze stroną, a przy każdym wdrożeniu weryfikowane są wszystkie linki wewnętrzne.
Od zapisanego wyniku do publicznych tabelPięć kroków: wpisanie wyniku na telefonie, zapis i weryfikacja, przeliczenie tabel na podstawie wyników, wygenerowanie strony z nowych danych oraz aktualizacja publicznych tabel i rankingu. Całość trwa około dwóch minut.CzłowiekWynik wpisanyna telefoniekod z trzechsłówZapisany isprawdzonyw jednejtransakcjiTabeleprzeliczonez wyników, nigdynie wpisuje sięich ręcznieStronawygenerowanana nowo zdanychautomatyczniePublicznetabelezaktualizowaneok. 2 minutyOd zapisanego wyniku do publicznych tabelPięć kroków: wpisanie wyniku na telefonie, zapis i weryfikacja, przeliczenie tabel na podstawie wyników, wygenerowanie strony z nowych danych oraz aktualizacja publicznych tabel i rankingu. Całość trwa około dwóch minut.CzłowiekWynik wpisany na telefoniekod z trzech słówZapisany i sprawdzonyw jednej transakcjiTabele przeliczonez wyników, nigdy nie wpisuje się ich ręcznieStrona wygenerowana na nowo z danychautomatyczniePubliczne tabele zaktualizowaneok. 2 minuty
Nikt nie naciska przycisku publikacji. Jeśli wynik się nie pojawił, strona Publikacja w panelu pokazuje, który krok go zatrzymuje.
Przeczytaj diagram jako tekst
  1. Człowiek: Wynik wpisany na telefonie (kod z trzech słów)
  2. Zapisany i sprawdzony (w jednej transakcji)
  3. Tabele przeliczone (z wyników, nigdy nie wpisuje się ich ręcznie)
  4. Strona wygenerowana na nowo z danych (automatycznie)
  5. Publiczne tabele zaktualizowane (ok. 2 minuty)

Efekt

  • Nowa strona działa od 17 września 2026 roku i zastąpiła WordPressa, osadzone arkusze, Formularz Google i dashboardy Looker Studio.
  • Tabele i ranking klubowy są liczone z wyników, więc błędy i niespójności ze starej strony już się nie powtórzą.
  • Organizator prowadzi ligę z jednego panelu, a wyniki wpisane z telefonu trafiają na publiczne strony bez naciskania żadnego przycisku.
  • Strony lig są czytelne na telefonie i prawidłowo indeksują się w wyszukiwarkach.
  • Główne zdjęcie na stronie startowej jest serwowane jako responsywny WebP: telefon pobiera wersję 19 kB zamiast oryginału o wadze 2,6 MB.
Od przeglądu do ligi, która publikuje się sama, 2026Oś czasu: 9 wydarzeń, od 30 sie do 13 paź.30 siePrzegląd starej strony;wybór bazy danych31 sieStart paneluadministracyjnego ieksportu danych4 wrzPierwsze wdrożenietestowe; newsletter;import CSV9 wrzImport prawdziwychdanych ligi10 wrzLink do formularzawyników dla sędziów iorganizatorów11 wrzKody z trzech słów;narzędzia doprzełączenia17 wrzStart21 wrzRegulamin w formiepodstron serwisu13 paźPoniedziałkowy szkicwysyłany dozatwierdzeniaOd przeglądu do ligi, która publikuje się sama, 2026Oś czasu: 9 wydarzeń, od 30 sie do 13 paź.30 siePrzegląd starej strony; wybór bazy danych31 sieStart panelu administracyjnego i eksportudanych4 wrzPierwsze wdrożenie testowe; newsletter;import CSV9 wrzImport prawdziwych danych ligi10 wrzLink do formularza wyników dla sędziów iorganizatorów11 wrzKody z trzech słów; narzędzia doprzełączenia17 wrzStart21 wrzRegulamin w formie podstron serwisu13 paźPoniedziałkowy szkic wysyłany dozatwierdzenia
Daty pochodzą z historii commitów i pull requestów projektu.
Przeczytaj diagram jako tekst
  1. 30 sie: Przegląd starej strony; wybór bazy danych
  2. 31 sie: Start panelu administracyjnego i eksportu danych
  3. 4 wrz: Pierwsze wdrożenie testowe; newsletter; import CSV
  4. 9 wrz: Import prawdziwych danych ligi
  5. 10 wrz: Link do formularza wyników dla sędziów i organizatorów
  6. 11 wrz: Kody z trzech słów; narzędzia do przełączenia
  7. 17 wrz: Start
  8. 21 wrz: Regulamin w formie podstron serwisu
  9. 13 paź: Poniedziałkowy szkic wysyłany do zatwierdzenia

Wnioski

Problem ze stroną małego klubu to często bałagan w danych, który tylko wygląda na problem z wyglądem. Kiedy pojawiło się jedno wiarygodne źródło informacji o zawodnikach i wynikach, bez trudu udało się stworzyć szybką stronę, tabele wygodne do przeglądania na telefonie oraz zautomatyzować cotygodniowy newsletter.

Technologie
Astro, Tailwind CSS, TypeScript, Zod, PHP, MariaDB, GitHub Actions
Rodzaj
Strategia i wdrożenie
  • website
  • sports
  • league
  • admin-panel
  • newsletter
  • wordpress-migration
  • static-site
  • mobile-first

Umów 30-minutową rozmowę

Opowiedz nam o jednym procesie. Powiemy, czy automatyzacja coś w nim zmieni i ile pracy by to wymagało.