dodalem pinia store.
dodalem dokumentacje opisujaca dzialanie store dodalem services do komunikacji z directus dodalem opis dzialania services dodalem mocki danych przygotowania do refaktoryzacji
This commit is contained in:
437
notes/arch_struct.md
Normal file
437
notes/arch_struct.md
Normal file
@@ -0,0 +1,437 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user