464 testy zanim ruszył panel. CallWithUs & testcontainers.
CallWithUs to multi-tenant SaaS dla call center: wgrywasz leady z pliku xlsx, system je klasyfikuje, robi skrót i routuje do właściwego agenta. Zanim panel pokazał pierwszy ekran, miał 464 testy w 71 plikach, odpalane na prawdziwej bazie Postgres w testcontainers. Ani jednego mocka warstwy danych. Tłumaczę, dlaczego tak buduję i kiedy to przesada.
Co CallWithUs robi
Punkt wejścia to plik. Call center dostaje leady w xlsx (u źródła z systemu Conpeeka), wgrywa go, a CallWithUs parsuje, deduplikuje, klasyfikuje według trzech szablonów i przypisuje do agenta. Do tego dochodzi AI Lead Brief: model Gemini 3.1 Flash Lite robi zwięzły skrót leada, żeby agent nie czytał całego wiersza tabeli. Na końcu jest dispatch, czyli wysyłka do agenta mailem albo formularzem. Stack to Next.js 16, TypeScript w trybie strict i Drizzle nad Cloud SQL.
Dlaczego 464 testy na prawdziwej bazie
Najważniejsza decyzja inżynierska w tym projekcie nie dotyczy frontu ani AI. Dotyczy tego, że testy chodzą na prawdziwym Postgresie w testcontainers, nie na mocku. Powód jest prosty: w aplikacji multi-tenant najgroźniejsze błędy siedzą dokładnie tam, gdzie mock kłamie.
- Izolacja najemców. Czy zapytanie na pewno filtruje po
tenant_idi nie pokaże danych jednego klienta drugiemu. Mock zwróci to, co mu każę. Prawdziwa baza zwróci to, co naprawdę jest w zapytaniu. - Deduplikacja. Lead nie może wejść dwa razy. Mam okno 90 dni i częściowy unikalny indeks, który to wymusza po stronie bazy. To się testuje tylko na bazie, bo to baza pilnuje reguły.
- Transakcje i kolejność. Import to wiele zapisów naraz. Mock nie wyłapie problemu z transakcją ani z kolejnością operacji.
Mock warstwy danych testuje moje wyobrażenie o bazie. testcontainers testuje bazę. Przy 71 plikach testowych pełny przebieg to około 190 sekund. To akceptowalna cena za pewność, że schemat i zapytania faktycznie działają.
Mock danych sprawdza, czy dobrze pamiętasz, jak działa baza. Test na prawdziwej bazie sprawdza, czy baza naprawdę tak działa. Przy danych wielu klientów chcę to drugie.
Ciekawy kontrast z moimi innymi projektami
Piszę dużo o n8n jako backendzie (AdRiser, Workin'Agency). CallWithUs jest świadomie inny: to klasyczna aplikacja w kodzie, bez n8n w środku. Dlaczego. Bo tu logika nie jest „przesuń dane z A do B", tylko twarde reguły biznesowe z izolacją najemców i transakcjami, gdzie chcę typów TypeScriptu, kontroli nad zapytaniami i właśnie tej siatki testów. To dobry przykład, że nie ma jednego słusznego stacku. Dobieram narzędzie pod kształt problemu, nie odwrotnie.
Gdzie to jest dziś (uczciwie)
- Pre-MVP. CallWithUs nie jest jeszcze produktem dla szerokiego rynku. Testy stoją, rdzeń działa, ale to wciąż etap budowy, nie skalowania.
- Zrzut pokazuje dane syntetyczne. Leady na obrazku są wygenerowane na potrzeby demo. Nie pokazuję danych prawdziwych dzwoniących, bo to dane osobowe i nie ma do tego podstaw.
- Testy to nie to samo co produkcja. 464 zielone testy dają mi pewność co do logiki, ale nie zastępują obserwacji systemu pod realnym ruchem. To dwie różne rzeczy i nie udaję, że jedna załatwia drugą.
464 testy nie są wartością same w sobie. Dla prostego CRUD-a byłyby przerostem formy. Mają sens tu, bo cena błędu to wyciek danych między klientami albo zgubiony lead, czyli rzeczy, których nie chcę debugować na produkcji. Liczba testów ma odpowiadać cenie pomyłki, nie ambicji. To samo radzę klientom: nie testuj wszystkiego po równo, testuj mocno tam, gdzie błąd boli najbardziej.
CallWithUs jeszcze dojrzewa i będę o nim pisał, gdy wejdzie w kolejny etap. Jeśli budujesz coś, gdzie dane wielu klientów nie mogą się przemieszać, chętnie pogadam, jak to opakować testami.
Najczęstsze pytania
Po co testować na prawdziwej bazie zamiast mockować?
Bo większość błędów w aplikacji multi-tenant siedzi tam, gdzie mock kłamie: w zapytaniach SQL, indeksach, transakcjach i izolacji danych między najemcami. testcontainers odpala prawdziwego Postgresa w kontenerze na czas testów, więc test sprawdza realny schemat i realne zapytania, a nie moje wyobrażenie o nich.
464 testy dla pre-MVP to nie przesada?
Dla aplikacji, która rozdziela dane wielu klientów i decyduje o routingu leadów, nie. Cena błędu to wyciek danych między najemcami albo zgubiony lead. Testy są tańsze niż taki incydent. Dla prostego CRUD-a faktycznie byłyby przesadą.
Do czego służy AI w CallWithUs?
Model Gemini 3.1 Flash Lite przygotowuje skrót leada (AI Lead Brief) i wspiera klasyfikację według trzech szablonów. To warstwa pomocnicza nad deterministycznym importem i routingiem. Twarde reguły (deduplikacja, przypisanie najemcy) robi kod, nie model.
Budujesz coś, gdzie błąd kosztuje?
Na warsztacie (90 minut, bezpłatny) rozrysujemy proces i wskażemy miejsca, gdzie pomyłka boli najbardziej, te warto opakować testami i obserwowalnością. Reszty nie ma sensu złocić.
Zamów warsztat →