Files
duck-prod-manager/notes/arch_struct.md
bartool 6e3d722e69 dodalem pinia store.
dodalem dokumentacje opisujaca dzialanie store
dodalem services do komunikacji z directus
dodalem opis dzialania services
dodalem mocki danych
przygotowania do refaktoryzacji
2026-04-30 16:49:50 +02:00

8.6 KiB

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:

{
  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:

{
  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:

{
  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:

timelinePreview

W prawym drawerze albo widoku szczegolowym potrzebna jest pelna historia:

events

Dlatego mamy dwa poziomy danych:

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:

products
orders
clients
models
parts
events
lists

lepiej utworzyc custom endpoint:

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:

frontend -> Directus -> FastAPI -> stary system Mayo

Frontend powinien jak najczesciej rozmawiac tylko z Directusem.

Planowane endpointy

Lista produktow

GET /mayo-api/products

Parametry:

?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:

{
  "items": [],
  "pageInfo": {
    "limit": 30,
    "offset": 0,
    "hasMore": true,
    "total": 184
  }
}

Pelny timeline produktu

GET /mayo-api/products/:id/timeline

Cel:

  • pobranie pelnej historii produkcji jednego produktu,
  • uzycie w prawym drawerze albo widoku szczegolowym.

Dodanie eventu do timeline

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

GET /mayo-api/products/:id/specification

Cel:

  • pobranie pelnej specyfikacji jednego produktu,
  • uzycie w panelu specyfikacji.

Odswiezenie specyfikacji

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

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:

limit = 30
offset = 0

Nastepne pobranie:

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:

productId

To wewnetrzne ID produktu w Directusie.

orderId

To numer starego systemu Mayo, np.:

0143/2025/1

Nie nalezy uzywac orderId jako productId.

Podzial odpowiedzialnosci

Docelowy przeplyw:

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.