Case Study

Przejęliśmy Projekt CRM Napisany przez AI — Od Prototypu do Produkcji

Przejęcie projektu CRM wygenerowanego przez AI i doprowadzenie go do produkcyjnej jakości. Diagnoza, decyzje architektoniczne, zakres przepisania i wnioski dla firm korzystających z aplikacji tworzonych przez sztuczną inteligencję.

Punkt wyjścia: CRM napisany przez AI

Klient z branży handlowej zwrócił się do nas z prośbą o przejęcie wewnętrznego narzędzia typu CRM, wspierającego pracę zespołu handlowego. Aplikacja została wygenerowana w całości z pomocą AI (Claude): backend oraz frontend napisane w JavaScript, Node.js po stronie serwera, SQLite jako warstwa danych. W środowisku demonstracyjnym aplikacja wyglądała kompletnie — logowanie, listy klientów, formularze i podstawowe raporty działały zgodnie z oczekiwaniami. Zakres zlecenia został pierwotnie sformułowany jako wdrożenie gotowej aplikacji na serwer produkcyjny.

Przed akceptacją zakresu prac przeprowadziliśmy wstępny audyt kodu oraz zachowania aplikacji w różnych scenariuszach użycia. Wynik audytu istotnie zmienił zakres projektu.

Powtarzalny wzorzec: aplikacje generowane przez AI często poprawnie obsługują scenariusz podstawowy (happy path), lecz nie zostały zweryfikowane w warunkach odbiegających od niego. Klient biznesowy zazwyczaj nie ma narzędzi, by samodzielnie stwierdzić, że otrzymany produkt jest w istocie prototypem wymagającym dodatkowych prac inżynierskich.

Diagnoza: zakres faktycznie działającej funkcjonalności

Po przeprowadzeniu audytu stwierdziliśmy, że poprawnie obsługiwany jest wyłącznie podstawowy scenariusz użycia — i to z zastrzeżeniami. Odchylenia od tej ścieżki skutkowały nieobsłużonymi wyjątkami. Poniżej kluczowe ustalenia z audytu:

  • Brak obsługi błędów i walidacji po stronie backendu — niepoprawne dane wejściowe (pusty formularz, nieoczekiwany typ danych, błąd sieci) powodowały awarię żądania
  • Walidacja realizowana wyłącznie po stronie frontendu — backend akceptował dane w formie, w jakiej zostały przesłane, bez dodatkowej weryfikacji
  • SQLite zakodowany na sztywno — ścieżka do pliku bazy umieszczona w kodzie źródłowym, bez mechanizmu konfiguracji
  • Tryb diagnostyczny wbudowany w logikę aplikacji — flagi DEBUG ustawione na wartość true bezpośrednio w plikach źródłowych, bez możliwości przełączenia z poziomu konfiguracji
  • Pełne dane diagnostyczne w odpowiedziach HTTP — stack trace wyjątków dostępny dla użytkownika końcowego, co stanowi również problem bezpieczeństwa
  • Brak migracji schematu bazy danych — struktura tabel istniała wyłącznie w pliku .sqlite na stacji programistycznej, bez możliwości odtworzenia na innym środowisku
  • Sekrety w repozytorium kodu — klucze API, hasła oraz tokeny dostępowe zakomitowane w plikach konfiguracyjnych
  • Pokrycie testowe ograniczone do jednego scenariusza — w repozytorium znajdował się wyłącznie skrypt weryfikujący najprostszą ścieżkę użycia
Prototyp a produkt: aplikacja sprawiała wrażenie rozwiązania gotowego do wdrożenia, lecz w rzeczywistości stanowiła prototyp. Typowe zdarzenia produkcyjne — utrata połączenia, równoległe operacje wielu użytkowników, nietypowe znaki w danych wejściowych — skutkowały błędami niemożliwymi do obsłużenia bez gruntownych zmian w kodzie.

Uzasadnienie decyzji o przepisaniu backendu

Rozważaliśmy scenariusz refaktoryzacji istniejącego kodu jako opcję tańszą niż przepisanie od podstaw. Szczegółowa analiza wykazała jednak, że struktura źródeł nie pozwala na stopniowe wprowadzanie poprawek — kod nie posiadał punktów zaczepienia umożliwiających sensowną dekompozycję:

Brak separacji warstw

Logika biznesowa, warstwa dostępu do danych oraz obsługa HTTP znajdowały się w tych samych plikach. Pojedyncza funkcja łączyła parsowanie żądania, zapytania SQL i budowanie odpowiedzi.

Brak możliwości testowania

Zależności były wstrzykiwane bezpośrednio wewnątrz funkcji. Uniemożliwiało to podmianę bazy danych, zegara czy klienta HTTP na implementację testową — każdy test wymagałby uruchomienia pełnego środowiska.

Brak separacji środowisk

Aplikacja korzystała z tej samej konfiguracji niezależnie od środowiska. Nie istniał mechanizm pozwalający przełączyć połączenie z bazą, poziom logowania ani parametry diagnostyczne.

Niezgodność ze stackiem klienta

Infrastruktura docelowa klienta oparta jest o Nginx oraz PHP. Wdrożenie aplikacji Node.js wymagałoby dodatkowego komponentu w stacku operacyjnym i generowałoby koszty utrzymania.

Istotne ustalenie analizy: nawet w przypadku utrzymania platformy Node.js backend wymagałby napisania od podstaw, aby spełniać wymagania utrzymaniowe i rozwojowe. Przy porównywalnym nakładzie pracy wybraliśmy technologię zgodną ze stackiem klienta — PHP 8.5 i Symfony 8.0. Zgodność ze stackiem docelowym przekłada się na niższe koszty infrastruktury, spójność ze znanym klientowi środowiskiem operacyjnym oraz szerszą dostępność specjalistów do dalszego rozwoju.

Wniosek: kod wygenerowany przez AI nie zawsze posiada strukturę pozwalającą na skuteczną refaktoryzację. W wielu przypadkach przepisanie od podstaw okazuje się tańszą i szybszą opcją niż próba adaptacji szkieletu, który nie został świadomie zaprojektowany.

Warstwa prezentacji: zakres zmian po stronie frontendu

Jakość warstwy frontendowej była zdecydowanie wyższa niż backendowej. Interfejs użytkownika został zrealizowany poprawnie — kod wygenerowany przez AI okazał się w tym obszarze gotowy do produkcyjnego wykorzystania po wprowadzeniu niewielkich korekt.

Elementy, które zachowaliśmy bez istotnych modyfikacji:

  • Struktura komponentów oraz podział na widoki
  • Obsługa stanów interfejsu — wskaźniki ładowania, stany puste, komunikaty powodzenia
  • Układ, stylowanie oraz responsywność
  • Walidacja formularzy po stronie klienta (jako pierwsza warstwa weryfikacji — drugą wprowadziliśmy po stronie backendu)

Wprowadzone zmiany miały charakter ograniczony: rozszerzenie obsługi błędów zwracanych przez API o czytelne komunikaty, drobne korekty walidacji oraz aktualizacja adresów punktów końcowych w związku z migracją backendu do Symfony.

Obserwacja: warstwa prezentacji jest obszarem, w którym AI dostarcza wyniki o satysfakcjonującej jakości. Istotne problemy pojawiają się w obszarach wymagających świadomych decyzji architektonicznych — trwałości danych, logiki domenowej, integracji zewnętrznych oraz zarządzania środowiskami.

Nowa architektura: PHP/Symfony z bazą MariaDB

Implementację poprzedziło zaprojektowanie warstwowej architektury aplikacji — etap, który w poprzedniej wersji projektu nie został zrealizowany. Kod wygenerowany przez AI pełnił funkcję działającego prototypu, lecz nie posiadał struktury pozwalającej na długoterminowe utrzymanie.

1

Warstwa kontrolerów

Kontrolery Symfony przyjmują żądania HTTP, walidują dane wejściowe z wykorzystaniem komponentu Symfony Validator i delegują realizację logiki do warstwy usług. Kontroler operuje wyłącznie na obiektach domenowych — nie posiada wiedzy o strukturze bazy danych.

2

Warstwa usług (service layer)

Logika biznesowa — reguły przypisywania klientów do opiekunów, etapy procesu sprzedażowego, obliczanie wskaźników — znajduje się w dedykowanych klasach usługowych. Każda z nich jest testowalna jednostkowo, bez konieczności uruchamiania bazy danych.

3

Warstwa dostępu do danych

Doctrine ORM wraz ze wzorcem repozytorium. Zapytania do bazy danych są skupione w repozytoriach właściwych dla konkretnego bytu (np. ClientRepository), co ułatwia ich lokalizację, modyfikację oraz optymalizację.

4

Migracje schematu

Doctrine Migrations — każda zmiana struktury bazy danych zapisana jest w dedykowanym pliku migracji pod kontrolą wersji. Odtworzenie schematu na dowolnym środowisku realizowane jest pojedynczą komendą.

5

Konfiguracja środowiska

Zmienne środowiskowe w plikach .env oraz profile Symfony (dev, prod, test). Sekrety pozostają poza repozytorium, tryb diagnostyczny wyłączany jest na środowisku produkcyjnym z poziomu zmiennych środowiskowych.

Warstwę danych przenieśliśmy z SQLite na MariaDB. SQLite stanowi odpowiednie rozwiązanie dla prototypów i aplikacji jednoużytkownikowych, jednak w systemie CRM wykorzystywanym jednocześnie przez wielu użytkowników ograniczenia związane z blokowaniem bazy oraz brak wsparcia dla części zapytań istotnie wpływały na stabilność i wydajność systemu.

Architektura jako fundament utrzymaniowy: świadome decyzje architektoniczne przekładają się na koszt i możliwość utrzymania aplikacji w perspektywie kilkuletniej. Tego poziomu decyzji AI samodzielnie nie podejmie — wymaga on kontekstu biznesowego oraz oceny wymagań pozafunkcjonalnych, których narzędzie nie posiada.

Automatyczny deployment i gotowość produkcyjna

Proces wdrożenia w poprzedniej wersji aplikacji sprowadzał się do ręcznego skopiowania plików na serwer oraz uruchomienia procesu aplikacyjnego. Nie przewidziano mechanizmu migracji bazy danych, rozgrzewania cache ani możliwości wycofania zmian. Wprowadziliśmy w jego miejsce skryptowy proces wdrożeniowy, wykonujący każdą aktualizację w sposób atomowy:

  • Budowa nowego wydania w katalogu releases/<timestamp>/, niezależnym od aktualnie produkcyjnej wersji
  • Instalacja zależności (composer install --no-dev) oraz rozgrzanie cache Symfony
  • Wykonanie migracji schematu bazy danych oczekujących na zastosowanie
  • Przełączenie dowiązania symbolicznego current na nowe wydanie — operacja wykonywana atomowo
  • Kontrolowane przeładowanie procesu PHP-FPM
  • Procedura wycofania zmian realizowana pojedynczą komendą — dowiązanie symboliczne zostaje przywrócone na poprzednie wydanie

Równolegle wprowadzone zostały elementy nieobecne w pierwotnej wersji projektu: rozdzielenie konfiguracji środowisk, wyłączenie trybu diagnostycznego na środowisku produkcyjnym z poziomu zmiennych środowiskowych, obsługa błędów prezentująca neutralny komunikat użytkownikowi końcowemu oraz przeniesienie sekretów do pliku .env.local poza repozytorium.

Wymagania wobec procesu wdrożeniowego: każdy deployment powinien być powtarzalny, audytowalny oraz odwracalny. Brak tych właściwości oznacza, że aplikacja nie jest gotowa do wdrożenia produkcyjnego, niezależnie od jakości jej działania w środowisku demonstracyjnym.

Weryfikacja scenariuszy użycia wykraczających poza podstawowy

Pokrycie testowe w pierwotnej wersji projektu ograniczało się do pojedynczego skryptu weryfikującego podstawową ścieżkę działania aplikacji. Przyjęliśmy bardziej systematyczne podejście do weryfikacji jakości:

Krok 1

Mapowanie scenariuszy użycia

Przygotowanie pełnej listy ścieżek użytkownika w oparciu o funkcjonalności aplikacji: scenariusze podstawowe, błędy walidacji, stany puste, wyjątki sieciowe oraz konflikty wynikające z współbieżnego dostępu.

Krok 2

Testy jednostkowe logiki biznesowej

Pokrycie testami PHPUnit warstwy usług — reguły przypisywania klientów, etapy lejka sprzedażowego, kalkulacja wskaźników. Każda usługa objęta testami ścieżek zasadniczych oraz przypadków brzegowych.

Krok 3

Testy integracyjne

Testy kontrolerów uruchamiane na dedykowanym środowisku testowym z rzeczywistą instancją MariaDB. Weryfikacji podlega pełny cykl przetwarzania żądania: kontroler, warstwa usług, repozytorium, baza danych, odpowiedź.

Krok 4

Weryfikacja manualna przypadków brzegowych

Scenariusze, których automatyzacja nie przynosi proporcjonalnych korzyści: pusty wynik wyszukiwania, utrata połączenia w trakcie zapisu, równoległa edycja tego samego rekordu. Weryfikacja wykonywana według udokumentowanej listy kontrolnej.

Efekt końcowy: w ramach projektu klient otrzymał zarówno działającą aplikację, jak i dokumentację obejmującą listę przetestowanych scenariuszy wraz z wynikami weryfikacji. Dokumentacja stanowi podstawę dla przyszłych zmian funkcjonalnych i pozwala na kontrolowane rozszerzanie zakresu testów.

Rezultaty projektu

Aplikacja pierwotnie działała wyłącznie w warunkach demonstracyjnych. Po zakończeniu prac stanowi ona stabilne narzędzie pracy zespołu handlowego, gotowe do dalszego rozwoju funkcjonalnego oraz skalowania liczby użytkowników. Poniżej szacunkowe podsumowanie zakresu zmian:

Wszystkie
scenariusze pokryte testami
pierwotnie: wyłącznie ścieżka podstawowa
~6 tyg
łączny czas przejęcia
backend, wdrożenie oraz testy
kilkadziesiąt
błędów krytycznych naprawionych
nieujawnionych w wersji demo
100%
gotowość produkcyjna
pierwotnie: wbudowany tryb diagnostyczny

Kluczowym efektem projektu, wykraczającym poza same wskaźniki ilościowe, jest przywrócenie kontroli nad procesem rozwoju aplikacji. Obecność testów automatycznych, migracji bazy danych oraz procedury wycofania zmian pozwala klientowi wprowadzać modyfikacje w sposób bezpieczny i kontrolowany — bez ryzyka regresji w obszarach niezwiązanych bezpośrednio z wprowadzaną zmianą.

Nasze podejście do AI: narzędzie pod nadzorem inżynierskim

Opisane powyżej problemy nie stanowią podstawy do ogólnego sceptycyzmu wobec narzędzi sztucznej inteligencji. W CodeRoll aktywnie korzystamy z AI w codziennej pracy — Claude Code stanowi podstawowe narzędzie wspierające pisanie kodu, Gemini wykorzystujemy do zastosowań o bardziej ogólnym charakterze. Istotą odpowiedzialnego wykorzystania tych narzędzi jest odpowiednie umiejscowienie ich w procesie wytwórczym.

  • AI wspiera pracę programisty, nie zastępuje decyzji projektowych. Wykorzystujemy je do generowania kodu powtarzalnego, pierwszych wersji komponentów, szablonów testów oraz do eksploracji możliwych rozwiązań.
  • Kod wygenerowany przez AI podlega recenzji inżynierskiej. Traktujemy go analogicznie do kodu napisanego przez programistę na wczesnym etapie rozwoju — wartościowego jako punkt wyjścia, wymagającego weryfikacji i często korekty przed włączeniem do projektu.
  • Sztuczna inteligencja posiada ograniczoną zdolność oceny własnych rozwiązań. Wygenerowana aplikacja może działać poprawnie w scenariuszu demonstracyjnym, a jednocześnie zawierać istotne braki — brak walidacji danych wejściowych, sekrety w repozytorium, nieadekwatny dobór warstwy danych. Identyfikacja takich problemów wymaga doświadczenia produkcyjnego.
  • Decyzje architektoniczne, kwestie bezpieczeństwa oraz gotowość produkcyjna pozostają w gestii inżyniera. AI dostarcza szkielet rozwiązania; kontekst biznesowy oraz wymagania utrzymaniowe definiuje zespół projektowy.
Nasze stanowisko: aplikacje generowane w całości przez AI należy traktować jako prototypy, a nie gotowe produkty. W zdecydowanej większości przypadków wdrożenie takiego rozwiązania do środowiska produkcyjnego wymaga udziału doświadczonego inżyniera — uzupełnienia architektury, scenariuszy pominiętych przez model oraz elementów związanych z bezpieczeństwem i utrzymaniem. Nie jest to ograniczenie technologii, a jej naturalna rola: AI stanowi narzędzie wspierające proces wytwórczy, nie zastępuje kompetencji inżynierskich.

Kiedy warto rozważyć usługę „AI rescue”?

Poniższe sygnały wskazują, że aplikacja wygenerowana przez AI wymaga przejęcia przez doświadczony zespół inżynierski przed wdrożeniem produkcyjnym:

  • Aplikacja działa w środowisku demonstracyjnym, lecz zawodzi przy pierwszych realnych użytkownikach — charakterystyczny objaw pokrycia ograniczonego do ścieżki podstawowej
  • Wymagane jest wdrożenie produkcyjne, lecz brak zdefiniowanego procesu — brak procedury wdrożeniowej, migracji schematu bazy oraz konfiguracji środowisk
  • Zastosowana warstwa danych jest nieadekwatna do docelowej infrastruktury — np. SQLite lub przechowywanie danych po stronie klienta, podczas gdy serwer docelowy wyposażony jest w MySQL, MariaDB lub PostgreSQL
  • W aplikacji występują błędy, a ich diagnoza przekracza kompetencje osoby, która zleciła jej wygenerowanie — typowe w sytuacji, gdy projekt powstał bez udziału programisty
  • Aplikacja działa wyłącznie w środowisku lokalnym autora — ścieżki zakodowane na sztywno, niezmapowane zależności systemowe
  • Brak testów lub pokrycie ograniczone do scenariusza podstawowego — uniemożliwia bezpieczne wprowadzanie zmian funkcjonalnych
  • Sekrety zakomitowane do repozytorium kodu — wymaga niezwłocznej rotacji kluczy oraz uporządkowania konfiguracji

Zakres prac realizowanych w ramach usługi

  • Audyt kodu źródłowego oraz architektury wraz z raportem stanu projektu
  • Przepisanie backendu lub jego części z dostosowaniem do wymagań produkcyjnych
  • Zaprojektowanie warstw aplikacji, wprowadzenie testów oraz migracji schematu bazy
  • Konfiguracja środowisk, skrypty wdrożeniowe oraz podstawowy monitoring
  • Zabezpieczenie sekretów, walidacja danych wejściowych, obsługa błędów
  • Dokumentacja scenariuszy testowych oraz procesu wdrożeniowego

Podsumowanie

Narzędzia oparte o sztuczną inteligencję znacząco obniżyły próg wejścia w tworzenie aplikacji — rozwiązania, których wytworzenie wymagało dotychczas zespołu programistów, mogą obecnie powstawać przy znacznie mniejszych zasobach. Jednocześnie obserwujemy wzrost liczby projektów stanowiących prototypy o pozornej gotowości produkcyjnej, niespełniających wymagań utrzymaniowych ani bezpieczeństwa.

Kod wygenerowany przez AI nie wymaga odrzucenia. W opisywanym projekcie warstwa prezentacji została zachowana w zdecydowanej większości — jakość kodu frontendowego okazała się satysfakcjonująca. Przepisania wymagał backend, nie ze względu na ograniczenia AI, lecz ze względu na charakter obszaru: warstwa serwerowa wymaga świadomych decyzji architektonicznych, których generator kodu samodzielnie nie podejmuje.

Wnioski wynikające z projektu:

  • Aplikacje wygenerowane przez AI należy traktować jako prototypy; wdrożenie produkcyjne wymaga udziału inżyniera
  • Warstwa frontendowa AI osiąga satysfakcjonującą jakość; warstwa backendowa wymaga weryfikacji inżynierskiej
  • Stos technologiczny aplikacji powinien być dostosowany do infrastruktury klienta, a nie odwrotnie
  • Gotowość produkcyjna obejmuje nie tylko kod aplikacji, lecz również proces wdrożeniowy, pokrycie testowe, konfigurację środowisk oraz monitoring
  • Oszczędność czasu wynikająca z wykorzystania AI jest realna, lecz nie zwalnia z weryfikacji inżynierskiej

W przypadku projektu wygenerowanego przez AI, który nie spełnia oczekiwań produkcyjnych, zachęcamy do kontaktu. Umówienie darmowej konsultacji pozwoli nam ocenić stan kodu oraz określić, które elementy można zachować, a które wymagają gruntownych zmian.

Projekt wygenerowany przez AI wymaga przejęcia?

Świadczymy usługi w zakresie AI rescue — przejmujemy aplikacje wygenerowane przez sztuczną inteligencję i doprowadzamy je do jakości produkcyjnej. Zakres obejmuje architekturę, pokrycie testowe, procesy wdrożeniowe oraz bezpieczeństwo. Umów darmową konsultację, podczas której ocenimy stan Twojego projektu i przedstawimy rekomendacje dalszych działań.

Umów darmową konsultację