Wiki
Stos technologiczny i uzasadnienie wyborow
Dlaczego QuoteNode korzysta z Java, Spring Boot i PostgreSQL oraz jakie kompromisy oznacza to dla hostingu i wydajnosci.
Stos technologiczny i uzasadnienie wyborow
Decyzje technologiczne w QuoteNode wynikaja z bezpieczenstwa, poprawnosci i dlugoterminowej utrzymywalnosci, a nie z pogoni za najnowszym frameworkiem czy minimalnym zuzyciem zasobow.
Ta strona wyjasnia, czego uzywamy, dlaczego wybralismy akurat to i co to oznacza dla deploymentu.
Dlaczego Java 25 i Spring Boot 4
Bezpieczenstwo jako glowny powod
QuoteNode pracuje na wrazliwych danych handlowych: rekordach klientow, strategiach cenowych, negocjacjach ofert i relacjach biznesowych. Stos technologiczny musi byc sprawdzony w srodowiskach, w ktorych blad bezpieczenstwa ma realne konsekwencje.
Java i Spring Boot to domyslny wybor w bankowosci, ubezpieczeniach, ochronie zdrowia i administracji panstwowej — czyli tam, gdzie bezpieczenstwo nie jest opcjonalne. To nie przypadek:
- Dojrzaly model bezpieczenstwa — Spring Security zapewnia sprawdzona i audytowalna warstwe dla uwierzytelniania, autoryzacji, zarzadzania sesja, ochrony CSRF i naglowkow bezpieczenstwa. Nie trzeba budowac tych prymitywow od zera.
- Type safety — silny system typow Javy wychwytuje cale klasy bledow juz na etapie kompilacji, ktore w jezykach dynamicznych stalyby sie bledami runtime. Przy wyliczaniu wartosci ofert, wielowalutowosci, VAT i rabatow to nie jest luksus.
- Memory safety — JVM zapewnia automatyczne zarzadzanie pamiecia przez garbage collection, eliminujac przepelelnienia bufora, use-after-free i inne podatnosci korupcji pamieci znane z C/C++, a czasem tez z ekosystemow Go.
- Dojrzaly ekosystem — biblioteki takie jak Flyway (migracje), Thymeleaf (szablony PDF), Hibernate (ORM) czy Testcontainers (testy integracyjne) sa utrzymywane przez organizacje z dlugim track recordem.
Dlaczego nie Go, Rust albo Node.js
Kazda z tych technologii bylaby rozsadnym wyborem dla innego produktu. Dla QuoteNode konkretnie:
- Go — swietne do uslug sieciowych i narzedzi CLI, ale jego system typow jest slabszy, a modelowanie bardziej zlozonej logiki cenowej oraz deterministycznych obliczen wielowalutowych jest bardziej podatne na bledy. Ekosystem dla potrzeb enterprise (ORM, migracje, renderowanie PDF, frameworki security) jest tez mniej dojrzaly.
- Rust — maksymalizuje wydajnosc i bezpieczenstwo pamieci, ale kosztem szybkosci developmentu i dojrzalosci ekosystemu dla aplikacji biznesowych. QuoteNode to platforma biznesowa typu CRUD-heavy, a nie projekt systems programming. Czasy kompilacji i prog wejscia spowolnilyby rozwoj bez proporcjonalnej korzysci.
- Node.js — bardzo szybki do prototypowania, ale jednowatkowa wspolbieznosc, slabsza dyscyplina typow nawet przy TypeScript oraz rozdrobniony ekosystem czynia go slabszym wyborem dla security-critical platformy z obliczeniami finansowymi. Glebokie drzewo zaleznosci npm zwieksza tez ryzyko supply-chain.
Co to oznacza dla zuzycia zasobow
Aplikacje Java zuzywaja wiecej pamieci niz porownywalne uslugi w Go czy Rust. Backend QuoteNode potrzebuje zwykle 512 MB do 1.5 GB RAM, zaleznie od obciazenia i konfiguracji JVM. To swiadomy kompromis:
- kompilator JIT JVM optymalizuje gorace sciezki po rozgrzaniu, dajac przepustowosc porownywalna z jezykami kompilowanymi natywnie przy stalej pracy,
- pauzy garbage collectora sa pomijalne dla aplikacji single-tenant z typowym obciazeniem B2B,
- dodatkowa pamiec kupuje bogatszy system typow, dojrzale prymitywy security, battle-tested biblioteki i szybszy rozwoj funkcji.
Dla aplikacji self-hosted, single-tenant, obslugujacej jedna organizacje, roznica miedzy 256 MB a 1 GB RAM jest operacyjnie nieistotna. Najtanszy VPS zdolny uruchomic Docker Compose uruchomi tez QuoteNode bez problemu.
PostgreSQL 16
PostgreSQL jest jedyna wspierana baza danych. To decyzja celowa:
- ACID i transakcyjnosc — kazde wyliczenie oferty, zmiana statusu i zapis audytowy dzieja sie w poprawnej transakcji. Implementacja MVCC w PostgreSQL daje silne gwarancje izolacji.
- JSON support — snapshoty ofert sa przechowywane w kolumnach JSONB, co pozwala wydajnie odpytywac historyczne dane ofert bez dodatkowego document store.
- Rozszerzenia —
pgcryptodo serwerowego hashowania,pg_trgmdo wyszukiwania pelnotekstowego po nazwach klientow i produktach. - Niezawodnosc — PostgreSQL ma dekady historii produkcyjnej w systemach finansowych i handlowych.
- Narzedzia backupowe —
pg_dumpw formacie custom pozwala wykonywac spojne backupy online bez zatrzymywania aplikacji.
Szyfrowanie bazy
Wrazliwe pola sa szyfrowane na poziomie aplikacji przy uzyciu AES-256-GCM.
Zawsze szyfrowane (wymagany DB_ENCRYPTION_KEY):
- sekrety TOTP (kody 2FA)
- dane SMTP
Opcjonalnie szyfrowane (gdy ENCRYPT_PII=true):
- PII klientow — nazwy, emaile, telefony, NIP / tax ID
- PII osob kontaktowych — imiona, nazwiska, emaile, telefony
- PII dostawcow — tax ID, email, telefon
- PII kontaktow dostawcow — imiona, nazwiska, emaile, telefony
- PII uzytkownikow — email, imie, nazwisko, numer telefonu
- PII intentow zamowien — nazwa klienta, email, telefon
Gdy szyfrowanie PII jest wlaczone, zapytania exact-match uzywaja blind indexow HMAC-SHA256 przechowywanych obok ciphertextu zamiast zwyklego odpytywania kolumn. Wyszukiwanie pelnotekstowe spada wtedy do pol niebedacych PII (nazwy firm, cache display names). Zapytania typu LIKE po szyfrowanych kolumnach nie sa mozliwe z zalozenia — to swiadomy kompromis na rzecz ochrony danych.
Klucz szyfrujacy jest wyprowadzany z DB_ENCRYPTION_KEY przez SHA-256. Sam klucz nigdy nie trafia do bazy — istnieje tylko w pamieci aplikacji. Produkcyjny validator konfiguracji blokuje start z domyslnym kluczem developerskim. Dodatkowy validator startowy wykrywa niespojnosci miedzy flaga szyfrowania a realnym stanem bazy (na przyklad zaszyfrowane dane przy ENCRYPT_PII=false albo zly klucz) i odmawia startu, zeby zapobiec cichej korupcji danych.
Dostepne sa narzedzia CLI do operacji masowych: --pii-encrypt (zaszyfrowanie istniejacych danych jawnych), --pii-decrypt (powrot do tekstu jawnego) oraz --pii-rekey=<old-key> (przeszyfrowanie nowym kluczem).
Szyfrowanie at-rest dla calej bazy jest delegowane do infrastruktury hostingowej (LUKS, szyfrowane wolumeny EBS i podobne), bo daje lepsza wydajnosc niz szyfrowanie kolumn dla danych masowych.
Frontend Vue 3
Frontend jest aplikacja SPA zbudowana na Vue 3, Vite, PrimeVue 4 i Tailwind CSS 4:
- Vue 3 — reaktywny, komponentowy interfejs z mocnym wsparciem TypeScript i dojrzalym ekosystemem.
- PrimeVue 4 — biblioteka komponentow enterprise z dostepnymi, bogatymi funkcjonalnie tabelami, formularzami i dialogami. To pozwala nie odtwarzac zera zlozonych wzorcow UI.
- Tailwind CSS 4 — utility-first styling z design tokens, co ulatwia utrzymanie spojnego jezyka wizualnego bez przerostu CSS.
- Vite — szybki toolchain z hot module replacement dla lepszej produktywnosci w devie.
- vue-i18n — pelna internacjonalizacja z aktywnym wsparciem dla angielskiego, polskiego, niemieckiego, francuskiego, hiszpanskiego, wloskiego i portugalskiego.
Frontend komunikuje sie z backendem wylacznie przez typowane REST API. Jest serwowany jako statyczne assety przez Caddy i nie ma bezposredniego dostepu do bazy.
Gotenberg
Generowanie PDF wykorzystuje Gotenberg, czyli usluge HTML-to-PDF oparta na Chromium:
- poprawnie renderuje nowoczesny CSS (flexbox, grid, custom properties),
- dziala jako osobny kontener, izolujac sam proces renderowania,
- obsluguje paginacje, custom margins oraz szablony naglowkow i stopek,
- nie wymaga bezposredniej zaleznosci od Chromium w backendzie — integracja odbywa sie przez HTTP API.
Kontener Gotenberg zuzywa zwykle 200-400 MB RAM. Jest aktywny tylko w czasie generowania PDF i moze miec limity zasobow ustawione po stronie Dockera.
Caddy
Caddy 2 pelni role reverse proxy z automatycznym HTTPS:
- automatyczne wystawianie certyfikatow TLS przez Let’s Encrypt,
- wsparcie HTTP/2 i HTTP/3,
- prosty, deklaratywny konfig,
- niski koszt zasobow (~20 MB RAM).
W deploymentach Coolify warstwa TLS jest obslugiwana przez proxy samego Coolify i kontener aplikacji nie potrzebuje oddzielnego reverse proxy.
Laczne wymagania zasobowe
| Komponent | RAM (typowo) | Dysk | CPU |
|---|---|---|---|
| Backend (Java 25) | 512 MB – 1.5 GB | minimalny | 1 rdzen |
| PostgreSQL 16 | 256 MB – 512 MB | 1-10 GB danych | wspoldzielone |
| Frontend statyczny | ~20 MB | ~50 MB | pomijalne |
| Gotenberg | 200-400 MB | ~500 MB | burst only |
| Caddy | ~20 MB | minimalny | pomijalne |
| Lacznie | ~1.5 – 2.5 GB | ~2-12 GB | 2 rdzenie |
VPS z 4 GB RAM, 2 rdzeniami i 20 GB SSD spokojnie uruchomi kompletny stack QuoteNode dla zespolu 10-20 uzytkownikow. To odpowiednik okolo $10-20 miesiecznie — wyraznie mniej niz miesieczny koszt wielu SaaS CRM.
Idealne dla malych i srednich firm
QuoteNode jest projektowany dla organizacji majacych od 1 do 50 uzytkownikow:
- Freelancerow i samodzielnych konsultantow, ktorzy potrzebuja profesjonalnych dokumentow ofertowych bez placenia za enterprise CRM.
- Malych agencji (5-15 osob), ktore chca scentralizowanego zarzadzania klientami i ofertami wraz z widocznoscia pracy zespolowej.
- Srednich firm (15-50 osob) z bardziej uporzadkowana sprzedaza, potrzebujacych analityki pipeline, RBAC i zgodnosci audytowej.
Model self-hosted eliminuje miesieczne oplaty per-seat, a jednoczesnie daje pelna kontrole nad danymi, brandingiem i konfiguracja security. Dla organizacji, ktore juz utrzymuja podstawowa infrastrukture serwerowa albo korzystaja z platform typu Coolify, deployment QuoteNode doklada minimalny narzut operacyjny.
Roadmap jezykowa
QuoteNode wspiera obecnie angielski, polski, niemiecki, francuski, hiszpanski, wloski i portugalski zarowno w UI aplikacji, jak i na wszystkich powierzchniach klientowskich (oferty, PDF-y, publiczne linki, emaile).
Aktualna lista wspieranych jezykow:
- angielski (English)
- polski (Polski)
- niemiecki (Deutsch)
- francuski (Francais)
- hiszpanski (Espanol)
- wloski (Italiano)
- portugalski (Portugues)
Angielski i polski pozostaja obecnie referencyjnie kompletnymi lokalizacjami. Pozostale wspierane jezyki sa juz aktywne w produkcie i sa dalej rozszerzane w warstwie publicznej strony. Dlugoterminowym celem pozostaje pelne pokrycie glownych jezykow europejskich bez potrzeby przebudowy kodu — architektura i18n jest juz przygotowana na taki wzrost.
PDF-y ofert oraz strony linkow publicznych moga juz renderowac sie w dowolnym wspieranym locale niezaleznie od jezyka UI, dzieki czemu da sie prezentowac oferty klientom miedzynarodowym w ich preferowanym jezyku.