Przejdź do treści

Wewnętrzna platforma CRM i operacyjna · 2026

StravoOS

StravoOS to wewnętrzny system, który zbudowałem, żeby prowadzić Stravo — jedna aplikacja zamiast arkusza, notatnika i kalendarza, które nigdy się ze sobą nie zgadzały. Obejmuje cały cykl: lead trafia do systemu, przechodzi przez lejek, staje się klientem z projektami i fakturami, a każdy kontakt po drodze jest zapisywany, więc liczby są wyliczane, a nie wpisywane ręcznie.

19
Modeli danych
11
Modułów
16
Walidowanych modułów akcji
Pulpit StravoOS pokazujący przychód, wartość otwartego lejka, nieopłacone faktury i liczbę nowych leadów, nad panelami z zaległymi follow-upami, dzisiejszymi zadaniami i ostatnią aktywnością.
Pulpit. Wszystkie widoczne wartości to zasiane dane demonstracyjne, a nie rzeczywiste wyniki biznesowe.

Cel

Na czym polegał problem

  • Przestać trzymać ten sam lead w trzech miejscach. Arkusz z prospektami, osobna lista follow-upów i plik z notatkami nie potrafiły odpowiedzieć na jedyne istotne pytanie — które rozmowy właśnie stygną.
  • Sprawić, żeby liczbom dało się ufać. Każda wartość, na podstawie której podejmowałbym decyzję, musiała być wyliczona z zapisanych zdarzeń, a nie utrzymywana ręcznie.
  • Zbudować to tak, żeby dodanie drugiego użytkownika było później zmianą, a nie przepisywaniem systemu od nowa.

Moja rola

Samodzielny projektant i programista. Podejmowałem decyzje produktowe — czym są encje, które moduły zasługują na miejsce, co ma działać w wersji ograniczonej — i intensywnie korzystałem ze wsparcia AI przy ich wdrażaniu.

Co zbudowałem

  • CRM z pełną kartoteką leadów — status, źródło, priorytet, wartość szansy, tagi, obiekcje, powody przegranej — plus wyszukiwanie, filtrowanie, sortowanie, operacje masowe i oś czasu aktywności dla każdego leada.
  • Lejek sprzedażowy typu przeciągnij i upuść, działający na tych samych rekordach leadów. Przeniesienie karty na „Wygrane” zamienia leada w klienta.
  • Analityka kontaktu handlowego wyliczana wyłącznie z zapisanych aktywności: wykres trendu z 30 dni, lejek konwersji, wskaźniki odpowiedzi i umówionych spotkań.
  • Zadania w widoku tablicy, listy i kalendarza, z priorytetami, terminami i zadaniami cyklicznymi, które po zamknięciu tworzą kolejne wystąpienie.
  • Moduł klientów z projektami, elementami do dostarczenia, fakturami, dokumentami i dwustronnym wątkiem wiadomości.
  • Odwoływalny portal klienta bez logowania, oparty na tokenie udostępniania, dający klientowi wgląd w postęp prac i faktury oraz możliwość odpisania.
  • Silnik automatyzacji z wizualnym kreatorem wyzwalaczy i kroków oraz publicznym webhookiem, który kwalifikuje przychodzącego leada, dodaje go do CRM, tworzy zadanie, planuje follow-up i zapisuje powiadomienie — z logiem każdego kroku.
  • Narzędzie do audytu stron, które ocenia adres URL pod kątem SEO, szybkości, UX, zaufania i dostępności oraz eksportuje raport PDF z własnym brandingiem.
  • Strumieniowy asystent AI z dostępem do danych CRM, lejka i kontaktu handlowego, potrafiący tworzyć zadania i notatki.
  • Szyfrowany sejf na dane dostępowe klientów oraz paleta poleceń ⌘K do nawigacji i tworzenia rekordów z dowolnego miejsca.

Ekrany

Tablica lejka sprzedażowego typu przeciągnij i upuść z kolumnami Nowy lead, Kontakt, Zainteresowany, Umówione spotkanie i Oferta wysłana; każda karta pokazuje firmę, osobę kontaktową i wartość szansy.
Tablica lejka i tabela CRM to dwa widoki na jeden rekord Lead. Zasiane dane demonstracyjne.
Ekran analityki kontaktu handlowego z liczbą telefonów, maili, odpowiedzi i umówionych spotkań, wykresem aktywności z 30 dni i lejkiem konwersji z wartościami procentowymi.
Każda liczba tutaj jest wyliczona z logu aktywności, a nie wpisana ręcznie. Zasiane dane demonstracyjne.
Kreator automatyzacji pokazujący adres webhooka formularza na stronie oraz pionową sekwencję kroków: kwalifikacja leada przez AI, dodanie do CRM, utworzenie zadania, zaplanowanie follow-upu i powiadomienie.
Kreator automatyzacji. Formularz na stronie wysyła dane do webhooka, a przepływ wykonuje się po stronie serwera, zapisując każdy krok.
Strona szczegółów leada z danymi kontaktowymi, wartością szansy, źródłem i tagami, obok szybkich akcji do zapisania telefonu, maila, odpowiedzi, spotkania lub notatki oraz datowaną osią czasu aktywności.
Szczegóły leada wraz z osią czasu aktywności. Zasiane dane demonstracyjne.
Portal klienta otwarty przez link do udostępniania, pokazujący postęp projektu, elementy do dostarczenia i faktury, bez konieczności logowania.
Portal klienta, dostępny przez odwoływalny link, bez logowania. Zasiane dane demonstracyjne.

Narzędzia

Aplikacja

  • Next.js 15 (App Router)
  • React 19
  • TypeScript
  • Server Components
  • Server Actions

Dane

  • PostgreSQL
  • Prisma 7
  • Walidacja Zod
  • Supabase Auth

Interfejs

  • Tailwind CSS v4
  • Radix primitives
  • dnd-kit
  • Recharts
  • cmdk

Pozostałe

  • Vercel AI SDK
  • Node crypto (AES-256-GCM)
  • Eksport PDF w Chromium
  • Vercel

Wyzwania

Decyzje warte wyjaśnienia

Trzy widoki, jedna encja

Tabela CRM, tablica lejka i rejestr kontaktu handlowego opisują tych samych prospektów. Potraktowanie ich jako trzech zbiorów danych oznaczałoby trzy miejsca do aktualizacji i trzy okazje do rozbieżności. Wszystkie są widokami na jeden rekord Lead, więc przesunięcie karty na tablicy to ten sam zapis, co zmiana statusu w tabeli.

Liczby, na podstawie których można działać

Statystyki kontaktu handlowego są wyliczane z logu aktywności — telefony, maile, odpowiedzi, spotkania, zmiany statusu — a nie przechowywane jako liczniki. Kosztuje to więcej zapytań, ale oznacza, że wartości nie mogą oderwać się od tego, co faktycznie się wydarzyło, a ten sam log zasila przy okazji oś czasu każdego leada.

Projektowanie pod drugiego użytkownika, zanim on istnieje

Każda tabela ma userId od pierwszej migracji. Ta jedna decyzja sprawia, że obsługa wielu użytkowników i zabezpieczenia na poziomie wiersza są dodatkiem, a nie przepisaniem schematu — rzeczą niemal darmową na starcie i bardzo kosztowną później.

Bezpieczne przyjmowanie niezaufanych adresów URL

Narzędzie audytu pobiera dowolny adres wpisany przez użytkownika, co jest ryzykiem SSRF. Zapytania są sprawdzane, zanim zostaną wysłane, więc narzędzia nie da się skierować na wewnętrzne adresy sieciowe. Dane dostępowe klientów w sejfie są szyfrowane algorytmem AES-256-GCM kluczem, który istnieje wyłącznie w środowisku.

Ograniczanie zamiast psucia

Każda opcjonalna funkcja ma wariant zapasowy. Bez klucza AI kwalifikacja leadów schodzi do heurystyki słów kluczowych, a oferty wracają do szablonów. Bez klucza sejfu sejf jest po prostu niedostępny. Aplikacja działa i jest użyteczna, mając wyłącznie połączenie z bazą danych.

Czego się nauczyłem

  • Decyzje o schemacie są tymi kosztownymi. Błąd w interfejsie poprawia się w jedno popołudnie; wybór, żeby dodać userId do każdej tabeli albo przechowywać kwoty jako liczby całkowite w groszach, to różnica między wieczorem a przepisaniem systemu.
  • Liczba funkcji to nie jakość produktu. Moduły, które zasługują na swoje miejsce, to te, które usuwają ręczny krok — tablica lejka i webhook automatyzacji są używane; moduł, który tylko wyświetla dane, nie jest.
  • Wsparcie AI przyspieszyło pisanie kodu i ani trochę nie przyspieszyło decydowania, co zbudować. Notatki architektoniczne w README repozytorium to część, której broniłbym na rozmowie.
  • Pisanie dokumentacji obnażyło słabe miejsca projektu. Dwa razy zmieniłem schemat, bo wyjaśnienie, które właśnie pisałem, nie trzymało się kupy.

Kod źródłowy

Repozytorium jest prywatne, bo to działający system wewnętrzny. Chętnie przejdę przez kod i schemat na rozmowie albo udostępnię wgląd na życzenie.

Następny projekt

NewLab Systems

Siedmiostronicowa dwujęzyczna witryna dla dystrybutora diagnostyki specjalistycznej, napisana ręcznie, bez frameworka i bez kroku budowania.

Czytaj dalej