# Architektura Danych I Endpointow Data: 2026-04-29 ## Cel dokumentu Ten dokument podsumowuje ustalenia dotyczace architektury danych pomiedzy: - frontendem Quasar/Vue, - Directusem jako glownym backendem dla frontendu, - FastAPI jako integracja ze starym systemem Mayo. Najwazniejszy problem, ktory rozwiazywalismy: > Ile danych frontend powinien pobierac i trzymac w pamieci oraz jaki ksztalt powinny miec endpointy Directusa, zeby aplikacja byla szybka, czytelna i latwa do dalszej rozbudowy. ## Glowne zalozenie Frontend nie powinien pobierac pelnych danych kazdego produktu na glowna liste. Glowna lista produktow powinna dostawac lekki obiekt przygotowany specjalnie pod widok listy. Pelna specyfikacja i pelny timeline powinny byc pobierane dopiero wtedy, gdy uzytkownik ich potrzebuje. To jest dobre rozwiazanie, bo: - lista produktow bedzie szybciej sie ladowac, - virtual scroll i lazy loading beda prostsze, - frontend nie bedzie trzymal w pamieci danych, ktorych uzytkownik moze nigdy nie otworzyc, - backend moze przygotowac dane dokladnie pod ekran, - komponenty Vue nie musza znac struktury tabel w Directusie. ## Trzy rozne reprezentacje produktu Ten sam produkt moze miec kilka reprezentacji w aplikacji. To nie jest blad ani niepotrzebna duplikacja. To jest normalny podzial danych pod konkretne widoki. ### `ProductListItem` Lekki obiekt do glownej listy produktow. Zawiera tylko dane potrzebne do pokazania karty produktu, filtrowania i szybkiej pracy listy: ```js { id: 101, orderId: '0143/2025/1', orderNumber: '0143', orderYear: 2025, orderIndex: 1, model: 'Regius Core 6', client: 'HIENDGUITAR.COM / INDONESIA', finish: 'S+M', productionLists: ['CZE-00'], timelinePreview: { body: [ { id: 9001, code: 'B', label: 'Bejca', date: '2026-04-20', status: 'done', }, ], neck: [], }, } ``` To jest format, z ktorego korzysta karta produktu na glownej stronie. ### `ProductTimeline` Pelny timeline jednego produktu. Jest pobierany osobno, np. do prawego drawera albo widoku szczegolowego: ```js { productId: 101, events: [ { id: 9001, productId: 101, partId: 501, partType: 'BODY', type: 'operation', operationId: 1, operationCode: 'B', operationName: 'Bejca', date: '2026-04-20', note: null, photosCount: 0, }, { id: 9006, productId: 101, partId: 501, partType: 'BODY', type: 'note', operationId: null, operationCode: null, operationName: null, date: '2026-04-23', note: 'Do sprawdzenia rownomiernosc koloru.', photosCount: 2, }, ], timelinePreview: { body: [], neck: [], }, } ``` Pelny timeline zawiera operacje, notatki i pozniej moze zawierac informacje o zdjeciach. ### `ProductSpecification` Pelna specyfikacja produktu ze starego systemu Mayo. Nie powinna byc czescia `ProductListItem`. Jest pobierana dopiero po otwarciu panelu specyfikacji: ```js { productId: 101, orderId: '0143/2025/1', sourceUrl: 'http://10.8.0.6/mayo2/index.php?...', lastFetchedAt: '2026-04-22T10:30:00Z', sections: [ { key: 'szyjka', label: 'Szyjka', fields: [ { key: 'radius', label: 'Radius', values: ['GITARA SETIUS/REGIUS/CUSTOM/ 16'], }, ], }, ], diff: [], } ``` ## Dlaczego timeline jest w dwoch miejscach Na glownej liscie produktow potrzebny jest tylko skrot timeline: ```js timelinePreview ``` W prawym drawerze albo widoku szczegolowym potrzebna jest pelna historia: ```js events ``` Dlatego mamy dwa poziomy danych: ```txt ProductListItem.timelinePreview szybki skrot na karte produktu ProductTimeline.events pelny timeline do szczegolow ``` To jest dobre rozwiazanie, bo na liscie moze byc duzo produktow. Gdyby kazdy produkt mial pelny timeline, frontend pobieralby i przechowywal duzo danych, ktore czesto nie beda uzyte. ## Czy produkt na liscie powinien miec pelna specyfikacje Nie. Produkt na liscie nie powinien miec pelnej specyfikacji. Powinien miec tylko informacje potrzebne do pokazania karty: - numer zamowienia, - model, - klient, - finish, - listy produkcyjne, - skrot timeline. Pelna specyfikacja powinna byc pobierana przez osobny endpoint po kliknieciu produktu albo otwarciu drawera. ## Rola backendu Directus Directus powinien byc glownym API dla frontendu. Frontend nie powinien skladac produktu z wielu tabel Directusa. Backend powinien przygotowac gotowy ksztalt odpowiedzi pod konkretny ekran. To oznacza, ze zamiast zmuszac frontend do pobierania: ```txt products orders clients models parts events lists ``` lepiej utworzyc custom endpoint: ```http GET /mayo-api/products ``` ktory zwroci gotowe `ProductListItem`. To jest dobre rozwiazanie, bo: - frontend jest prostszy, - mniej logiki laczenia danych jest w Vue, - backend moze zoptymalizowac zapytania SQL, - jeden endpoint odpowiada jednemu widokowi aplikacji, - latwiej utrzymac stabilny kontrakt API. ## Rola FastAPI FastAPI nie powinien byc glownym API dla frontendu. Jego rola to integracja ze starym systemem Mayo: - pobranie specyfikacji po numerze zamowienia, - parsowanie strony starego systemu, - zwrocenie danych Directusowi albo procesowi importu. Docelowy przeplyw: ```txt frontend -> Directus -> FastAPI -> stary system Mayo ``` Frontend powinien jak najczesciej rozmawiac tylko z Directusem. ## Planowane endpointy ### Lista produktow ```http GET /mayo-api/products ``` Parametry: ```http ?limit=30&offset=0&search=regius&finish=GLOSS&year=2025&productionList=CZE-00 ``` Cel: - pobieranie danych do glownej listy, - obsluga virtual scroll i lazy loading, - filtrowanie, - zwrocenie `timelinePreview`. Przykladowa odpowiedz: ```json { "items": [], "pageInfo": { "limit": 30, "offset": 0, "hasMore": true, "total": 184 } } ``` ### Pelny timeline produktu ```http GET /mayo-api/products/:id/timeline ``` Cel: - pobranie pelnej historii produkcji jednego produktu, - uzycie w prawym drawerze albo widoku szczegolowym. ### Dodanie eventu do timeline ```http POST /mayo-api/products/:id/timeline/events ``` Cel: - dodanie operacji, notatki albo innego wpisu produkcyjnego. Backend powinien zwrocic: - utworzony event, - opcjonalnie nowy `timelinePreview`. Dzieki temu frontend moze od razu: - dopisac event do pelnego timeline, - zaktualizowac skrot na karcie produktu. ### Pelna specyfikacja produktu ```http GET /mayo-api/products/:id/specification ``` Cel: - pobranie pelnej specyfikacji jednego produktu, - uzycie w panelu specyfikacji. ### Odswiezenie specyfikacji ```http POST /mayo-api/products/:id/specification/refresh ``` Cel: - Directus prosi FastAPI o pobranie aktualnych danych ze starego systemu, - backend liczy hash/diff, - zapisuje nowa wersje tylko jesli dane sie zmienily, - zwraca aktualny stan specyfikacji. ### Slowniki ```http GET /mayo-api/dictionaries ``` Cel: - pobranie danych do filtrow i formularzy. Przyklady: - modele, - klienci, - finisze, - listy produkcyjne, - operacje, - kolory. ## Virtual scroll i lazy loading Glowna lista powinna dzialac na porcjach danych. Przyklad: ```txt limit = 30 offset = 0 ``` Nastepne pobranie: ```txt limit = 30 offset = 30 ``` Frontend nie powinien pobierac calej bazy tylko dlatego, ze lista nie ma paginacji widocznej dla uzytkownika. Lista moze wygladac jak jedna ciagla lista, ale technicznie powinna pobierac dane porcjami. ## Nazewnictwo `productId` i `orderId` Wazne rozroznienie: ```js productId ``` To wewnetrzne ID produktu w Directusie. ```js orderId ``` To numer starego systemu Mayo, np.: ```txt 0143/2025/1 ``` Nie nalezy uzywac `orderId` jako `productId`. ## Podzial odpowiedzialnosci Docelowy przeplyw: ```txt komponent Vue -> store Pinia -> service API -> Axios albo mock JSON -> Directus ``` Komponent: - renderuje UI, - dostaje dane przez props, - emituje zdarzenia. Store: - trzyma stan, - trzyma loading/error, - zarzadza cache, - decyduje kiedy pobrac dane. Service API: - zna endpointy, - zna Axios, - normalizuje odpowiedzi backendu. Backend: - laczy dane z tabel, - przygotowuje odpowiedz pod frontend, - pilnuje spojnosci danych. ## Dlaczego to jest dobre rozwiazanie Ten podzial jest dobry, bo utrzymuje osobne odpowiedzialnosci: - komponenty nie wiedza nic o Directusie, - store nie musza znac szczegolow Axiosa, - services nie przechowuja stanu, - backend moze zmieniac strukture bazy bez przepisywania calego frontendu, - mock API pozwala pracowac nad wygladem bez gotowego backendu. To jest praktyczny kompromis dla MVP: nie jest przesadnie skomplikowany, ale od razu porzadkuje najwazniejsze granice aplikacji.