Studium przypadku
ContactDock
Bot Telegram, panel Mini App i serverless API, które zamieniają formularz kontaktowy dowolnej strony w wiadomości w Telegramie, bez backendu po stronie witryny. Działa na nim formularz kontaktowy tego portfolio.
- Rola
- Projekt samodzielny: produkt, bot, API, Mini App i wdrożenie
- Okres
- 2026
- Technologie
- Node.jsTelegram Bot APITelegram Mini AppsVercel FunctionsUpstash RedisLuaAES-256-GCMHMAC-SHA256

- testów automatycznych
- 75
- testów automatycznych
- języki: angielski, polski, rosyjski
- 3
- języki: angielski, polski, rosyjski
- pól formularza: 7 standardowych, 5 własnych
- 12
- pól formularza: 7 standardowych, 5 własnych
- dni ważności linku z przypomnieniami
- 90
- dni ważności linku z przypomnieniami
Problem
Formularz kontaktowy musi gdzieś wysyłać zgłoszenia: na serwer pocztowy, do CRM albo do panelu administracyjnego. Dla freelancerów i małych firm to więcej infrastruktury niż sam formularz.
ContactDock przenosi cały proces do Telegrama. Właściciel tworzy link w bocie, wkleja gotowy formularz na stronę, a każde zgłoszenie przychodzi jako wiadomość z przyciskami do jego obsługi.
Co zbudowałem
- Komendy i przyciski bota do tworzenia, odnawiania, testowania i odwoływania linków
- Gotowy formularz HTML dla każdego linku, bez własnych stylów, więc pasuje do strony
- Do 12 pól w formularzu: 7 standardowych i do 5 własnych, wymaganych lub opcjonalnych
- Powiadomienia z przyciskami: oznacz jako w trakcie, zamknij lub skopiuj e-mail
- Panel Mini App z przeglądem, linkami, wyszukiwaniem pełnotekstowym i filtrami po dacie, stronie i statusie
- Eksport przefiltrowanych zgłoszeń do CSV, wysyłany prosto na czat
- Przypomnienia 7 dni i 1 dzień przed wygaśnięciem 90-dniowego linku, wysyłane przez codzienny cron
- Bot i panel po angielsku, polsku i rosyjsku
Ekrany
Architektura
Funkcje serverless na Vercel obsługują formularz strony, webhook bota, API Mini App i codzienne zadanie cron. Cały stan jest przechowywany w Upstash Redis.
01
Punkty wejścia
- Formularz kontaktowy na dowolnej stronie
- Webhook bota Telegram
- Mini App (statyczny HTML, CSS, JS)
- Vercel Cron, codziennie o 09:00 UTC
02
API
- Jedna funkcja Vercel na każdą ścieżkę
- Walidacja originu, pól i rozmiaru
- Limity żądań w atomowym skrypcie Lua
- Weryfikacja podpisu initData Mini App
03
Dane i dostarczanie
- Listy i posortowane zbiory w Upstash Redis
- Zgłoszenia szyfrowane AES-256-GCM
- Wiadomości, przyciski i pliki CSV w Telegramie
Decyzje techniczne
01
Linki, których nie da się podrobić
Każdy link formularza zawiera token podpisany HMAC-SHA256 i powiązany z jedną stroną. Każde zgłoszenie jest też sprawdzane z listą aktywnych linków, więc odwołanie linku działa natychmiast.
02
Szyfrowanie danych
Zgłoszenia są przechowywane w Redis zaszyfrowane AES-256-GCM kluczem wyprowadzonym z sekretu serwera. Starsze, niezaszyfrowane rekordy nadal da się odczytać, więc włączenie szyfrowania nie wymagało migracji.
03
Żadnych zgubionych zgłoszeń
Listy w Redis są zmieniane pojedynczymi elementami przez skrypty Lua z LPOS i LSET, a nie nadpisywane w całości. Zgłoszenie, które przyjdzie podczas zmiany statusu, nigdy nie zostanie nadpisane.
04
Limity przeciw spamowi
5 zgłoszeń na minutę z jednego IP, 30 na minutę i 500 dziennie na link, liczone atomowo w Redis. Ukryte pole-pułapka po cichu odrzuca boty, a żądania większe niż 16 KB są odrzucane.
05
Tylko zaufany ruch z Telegrama
Webhook wymaga sekretnego nagłówka Telegrama, każde żądanie Mini App weryfikuje podpisane initData i wygasa po 24 godzinach, a bot ignoruje czaty grupowe, więc członkowie grupy nie zarządzają cudzymi linkami.
06
Limit 4096 znaków w Telegramie
Gdy zgłoszenie nie mieści się w jednej wiadomości, wyszukiwanie binarne znajduje najdłuższe równe przycięcie wszystkich wartości od odwiedzającego i dodaje notatkę. Pełny tekst zostaje w panelu.
Testy
75 testów działa na wbudowanym test runnerze Node.js z zamockowanym Redis i Telegramem, więc nie potrzebują sieci ani prawdziwych danych dostępowych. Kilka z nich:
- link tokens are bound to the site and reject tampering
- Telegram Web App initData is authenticated and time-limited
- message storage encrypts new records and remains compatible with legacy records
- dashboard status update keeps a submission pushed concurrently
- contact endpoint enforces a daily submission cap per link
- bot ignores group chats so members cannot manage the group links
Chcesz porozmawiać o tym projekcie?
Chętnie omówię kod, kompromisy i to, co zbudowałbym dalej.