# Bot Microservices: Hasura + Fastify Ten dokument jest kontraktem architektonicznym dla nowych serwisow bota. ## Zasady 1. Zawsze najpierw powstaje dokument kontraktu serwisu, potem implementacja. 2. Hasura jest jedynym source of truth dla danych i stanu wspoldzielonego. 3. Fastify jest shell-em mikroserwisu: HTTP, health, readiness, trigger, observability. 4. Logika domenowa nie siedzi w Fastify handlerach. Jest w czystych modulach `processing`. 5. Serwisy maja byc male i wyspecjalizowane. Kazdy liczy jeden skladnik decyzji albo jedna spojna klase skladnikow. 6. Serwis nie staje sie drugim systemem stanu. Jesli wynik ma byc wspoldzielony, zapisujemy go do Hasury albo wystawiamy przez endpoint. 7. Podzial na mikroserwisy robimy po granicach domenowych i kontraktach danych, nie po pomocniczych funkcjach. ## Model runtime Kazdy serwis ma ten sam ogolny przeplyw: `Hasura GraphQL -> input adapter -> processing -> output adapter -> Fastify endpoint` Warstwy: - `inputs/hasura` - zapytania GraphQL - mapowanie rekordow Hasury do lokalnych struktur - `processing` - czyste funkcje liczace cechy, score, klasyfikacje, gating - `outputs/hasura` - zapis wyniku, eventu, state snapshotu - `transport/http` - Fastify - endpointy health, ready, latest result, admin trigger - `orchestration` - petla, harmonogram, retry, timeouty, kolejnosc krokow ## Rola Fastify Fastify nie jest miejscem na model matematyczny. Fastify odpowiada za: - `GET /healthz` - `GET /readyz` - `GET /result/latest` - `GET /result/:id` - `POST /run` - start i stop serwisu - logowanie i metryki Fastify moze odpalac processing synchronicznie albo przez worker/job, ale sama logika ma pozostac poza transportem. ## Rola Hasury Hasura jest source of truth dla: - konfiguracji bota - snapshotow i tabel pochodnych - wynikow i eventow serwisow - historii potrzebnej do debugowania i replay Mikroserwis: - czyta z Hasury - liczy wynik - opcjonalnie zapisuje wynik do Hasury - opcjonalnie wystawia ten wynik przez HTTP Nie trzymamy osobnego "prawdziwego" stanu tylko w RAM mikroserwisu. ## Granica mikroserwisu Dobry mikroserwis: - ma jeden glowny kontrakt wejsciowy - ma jeden glowny wynik - ma jasny owner danych - da sie niezaleznie uruchomic i przetestowac Zly mikroserwis: - laczy wiele niespojnych modeli w jednym procesie - ma wiele roznych odpowiedzialnosci - staje sie nowym centrum stanu ## Proponowany podzial Minimalne serwisy obliczeniowe: 1. `bot-config-service` - czyta konfiguracje z Hasury - wystawia znormalizowany kontrakt configu 2. `market-snapshot-service` - czyta candles i derived DLOB z Hasury - wystawia ujednolicony snapshot rynku 3. `momentum-service` - liczy `mom_3s`, `mom_10s`, `mom_30s`, `vol_30s` 4. `microstructure-service` - liczy spread, depth, imbalance, slippage 5. `observer-service` - scala wyniki serwisow skladowych - ocenia gate'y - liczy finalny wynik obserwacji - zapisuje event i aktualny state Nie trzeba wdrazac ich wszystkich od razu jako osobne procesy. Najpierw dokumentujemy kontrakty, potem mozemy zaczac od modularnego monolitu i dopiero potem wycinac osobne procesy. ## Czy bloczek modelu zawsze jest osobnym serwisem Nie. Bloczki z modelu matematycznego w `bot1.tex` sa optymalna jednostka dokumentacji i analizy. Nie kazdy bloczek jest jednak optymalna jednostka deploymentu. Zasada: - `bot1.tex` opisuje bloczki matematyczne - kontrakt serwisu grupuje bloczki, ktore maja wspolne wejscie i wspolny wynik runtime - osobny proces wdrazamy dopiero wtedy, gdy taka granica ma sens operacyjny To oznacza, ze: - `momentum + volatility` to dobry jeden serwis, bo oba licza sie z candles - `spread + depth + imbalance + slippage` to dobry jeden serwis, bo wszystkie licza sie z DLOB - `gating + scoring + final observer result` lepiej trzymac razem na poczatku niz rozbijac zbyt drobno - `mom_3s`, `mom_10s`, `mom_30s` jako trzy osobne procesy nie maja sensu ## Rekomendowane granice dla strategii v1 Najbardziej sensowny podzial runtime dla obecnej strategii: 1. `market-snapshot-service` - jeden odczyt z Hasury - candles i derived DLOB 2. `momentum-service` - wszystko liczone tylko z candles - `mom_3s`, `mom_10s`, `mom_30s`, `vol_30s` 3. `microstructure-service` - wszystko liczone tylko z derived DLOB - spread, depth, imbalance, slippage 4. `observer-service` - pobiera wyniki serwisow skladowych albo liczy je lokalnie - ocenia gate'y - liczy score i finalny wynik - zapisuje eventy i state To jest lepsze niz rozbijanie strategii 1:1 po kazdym wzorze, bo: - zmniejsza liczbe round-tripow do Hasury - zmniejsza narzut operacyjny - zachowuje czytelne granice domenowe - nadal pozwala skalowac glowne klasy obliczen niezaleznie ## Zasada "small services" Mniejsze serwisy sa preferowane, bo: - latwiej je skalowac niezaleznie - latwiej je testowac - latwiej je debugowac - latwiej wymienic jeden model bez ruszania reszty Ale "mniejsze" nie znaczy "po jednej funkcji na proces". Jednostka podzialu to: - spojny kontrakt danych - spojna odpowiedzialnosc obliczeniowa - sensowny deployment boundary ## CPU i deployment Mamy duzy zapas CPU, wiec wolno nam preferowac prostsze, bardziej izolowane procesy zamiast upychania wszystkiego do jednego serwisu. To nie zmienia zasad: - nie duplikowac source of truth - nie mieszac transportu z logika - nie rozbijac na mikroserwisy bez kontraktu ## Kontrakt dla nowego serwisu Kazdy nowy serwis powinien miec dokument opisujacy: - nazwe i cel - wejscie z Hasury - wynik obliczen - zapis wyjscia do Hasury - endpointy Fastify - model bledow - SLA petli albo triggera ## Stan biezacy `services/bot-observer` zostal juz przesuniety w dobra strone: - Fastify jako shell - Hasura client osobno - snapshot loader osobno - model decyzji osobno - state/event write osobno Kolejny krok to dalsze cięcie po kontraktach, nie po plikach.