Typ uczestnika (user_type)
Każdy uczestnik ma w bazie typ — informację, czy jest w klubie nowy, czy wraca po przerwie, i czy sam trenuje, czy jest opiekunem. Ta jedna kolumna decyduje o dwóch rzeczach widocznych na co dzień: czy uczestnik może się zapisać na zajęcia próbne i czy pojawia się na tablicy zadań jako klient do obsłużenia.
👤 Instrukcja dla recepcji i biura
Co widzi klient
W oknie Zapisz się ➔ Zajęcia próbne klient wybiera uczestnika z listy. Uczestnik, który nie może być zapisany, jest wyszarzony i ma przy sobie powód:
| Komunikat | Co oznacza |
|---|---|
| Był(a) już na zajęciach próbnych | Próbne są za nim — odbyte, opłacone albo już umówione |
| Zajęcia próbne niedostępne — napisz na [email protected] | Uczestnik nie ma ustawionego typu, więc system nie wie, kim jest |
| Zaległe płatności | Konto opiekuna jest zawieszone do czasu uregulowania zaległości |
| Trener nie przydzielił jeszcze grupy | Próbne odbyte, czekamy na decyzję trenera |
Drugi komunikat to nie jest normalny stan. Oznacza brak typu i wymaga poprawienia rekordu — klient sam sobie z tym nie poradzi.
Skąd bierze się brak typu
Historycznie kilka ścieżek zakładało uczestnika bez pytania o typ: dopisanie uczestnika przez recepcję z poziomu grafiku, zapisy na półkolonie i kursy tenisa oraz konta lokalne zakładane na miejscu. Takie rekordy trafiały do bazy z pustym typem i wypadały zarówno z zapisów na próbne, jak i z tablicy zadań — nikt w klubie ich nie widział, a klient nie mógł się zapisać.
Od migracji 0255 wszystkie te ścieżki ustawiają Nowy uczestnik, a istniejące
rekordy zostały poprawione. Jeśli mimo to trafisz na uczestnika z tym komunikatem,
ustaw mu typ w profilu uczestnika — wtedy zapis od razu się odblokuje.
Trenerzy to wyjątek
Trener ma własny rekord uczestnika (żeby dało się go rezerwować), ale celowo bez typu. Dzięki temu nie pojawia się na tablicy zadań jako lead i nie dostaje propozycji zajęć próbnych. Nie ustawiaj trenerowi typu uczestnika.
🛠 Dokumentacja techniczna
Model danych
Kolumna player.user_type przyjmuje sześć wartości plus NULL:
| Wartość | Znaczenie |
|---|---|
newParticipant | Nowy, trenuje sam |
newGuardian | Nowy, jest opiekunem |
newParticipantAndGuardian | Nowy, trenuje i jest opiekunem |
returningParticipant | Powracający, trenuje sam |
returningGuardian | Powracający, opiekun |
returningParticipantAndGuardian | Powracający, trenuje i opiekun |
NULL | Rekord trenera — świadomy wyjątek |
Gdzie jest czytana
| Miejsce | Zachowanie przy NULL |
|---|---|
getTrialEnrollmentStatus (shouldPlayerEnrollSkillAssessment.ts) | blockedBy: 'notEligible' → wyszarzony wiersz w wyborze uczestnika |
getPlayersWithoutActivityTypeAndGame (players.ts) | Uczestnik nie trafia na tablicę zadań |
Filtr participantType na liście uczestników | Uczestnik nie pasuje ani do „nowych", ani do „powracających" |
getDefaultActivityStatus w createPlayer | Status aktywny (jak dla uczestnika, nie opiekuna) |
Bramka próbnych sprawdza typ jako pierwszy warunek, przed płatnościami i zapisami,
więc NULL blokuje zapis niezależnie od reszty historii uczestnika. Panel pracownika
tej bramki nie używa — recepcja może zapisać na próbne każdego, co przez długi czas
maskowało problem.
Wartość domyślna
createPlayer rozróżnia brak pola od jawnego null:
- pole pominięte →
newParticipant(uczestnik jest nowy, dopóki klub nie ustali inaczej), user_type: null→ zapisNULL, wyłącznie dla rekordów trenerów (lib/instructor-player.ts).
Dzięki temu nowa ścieżka tworzenia uczestnika nie może już przez przeoczenie wyprodukować rekordu bez typu.
Migracja naprawcza
migrations/0255_backfill_player_user_type.sql ustawia newParticipant wszystkim
rekordom z user_type IS NULL i is_instructor = 0, łącznie z zarchiwizowanymi —
przywrócenie takiego rekordu nie przywraca usterki. Migracja jest idempotentna:
ponowne uruchomienie nie ma już czego poprawić.
Skutek uboczny do zaplanowania z klubem: uczestnicy bez grupy i bez zajęć, którzy wcześniej byli niewidoczni, pojawiają się na tablicy zadań jako leady do obsłużenia.