Skip to content

Mini CRM (kontakty + notatki)

This content is not available in your language yet.

Stworzysz Mini CRM - uproszczony system zarządzania relacjami z klientami. Aplikacja pozwala przechowywać kontakty (imię, email, telefon), dodawać notatki do każdego kontaktu i kategoryzować klientów.

Czego się nauczysz?

  • Tworzenia formularzy CRUD (Create, Read, Update, Delete)
  • Walidacji danych kontaktowych (email, telefon)
  • Pracy z relacjami między danymi (kontakt → notatki)
  • Wyszukiwania i filtrowania
  • Tworzenia prostego interfejsu zarządzania danymi

W prawdziwej pracy...

Systemy CRM (Customer Relationship Management) są podstawą sprzedaży i obsługi klienta w każdej firmie. Salesforce, HubSpot, Pipedrive - wszystkie opierają się na podobnych zasadach. Umiejętność projektowania systemów do zarządzania kontaktami i notatkami jest fundamentem dla każdego programisty aplikacji biznesowych.

  1. Formularz dodawania kontaktu Użytkownik podaje imię, email i telefon nowego kontaktu. Może też dodać kategorię (np. klient, partner, lead).

  2. Walidacja danych System sprawdza poprawność wprowadzonych danych - czy email ma poprawny format, czy telefon zawiera tylko cyfry.

  3. Lista kontaktów Wszystkie kontakty są wyświetlane w formie listy lub tabeli z podstawowymi informacjami.

  4. Notatki do kontaktu Przy każdym kontakcie można dodawać notatki opisujące interakcje (spotkania, rozmowy, ustalenia).

Przykładowa struktura pliku JSON:

{
"contacts": [
{
"id": 1,
"name": "Jan Kowalski",
"email": "jan.kowalski@firma.pl",
"phone": "123456789",
"category": "klient",
"notes": [
{
"id": 1,
"content": "Pierwsza rozmowa - zainteresowany ofertą premium",
"created_at": "2026-02-10 14:30:00"
},
{
"id": 2,
"content": "Wysłano ofertę na email",
"created_at": "2026-02-12 10:00:00"
}
],
"created_at": "2026-02-10 14:00:00"
},
{
"id": 2,
"name": "Anna Nowak",
"email": "anna.nowak@example.com",
"phone": "987654321",
"category": "lead",
"notes": [],
"created_at": "2026-02-11 09:15:00"
}
]
}

Wymagane funkcje:

  • Formularz z polami: imię, email, telefon
  • Walidacja danych w PHP (email, wymagane pola)
  • Lista wszystkich kontaktów
  • Pole notatki przy dodawaniu kontaktu
  • Prosty interfejs CSS

Przykładowy scenariusz:

Użytkownik wpisuje “Jan Kowalski”, email i telefon. Dodaje notatkę “Nowy klient z polecenia”. Po zapisie kontakt pojawia się na liście z notatką widoczną pod danymi kontaktowymi.

Ocena: 3.0

Walidacja danych kontaktowych:

$name = trim($_POST['name'] ?? '');
$email = trim($_POST['email'] ?? '');
$phone = trim($_POST['phone'] ?? '');
if (empty($name)) {
$errors[] = "Imię i nazwisko jest wymagane";
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = "Nieprawidłowy format email";
}
// Walidacja telefonu (tylko cyfry, 9-15 znaków)
$phoneClean = preg_replace('/[^0-9]/', '', $phone);
if (!empty($phone) && (strlen($phoneClean) < 9 || strlen($phoneClean) > 15)) {
$errors[] = "Numer telefonu powinien mieć 9-15 cyfr";
}

Dodawanie kontaktu:

function addContact(array &$contacts, array $data): int {
$newId = empty($contacts) ? 1 : max(array_column($contacts, 'id')) + 1;
$newContact = [
'id' => $newId,
'name' => $data['name'],
'email' => $data['email'],
'phone' => $data['phone'] ?? '',
'category' => $data['category'] ?? 'lead',
'notes' => [],
'created_at' => date('Y-m-d H:i:s'),
];
// Jeśli jest pierwsza notatka
if (!empty($data['note'])) {
$newContact['notes'][] = [
'id' => 1,
'content' => $data['note'],
'created_at' => date('Y-m-d H:i:s'),
];
}
$contacts[] = $newContact;
return $newId;
}

Dodawanie notatki do kontaktu:

function addNote(array &$contacts, int $contactId, string $content): bool {
foreach ($contacts as &$contact) {
if ($contact['id'] === $contactId) {
$noteId = empty($contact['notes']) ? 1 : max(array_column($contact['notes'], 'id')) + 1;
$contact['notes'][] = [
'id' => $noteId,
'content' => trim($content),
'created_at' => date('Y-m-d H:i:s'),
];
return true;
}
}
return false;
}

Edycja kontaktu:

function updateContact(array &$contacts, int $contactId, array $data): bool {
foreach ($contacts as &$contact) {
if ($contact['id'] === $contactId) {
if (isset($data['name'])) {
$contact['name'] = $data['name'];
}
if (isset($data['email'])) {
$contact['email'] = $data['email'];
}
if (isset($data['phone'])) {
$contact['phone'] = $data['phone'];
}
if (isset($data['category'])) {
$contact['category'] = $data['category'];
}
return true;
}
}
return false;
}

Wyszukiwanie kontaktów:

function searchContacts(array $contacts, string $query): array {
if (empty($query)) {
return $contacts;
}
$queryLower = mb_strtolower($query);
return array_filter($contacts, function($contact) use ($queryLower) {
// Szukaj w imieniu
if (strpos(mb_strtolower($contact['name']), $queryLower) !== false) {
return true;
}
// Szukaj w emailu
if (strpos(mb_strtolower($contact['email']), $queryLower) !== false) {
return true;
}
// Szukaj w notatkach
foreach ($contact['notes'] as $note) {
if (strpos(mb_strtolower($note['content']), $queryLower) !== false) {
return true;
}
}
return false;
});
}

Filtrowanie po kategorii:

function filterByCategory(array $contacts, string $category): array {
if (empty($category)) {
return $contacts;
}
return array_filter($contacts, function($contact) use ($category) {
return $contact['category'] === $category;
});
}
function getCategories(): array {
return [
'lead' => 'Lead (potencjalny klient)',
'klient' => 'Klient',
'partner' => 'Partner biznesowy',
'inny' => 'Inny',
];
}

Statystyki kontaktów:

function getContactStatistics(array $contacts): array {
$stats = [
'total' => count($contacts),
'by_category' => [],
'with_notes' => 0,
'total_notes' => 0,
];
foreach ($contacts as $contact) {
$category = $contact['category'] ?? 'inny';
$stats['by_category'][$category] = ($stats['by_category'][$category] ?? 0) + 1;
if (!empty($contact['notes'])) {
$stats['with_notes']++;
$stats['total_notes'] += count($contact['notes']);
}
}
return $stats;
}

Ostatnia aktywność:

function getLastActivity(array $contact): ?string {
if (empty($contact['notes'])) {
return $contact['created_at'];
}
$lastNote = end($contact['notes']);
return $lastNote['created_at'];
}
function sortByLastActivity(array $contacts): array {
usort($contacts, function($a, $b) {
$activityA = getLastActivity($a);
$activityB = getLastActivity($b);
return strcmp($activityB, $activityA); // Malejąco
});
return $contacts;
}

Wykorzystaj lekcje!

Cotygodniowe spotkania podczas lekcji to idealny moment, by:

  • Pokazać postępy - nawet małe kroki się liczą
  • Wyjaśnić wątpliwości - pytaj, nie zgaduj
  • Skonsultować rozwiązania - feedback pomoże Ci się rozwijać

Pracuj iteracyjnie - lepiej mieć działający wariant A niż niedokończony C!