Czego się nauczycie?
- Projektowania workflow zgłoszeń (nowe -> w trakcie -> zamknięte)
- Obsługi priorytetów i statusów
- Filtrowania i sortowania danych
- Tworzenia paneli administracyjnych
- Praca zespołowa - podział zadań, współpraca, integracja kodu
Stworzycie System zgłoszeniowy - aplikację webową do przyjmowania i zarządzania zgłoszeniami od użytkowników. Może to być system zgłaszania usterek w szkole, helpdesk IT, formularz kontaktowy z obsługą lub system ticketowy. Użytkownicy mogą tworzyć zgłoszenia z opisem problemu i priorytetem, a operatorzy przeglądać je i zmieniać statusy.
Czego się nauczycie?
W prawdziwej firmie...
Systemy ticketowe to podstawa obsługi klienta i wsparcia technicznego. Jira, Zendesk, Freshdesk, GitHub Issues - wszystkie działają na podobnej zasadzie. Umiejętność projektowania takich systemów jest bardzo ceniona na rynku pracy.
Umiejętności rynkowe
Nauczycie się zarządzania stanami (state machine) - koncepcji używanej w każdej aplikacji biznesowej. Zrozumiecie, jak projektować interfejsy dla różnych typów użytkowników (zgłaszający vs operator).
Formularz zgłoszenia Użytkownik wypełnia formularz z tematem zgłoszenia, szczegółowym opisem, priorytetem (niski/średni/wysoki) oraz danymi kontaktowymi. System automatycznie nadaje numer zgłoszenia i znacznik czasu.
Walidacja i zapis System sprawdza poprawność danych - czy wszystkie wymagane pola są wypełnione, czy priorytet jest prawidłowy, czy email ma poprawny format. Poprawne zgłoszenia są zapisywane do pliku JSON.
Panel przeglądu zgłoszeń Lista wszystkich zgłoszeń z możliwością filtrowania po priorytecie, statusie lub dacie. Kolorowe oznaczenia priorytetów ułatwiają identyfikację pilnych spraw.
Zarządzanie statusami (B/C) W wyższych wariantach operator może zmieniać status zgłoszenia (NOWE -> W TRAKCIE -> ZAMKNIĘTE), co pozwala śledzić postęp obsługi.
Formularz zgłoszenia
Potwierdzenie
Lista zgłoszeń
Panel operatora (B/C)
Przykładowa struktura pliku JSON:
{ "tickets": [ { "id": 1, "ticket_number": "TKT-2026-0001", "subject": "Nie działa projektor w sali 204", "description": "Od rana projektor nie reaguje na przycisk włączania. Pilot ma nowe baterie. Proszę o pilną naprawę - mam prezentację o 12:00.", "priority": "high", "status": "new", "contact_name": "Anna Kowalska", "contact_email": "anna.kowalska@szkola.pl", "created_at": "2026-02-13 08:30:00", "updated_at": "2026-02-13 08:30:00" }, { "id": 2, "ticket_number": "TKT-2026-0002", "subject": "Prośba o nową myszka do pracowni", "description": "Myszka przy stanowisku 5 w pracowni 108 jest uszkodzona - nie działa scroll.", "priority": "low", "status": "in_progress", "contact_name": "Jan Nowak", "contact_email": "jan.nowak@szkola.pl", "created_at": "2026-02-13 09:15:00", "updated_at": "2026-02-13 10:00:00" } ]}Wymagane funkcjonalności:
Struktura plików:
Wszystko z wariantu A, plus:
htmlspecialchars() na wszystkich danych wyjściowychStruktura plików:
Wszystko z wariantu B, plus:
Generowanie numeru zgłoszenia:
<?phpfunction generateTicketNumber(array $tickets): string { $year = date('Y'); $count = count($tickets) + 1; return sprintf('TKT-%s-%04d', $year, $count);}
// Użycie:$ticketNumber = generateTicketNumber($existingTickets);// Wynik: "TKT-2026-0001"Walidacja priorytetu:
<?phpfunction validatePriority(string $priority): bool { $allowed = ['low', 'medium', 'high']; return in_array($priority, $allowed, true);}
function validateStatus(string $status): bool { $allowed = ['new', 'in_progress', 'done']; return in_array($status, $allowed, true);}
// Walidacja wszystkich pólfunction validateTicket(array $data): array { $errors = [];
if (empty($data['subject'])) { $errors[] = 'Temat jest wymagany'; } elseif (strlen($data['subject']) < 5) { $errors[] = 'Temat musi mieć minimum 5 znaków'; }
if (empty($data['description'])) { $errors[] = 'Opis jest wymagany'; } elseif (strlen($data['description']) < 20) { $errors[] = 'Opis musi mieć minimum 20 znaków'; }
if (!validatePriority($data['priority'] ?? '')) { $errors[] = 'Nieprawidłowy priorytet'; }
if (!filter_var($data['contact_email'] ?? '', FILTER_VALIDATE_EMAIL)) { $errors[] = 'Nieprawidłowy adres email'; }
return $errors;}Zmiana statusu zgłoszenia (wariant C):
<?phpfunction updateTicketStatus(int $ticketId, string $newStatus, string $operator): bool { $data = readJsonFile('data/tickets.json');
foreach ($data['tickets'] as &$ticket) { if ($ticket['id'] === $ticketId) { $ticket['status'] = $newStatus; $ticket['updated_at'] = date('Y-m-d H:i:s');
// Dodaj do historii zmian if (!isset($ticket['history'])) { $ticket['history'] = []; } $ticket['history'][] = [ 'status' => $newStatus, 'changed_by' => $operator, 'changed_at' => date('Y-m-d H:i:s') ];
return writeJsonFile('data/tickets.json', $data); } }
return false;}CSS dla chipów priorytetów:
.priority-chip { display: inline-block; padding: 4px 12px; border-radius: 12px; font-size: 0.8em; font-weight: bold; text-transform: uppercase;}
.priority-low { background-color: #e0f2fe; color: #0369a1;}
.priority-medium { background-color: #fef3c7; color: #d97706;}
.priority-high { background-color: #fee2e2; color: #dc2626;}
.status-chip { display: inline-block; padding: 4px 12px; border-radius: 12px; font-size: 0.8em;}
.status-new { background-color: #dbeafe; color: #1d4ed8;}
.status-in_progress { background-color: #fef9c3; color: #ca8a04;}
.status-done { background-color: #dcfce7; color: #16a34a;}JavaScript - walidacja formularza:
document.getElementById('ticketForm').addEventListener('submit', function(e) { const subject = document.getElementById('subject').value.trim(); const description = document.getElementById('description').value.trim();
if (subject.length < 5) { e.preventDefault(); alert('Temat musi mieć minimum 5 znaków'); return false; }
if (description.length < 20) { e.preventDefault(); alert('Opis musi mieć minimum 20 znaków - opisz problem dokładniej'); return false; }});
// Licznik znaków dla opisudocument.getElementById('description').addEventListener('input', function() { const counter = document.getElementById('charCounter'); counter.textContent = this.value.length + ' / 20 minimum'; counter.style.color = this.value.length >= 20 ? 'green' : 'red';});To prawdziwy projekt zespołowy!
Ten projekt to symulacja pracy w firmie IT. System ticketowy to podstawa każdego helpdesku - nauczycie się tworzyć coś, co jest używane w każdej organizacji!
Pracujcie iteracyjnie - lepiej mieć działający wariant A niż niedziałający C!