dodalem dokumentacje opisujaca dzialanie store dodalem services do komunikacji z directus dodalem opis dzialania services dodalem mocki danych przygotowania do refaktoryzacji
438 lines
8.6 KiB
Markdown
438 lines
8.6 KiB
Markdown
# 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.
|