Podsumowanie Projektu i Wyzwanie Biznesowe
3DPCC to wyspecjalizowana platforma B2B SaaS zaprojektowana w celu automatyzacji wycen, zarządzania produkcją i operacji magazynowych w branży druku 3D. Platforma obsługuje farmy druku 3D oraz profesjonalne firmy drukarskie wymagające scentralizowanego systemu ERP. Moja rola w tym projekcie to Jedyny Architekt i Główny Programista Full-Stack, odpowiedzialny za każdą warstwę systemu.
Projekt został przejęty w momencie, gdy istniejąca architektura natrafiła na ścianę ograniczeń technicznych. Stan wyjściowy: aplikacja posiadała bazę danych Supabase Postgres, ale cała logika opierała się na bezpośrednich zapytaniach frontendowych i pojedynczych Supabase Edge Functions.
Wymaganie biznesowe polegało na przekształceniu kalkulatora w centralny system operacyjny (ERP) dla farm druku 3D — z zarządzaniem organizacjami, obsługą wielu magazynów, deduplikacją klientów i rygorystycznymi procesami rezerwacji stanów.
Problem architektoniczny Serverless / Edge Functions w ERP: rozproszona logika i wywołania Edge Functions uniemożliwiały implementację kluczowych mechanizmów niezawodności. Brakowało zunifikowanej kontroli nad transakcjami wielodomenowymi, możliwości implementacji bezpiecznych mechanizmów retry (z backoff), kolejkowania ani wzorca Transactional Outbox dla zdarzeń. Trudne było egzekwowanie rygorystycznej idempotentności i spójnego kontraktu API dla złożonych operacji biznesowych. Dodatkowy zbędny narzut i złożoność na frontendzie wynikały z SSR (Next.js) w połączeniu z tokenami autoryzacyjnymi przechowywanymi w localStorage.
Jako jedyny programista zaprojektowałem i zaimplementowałem od zera dedykowane, kanoniczne API backendowe Node.js (Modularny Monolit), przejmując całą logikę biznesową i transakcyjną, oraz przepisałem frontend w czyste, wysoko wydajne SPA.
Architektura Backendowa: Modularny Monolit (Node.js 24 LTS)
Wybór padł na Modularny Monolit. W jednoosobowym zespole mikroserwisy generowałyby ogromny narzut DevOps — siatki usług, rozproszone śledzenie, uwierzytelnianie między serwisami i orkiestracja kontenerów to znaczące obciążenia operacyjne przynoszące niewielkie korzyści na tym etapie produktu. Zamiast tego kod biznesowy podzielono na izolowane moduły w jednym repozytorium z jasnymi ograniczeniami zależności.
src/modules/<module>/
├── <module>.routes.ts # HTTP transport & Express routing
├── <module>.schemas.ts # Zod validation contracts (input/output)
├── <module>.service.ts # Use cases & pure domain logic
├── <module>.repository.ts # Drizzle ORM (I/O queries to Postgres)
├── <module>.types.ts # Domain and local types
└── tests/ # Dedicated module integration testsZasady Architektoniczne (Enforced by Design)
- Kanoniczne API biznesowe: Frontend nie wykonuje już bezpośrednich zapytań do Supabase — cała komunikacja przechodzi przez wersjonowane API /api/v1.
- Brak logiki w routerach: Router obsługuje wyłącznie odbiór HTTP, weryfikację nagłówków i walidację wejścia przez Zod.
- Czysta logika w Serwisie: Warstwa serwisowa nie ma żadnych zależności od Express (req/res); jest w 100% testowalnie jednostkowo i zarządza spójnością transakcji.
- Izolacja DB w Repozytorium: Żaden moduł nie może wykonywać bezpośrednich zapytań SQL/Drizzle do tabel innego modułu — komunikacja wyłącznie przez publiczne serwisy.
- Brak zależności cyklicznych: Jawna rejestracja modułów w głównym routerze /api/v1, bez magicznego auto-discovery.
Dogłębna Analiza Modułów Domenowych
1. Magazyn i Rezerwacje Stanów
Stany i korekty: wiele magazynów na organizację (domyślny per org), ograniczona lista stanów i transakcyjne korekty ilości. Zaimplementowany pełny cykl życia rezerwacji stanów: tworzenie, konsumpcja, zwolnienie i wygaśnięcie.
Idempotentność i Concurrency: odcisk palca żądania SHA-256 (na podstawie parametrów + requestId). Ponowienie żądania przy zerwanym połączeniu nie duplikuje rezerwacji ani nie korumpuje stanów magazynowych.
2. Silnik Zamówień
Maszyna stanów: rygorystyczna maszyna stanów zamówień (Szkic → Potwierdzone → W realizacji → Zrealizowane / Anulowane). Przejścia stanów są sprzężone z automatyczną konsumpcją lub zwolnieniem rezerwacji magazynowej w jednej transakcji.
Migawki finansowe: kwoty zamówień źródłowych przechowywane jako liczby całkowite w najmniejszej jednostce walutowej (grosz/cent ISO 4217) — eliminuje błędy zaokrąglania zmiennoprzecinkowego.
3. Identyfikacja i Łączenie Klientów
Kolejka duplikatów: automatyczne wykrywanie potencjalnych duplikatów klientów na podstawie danych kontaktowych i adresowych.
Logiczne scalanie: idempotentny, audytowalny proces scalania rekordów klientów (POST /api/v1/customers/:id/merge), zachowujący historyczną integralność powiązanych zamówień.
4. Entitlementy i Gating Funkcji
System dynamicznie rozwiązuje uprawnienia organizacji na podstawie planów subskrypcji Stripe Billing i przyznanych możliwości (notes.access, inventory.manage itp.). Endpoint /api/v1/entitlements jest jedynym źródłem prawdy dla UI frontendu — LimitMetry, Upselle i bramki RequireEntitlement.
Bezpieczeństwo, Multi-tenancy i Audit Log
Multi-tenancy i Izolacja
Każdy rekord bazy danych zawiera org_id. Wszystkie zapytania Repozytorium automatycznie dołączają WHERE org_id = tenant.orgId, czyniąc wyciek danych między dzierżawcami niemożliwym przez normalne ścieżki kodu aplikacji. Obrona w głąb: polityki Row Level Security (RLS) Supabase Postgres działają jako druga linia obrony przed wyciekiem danych między organizacjami.
Dedykowany Audit Log (audit_records)
Zaprojektowany jako niezmienna tabela Append-Only. Kod aplikacji posiada uprawnienia wyłącznie INSERT — nigdy nie może aktualizować ani usuwać rekordów audytu. Każda krytyczna akcja (akceptacja zaproszenia, zmiana roli, przeniesienie własności organizacji) zapisuje rekord audytu z migawkami before_state i after_state w tej samej transakcji Postgres co operacja biznesowa.
Architektura Frontendu: Przemyślane SPA (React 19 + Vite 8)
Frontend został zmigrowany z SSR (Next.js) do czystej aplikacji jednostronicowej (SPA) zbudowanej na React 19 i Vite 8, odciążając przeglądarkę i eliminując problemy autoryzacyjne. Dla aplikacji dashboardowej B2B, gdzie cała istotna treść jest za uwierzytelnieniem, SSR nie przynosi żadnych korzyści SEO, a wprowadza znaczną złożoność. Podejście SPA zapewnia szybszą iterację, prostsze wdrożenie (pliki statyczne na CDN) i pełną kontrolę nad cyklem renderowania.
Wzorzec 'Two Seams' (Dwa Szwy Architektoniczne)
Aby zapobiec uzależnieniu projektu od konkretnych bibliotek pomocniczych, wprowadzono dwa szwy izolacyjne:
- lib/navigation.ts — jedyny moduł w całej aplikacji importujący react-router. Wszystkie komponenty i widoki nawigują przez ten abstrakcyjny interfejs.
- lib/i18n.ts — jedyny moduł importujący use-intl.
W efekcie zamiana routera lub silnika i18n w przyszłości wymaga modyfikacji dokładnie jednego pliku w projekcie, bez żadnego wpływu na drzewo komponentów.
Obsługa 16 Języków (i18n) i Typowanie ICU
Angielski jest statycznie dołączony do aplikacji, służąc zarówno jako fallback w czasie wykonania, jak i kotwica typów TypeScript dla typu AppMessages — zapewniając, że wszystkie klucze tłumaczeń są bezpieczne typowo w całej bazie kodu. Pozostałe 15 języków ładuje się dynamicznie jako leniwe chunki, wyzwalane wyłącznie przy wykryciu lub zmianie ciasteczka 3dpcc-locale. Dedykowane testy Vitest weryfikują kompletność kluczy i strukturę parametrów ICU we wszystkich 16 plikach JSON lokalizacji.
Proces Inżynieryjny i Jakość (Quality Assurance)
Dokumentacja Decyzji Architektonicznych (ADR)
Projekt jest prowadzony przez 17 formalnych dokumentów ADR dokumentujących każdą istotną decyzję techniczną wraz z jej kontekstem, rozważanymi alternatywami i uzasadnieniem. Kluczowe ADR to ADR-001 Strategia Schematu Drizzle, ADR-009 Cykl Życia Rezerwacji Stanów, ADR-010 Maszyna Stanów Zamówień, ADR-013 Autoryzacja Operatora Platformy i inne. Dokumenty te służą jako pamięć instytucjonalna systemu.
Bramki CI/CD i Testowanie
Trzy niezależne bramki jakości skonfigurowane w GitHub Actions, wyzwalane przy każdym Pull Request:
- Bramka Statyczna i Jednostkowa: ESLint, TypeScript tsc --noEmit, Vitest (testy jednostkowe). Działa całkowicie w procesie bez zewnętrznych zależności.
- Bramka Bazy Danych: Testy integracyjne działające na prawdziwej, skonteneryzowanej instancji Supabase Postgres. Testy generują syntetyczne dane, automatycznie po sobie sprzątają, weryfikując idempotentność, współbieżność i polityki RLS.
- Bramka Produkcyjna: Test budowania i test dymny produkcyjnego kontenera Docker (Node 24 LTS). Zapewnia, że artefakt produkcyjny jest zawsze możliwy do zbudowania i że skonteneryzowana aplikacja uruchamia się poprawnie.
Wyniki i Wartość Biznesowa dla Klienta
Transformacja architektoniczna 3DPCC przyniosła trzy konkretne wyniki biznesowe:
- Uporządkowana architektura procesów: Zastąpienie bezpośrednich zapytań do bazy danych z frontendu kanonicznym backendem biznesowym, co umożliwiło implementację zaawansowanych mechanizmów spójności — idempotentność, maszyny stanów, transakcje.
- Przewidywalność kosztowa: Modularny monolit umożliwia tanie działanie na jednej instancji (Railway/Docker) bez płacenia za utrzymanie złożonej infrastruktury mikroserwisów ani rozproszonych funkcji serverless.
- Gotowość na integracje: Wygenerowane API z pełną dokumentacją OpenAPI 3.1 i stabilnym wersjonowaniem umożliwia szybką integrację z zewnętrznymi sklepami (Etsy, Amazon) i tworzenie aplikacji mobilnych.

