Przejdź do treści

Tryb raportowy

Tryb raportowy służy do pobierania dużych wolumenów danych analitycznych, poza modelem transakcyjnym trybu żądaniowego. Integrator zleca wygenerowanie raportu, a wynik trafia asynchronicznie do repozytorium raportów należącego do integratora.

Charakterystyka

  • Tysiące danych analitycznych — wolumeny nieadekwatne dla synchronicznego trybu żądaniowego.
  • W pełni asynchroniczne działanie — zlecenie zwraca 202 Accepted natychmiast, generowanie odbywa się w tle.
  • Szyfrowanie kluczem integracyjnym — wynik szyfrowany end-to-end kluczem publicznym integratora (RSA/AES-GCM), zob. Szyfrowanie.
  • Konfigurowalny cel dostarczenia — wynik trafia do magazynu docelowego wskazanego w zleceniu (pole storage, rodzaj = storage.type): m.in. magazyn obiektowy (Azure Blob Storage), endpoint HTTP integratora (POST), katalog czy udział SMB. W każdym przypadku dane lądują po stronie integratora, nie w infrastrukturze KAMSOFT — KAMSOFT nie przechowuje kopii wyniku. Szczegóły: Cel dostarczenia raportu.

Przepływ informacji

flowchart LR
    I["Aplikacja integratora"]:::integrator -- "Zlecenie" --> A["API.ERP"]:::api
    A <--> D1["FK"]:::domain
    A <--> D2["WMS"]:::domain
    A <--> D3["HR"]:::domain
    A -- "Raport — zapis obiektu" --> R["Magazyn obiektowy"]:::repo
    R -. "odczyt / powiadomienie" .-> I
    A -- "Raport — POST bezpośrednio" --> I

    classDef integrator fill:#8BC34A,stroke:#558B2F,color:#000
    classDef api fill:#03A9F4,stroke:#0277BD,color:#000
    classDef domain fill:#FFA000,stroke:#E65100,color:#000
    classDef repo fill:#FFFFFF,stroke:#333,color:#000

Sekwencja przetworzenia jednego zlecenia raportu:

sequenceDiagram
    participant I as Aplikacja integratora
    participant A as API.ERP
    participant D as Systemy dziedzinowe (FK / WMS / HR / ESM)
    participant R as Repozytorium raportów (integratora)

    I->>A: Zlecenie (POST /v1/reports)
    A-->>I: 202 Accepted + encryptedSessionKey
    A->>D: Pobranie i agregacja danych źródłowych
    D-->>A: Dane źródłowe
    A->>A: Szyfrowanie wyniku (AES-256-GCM + RSA-OAEP)
    alt Magazyn obiektowy
        A->>R: Zapis zaszyfrowanego artefaktu
        R-->>I: Powiadomienie (zdarzenie magazynu / odczyt po runAt)
    else Endpoint HTTP
        A->>I: POST — zaszyfrowany artefakt
        I-->>A: 2xx (potwierdzenie odbioru)
    end

Krok Powiadomienie (magazyn → integrator) odpowiada zdarzeniu gotowości pliku w magazynie integratora (np. zdarzenie Blob Storage po stronie integratora) — API.ERP nie wysyła dodatkowego callbacku; integrator sam nasłuchuje na swoim repozytorium lub odpytuje je po czasie wynikającym z runAt. W wariancie endpoint HTTP potwierdzeniem jest sam kod odpowiedzi 2xx (patrz niżej). Pełny opis zlecenia, szyfrowania i odszyfrowania wyniku: Raporty retrospektywne.

Cel dostarczenia raportu

Cel (magazyn docelowy) wskazuje się per żądanie, w polu storage zlecenia POST /v1/reports; storage.type wybiera rodzaj celu, a pole połączenia zależy od typu. Tryb raportowy obsługuje wszystkie typy — blob, http, local, smb — wg wspólnego modelu: Cel dostarczenia (storage.type). Dane są szyfrowane end-to-end kluczem integratora przed dostarczeniem, a dostarczany artefakt jest identyczny niezależnie od typu (bez osobnego manifestu; tożsamość raportu niesie nazwa pliku). Poniżej dwa najczęstsze warianty.

Magazyn obiektowy (Blob Storage)

API.ERP zapisuje zaszyfrowany artefakt raportu do kontenera wskazanego przez integratora, jako obiekt o nazwie {executionId}-{reportId}.{format} (tożsamość raportu niesie nazwa obiektu). Integrator konsumuje pliki asynchronicznie (nasłuch zdarzeń magazynu lub odczyt po runAt). To dotychczasowy, domyślny tryb.

Cel wskazuje się w polu storage zlecenia (POST /v1/reports):

{
  "storage": {
    "type": "blob",
    "connectionString": "BlobEndpoint=https://<account>.blob.core.windows.net/;SharedAccessSignature=..."
  }
}

Magazyn jest własnością integratora — KAMSOFT zapisuje do niego zaszyfrowany artefakt i nie przechowuje kopii wyniku.

Endpoint HTTP

Zamiast zapisu do magazynu, API.ERP wysyła wynik pojedynczym żądaniem HTTP POST na adres wskazany przez integratora. Jedno wywołanie = jeden gotowy raport.

Cel wskazuje się w polu storage zlecenia — z type: "http". Adres (i opcjonalny statyczny nagłówek Authorization) przekazuje się w connectionString, spójnie z pozostałymi typami:

{
  "storage": {
    "type": "http",
    "connectionString": "https://integrator.example.com/api-erp/report"
    // albo z nagłówkiem: "Url=https://integrator.example.com/api-erp/report;Authorization=<schemat> <wartość>"
  }
}

Uwierzytelnianie a odroczony runAt

W trybie raportowym API.ERP przekazuje wyłącznie statyczny nagłówek Authorization podany w connectionStringnie generuje ani nie odświeża tokenów w chwili dostarczenia. Ponieważ raport bywa planowany na przyszłość (runAt nawet za kilka dni), token krótkotrwały (Bearer/JWT) się nie nadaje — wygaśnie przed dostarczeniem. Użyj poświadczenia ważnego w chwili dostarczenia (np. długoterminowy klucz/API key po stronie odbiorcy) albo endpointu niewymagającego tokenu czasowego. Uwierzytelnianie generowane przy wysyłce jest dostępne w trybie notyfikacyjnym/rozgłoszeniowym, a nie w raportowym.

  • Metoda i adres: POST na jeden, stały URL integratora (z storage.connectionString).
  • Body: zaszyfrowany artefakt raportu (ten sam ładunek, który trafiłby do magazynu — AES-256-GCM, klucz sesyjny zaszyfrowany RSA-OAEP kluczem publicznym integratora). Content-Type: application/octet-stream.
  • Nagłówki żądania:
    • Authorizationstatyczny nagłówek przekazywany bez zmian z storage.connectionString (dowolny schemat); musi być ważny w chwili dostarczenia wg runAt — zob. ostrzeżenie wyżej (token krótkotrwały się nie nadaje);
    • ks-report-execution-id — identyfikator wykonania (executionId); klucz idempotencji i powiązania ze zleceniem (202 Accepted);
    • ks-report-file — nazwa/tożsamość artefaktu ({executionId}-{reportId}.{format}) — odpowiednik nazwy obiektu w magazynie.
  • Manifest nie jest wysyłany — spójnie z magazynem obiektowym (Blob), gdzie również zapisywany jest wyłącznie artefakt; tożsamość raportu niesie nazwa pliku.
  • Odpowiedź: endpoint musi zwrócić 2xx dla powodzenia. Kod inny niż 2xx, brak połączenia lub przekroczenie czasu = niepowodzenie i ponowienie wg polityki retry; treść body błędu jest odczytywana i logowana po stronie API.ERP. Po wyczerpaniu prób zlecenie trafia do obsługi błędów (dead-letter) — zasady wspólne dla trybów wychodzących: Cel dostarczenia → Dostarczanie, ponawianie, idempotencja.
  • Idempotencja: ponowienie oznacza, że integrator może otrzymać ten sam raport więcej niż raz — odbiorca rozróżnia duplikaty po ks-report-execution-id i nie dubluje skutków.

Zarys żądania:

POST /receiveReport HTTP/1.1
Authorization: ApiKey <długoterminowy-klucz>
Content-Type: application/octet-stream
ks-report-execution-id: 8f3c1a20-...-e065
ks-report-file: 8f3c1a20-...-e065-cost-calculation-2026-07.csv

<zaszyfrowany artefakt raportu (bajty)>

Odbiorca odszyfrowuje artefakt kluczem prywatnym odpowiadającym PublicKeyPem przekazanemu w zleceniu (patrz Raporty retrospektywne).

Pełny kontrakt endpointu odbiorczego w formacie OpenAPI 3.0: API-ERP-Report-Receiver.yaml.

Ten sam wynik, różne cele

Wszystkie rodzaje celu (storage.type) to warianty tego samego dostarczenia — dostarczany artefakt jest identyczny niezależnie od typu (bez osobnego manifestu; tożsamość raportu niesie nazwa pliku). Cel wskazuje się w zleceniu polem storage (rodzaj = type, dane połączenia zależne od typu); zestaw dostępnych typów bywa ograniczany ustaleniami integracji.

Kiedy używać

Tryb raportowy pasuje do eksportów analitycznych, zestawień okresowych i danych o wolumenie zbyt dużym dla pojedynczej odpowiedzi HTTP w trybie żądaniowym — np. raporty kalkulacji kosztów, dane do systemów ankietowania czy badań klinicznych, gdzie kluczowe są przewidywalne okna czasowe (runAt) i szyfrowanie end-to-end, a nie natychmiastowa reakcja na pojedyncze zdarzenie (do tego służy tryb rozgłoszeniowy).

Odniesienia