---
title: "LeatherMaster"
canonical_url: "https://www.adriannita.pl/projekty/leathermaster"
---

> Index of every page on this site: [llms.txt](https://www.adriannita.pl/llms.txt)

## Zadanie

Zakład z Dąbrówki pod Poznaniem potrzebował strony, która pokaże usługi i metamorfozy przed i po, przyjmie zapisy na szkolenia z płatnością online i da się edytować bez programisty.

## Co zrobiłem

Wszystko sam. Rozmawiałem z właścicielem, zaprojektowałem stronę, napisałem backend w Laravelu, front w Blade i Tailwindzie oraz panel w Livewire, podpiąłem płatności i ustawiłem CI/CD.

## Szczegóły

### Zapisy i płatności

Jednym zapisem można zarezerwować kilka miejsc i podać nazwisko każdego uczestnika. Rezerwacja ma licznik czasu i po nim wygasa, a po opłaceniu klient dostaje plik `.ics` do kalendarza. Dane firmy wypełniają się same po wpisaniu NIP-u. Biorę je z białej listy VAT i trzymam w cache przez 24 godziny, bo API ma dzienny limit zapytań.

Płatności idą przez ING Pay, BLIK-iem albo przelewem. Webhook sprawdza podpis, a odrzuconą lub wygasłą płatność klient może ponowić. Sandbox w kilku miejscach zachowuje się inaczej, niż mówi dokumentacja, więc zapisałem to w README.

### Panel

Usunięte rzeczy leżą w koszu panelu przez 30 dni i można je przywrócić. Każdy rekord ma historię zmian, ekrany wyszukuje się pod ⌘K, a na telefonie menu jest w dolnym pasku.

![Pulpit panelu LeatherMaster: najbliższe terminy szkoleń z liczbą zajętych miejsc i ostatnie zapisy ze statusem płatności (dane przykładowe)](https://www.adriannita.pl/images/projects/leathermaster-panel.webp)

### Bezpieczeństwo

Do panelu loguje się passkeyem i kodem 2FA. Identyfikatory passkeyów podpisuję osobnym sekretem, żeby zmiana `APP_KEY` ich nie unieważniła.

### SEO

Sitemap i dane strukturalne generują się same. Gdy zmieni się adres podstrony, stary przekierowuje 301 na nowy, a wyłączona strona odpowiada 503 z nagłówkiem `Retry-After`.

## Efekt

Strona działa pod adresem [leathermaster.pl](https://www.leathermaster.pl). Właściciel sam zmienia treści i dodaje terminy szkoleń, a zapisy obsługuje w panelu bez mojej pomocy.

## Sitemap

See the full [sitemap](https://www.adriannita.pl/sitemap.md) for all pages.
