ziecina.dev
← Wszystkie projekty
Open sourceDemo na żywoProjekt własny

Build Budget

Kontrola budowy domu: etapy, wydatki na tle budżetu, dokumenty i raporty PDF dla banku.

Rola
Wszystko: produkt, API, frontend, infrastruktura, CI
Stack
Next.js · NestJS · PostgreSQL · Redis
Hosting
Vercel (web) · Railway (API)
Linki
Demo ↗GitHub ↗Kod jest publiczny

Problem

Buduję własny dom, a budowa produkuje mnóstwo informacji: telefony do wykonawców, zdjęcia z placu budowy, rachunki, faktury i pozwolenia. Każdy etap ma swój stos, a w praktyce wszystko było rozrzucone po arkuszach, galerii w telefonie i papierowych segregatorach. Chciałem jednego miejsca, w którym przechowam to wszystko, uporządkowane według etapów i obok budżetu, tak żeby znaleźć wszystko w kilka sekund i udostępnić to każdemu, kto bierze udział w budowie.

Moja rola

Wszystko od początku do końca: zakres produktu, API w NestJS, frontend w Next.js, infrastruktura i CI. Zbudowałem go jako kompletny produkt SaaS, a nie demo CRUD-a: z porządnym logowaniem, płatnościami, zadaniami w tle, przechowywaniem plików i aktualizacjami na żywo.

Co zbudowałem

Budżet dla każdego etapu

Budowa dzieli się na etapy, a każdy etap ma własną stronę z wydatkami, dokumentami, dziennikiem i zadaniami. Wydatki są liczone na tle planowanego budżetu, z wykresem podsumowania i ostrzeżeniem przy każdym etapie, który go przekracza.

Dokumenty i dziennik budowy

Rachunki, faktury i pozwolenia trafiają z przeglądarki prosto do S3 przez presigned URL, więc API nie przepuszcza przez siebie ich zawartości. Każdy etap ma dziennik ze zdjęciami z budowy.

Raporty PDF dla banku

Raporty generują się w tle (Redis, BullMQ, PDFKit), więc ciężki raport nigdy nie blokuje zapytania. Użytkownik pobiera go, gdy jest gotowy.

Współpraca na żywo

Projekt można udostępnić z rolą właściciela albo edytora. Socket.io wysyła zmiany etapów i wydatków do wszystkich, którzy mają projekt otwarty.

Subskrypcje

Stripe Checkout z darmowym planem ograniczonym do jednego projektu. Plan zmienia się wyłącznie przez webhooki weryfikowane podpisem.

Przypomnienia i porównanie kosztów

Codzienne zadanie wysyła e-mailem przypomnienia o zadaniach z terminem w ciągu trzech dni. Nocne zadanie liczy anonimowy koszt m² według regionu i etapu, trzyma go w Redisie i pokazuje na publicznej stronie.

Inżynieria

  • Monorepo: aplikacja Next.js (App Router), API w NestJS i wspólna paczka, dzięki której zasady haseł są zdefiniowane raz dla obu stron.
  • Tokeny JWT (access i refresh) w ciasteczkach httpOnly ustawianych przez route handlery Next.js. Uwierzytelniony proxy po cichu odświeża sesję, a przed pierwszym logowaniem trzeba potwierdzić e-mail.
  • Testy jednostkowe z progiem pokrycia 80% dla plików z logiką oraz testy end-to-end, które uruchamiają prawdziwą aplikację na osobnej bazie. CI odpala jedne i drugie oraz buduje obie aplikacje przy każdym pushu, z Postgresem i Redisem jako kontenerami usług.
  • Wieloetapowy obraz Dockera na node:20-slim, a nie Alpine, bo silnik zapytań Prismy potrzebuje glibc i OpenSSL. Obraz zawiera tylko API.
  • E-maile idą lokalnie przez Mailpit, a na produkcji przez HTTPS API Resend, bo Railway blokuje wychodzący SMTP.
  • Interfejs po polsku i angielsku (next-intl).

Kluczowa decyzja

Rotacja przy każdym odświeżeniuIdempotentne odświeżanie

Naprawa wyścigu przy odświeżaniu tokenu

Każdy panel na stronie projektu pobiera własne dane, więc gdy token dostępu wygasa, kilka zapytań próbuje go odświeżyć w tej samej chwili. Przy rotacji przy każdym odświeżeniu pierwsze zapytanie unieważniało token, którego pozostałe jeszcze używały, i użytkownik był wylogowywany w trakcie pracy. Odświeżanie jest teraz idempotentne: refresh token zmienia się tylko na początku nowej sesji (logowanie, potwierdzenie e-maila), więc równoległe odświeżenia kończą się sukcesem na tym samym tokenie.

Następny projektStajnia Lauden →