Konwencje techniczne
Konwencje API są zbieżne z założeniami REST API – Założenia v1.0 (pharmind XF). Poniżej zastosowanie tych założeń w API.ERP — tak, jak jest wdrożone; elementy oznaczone „do doprecyzowania” nie mają jeszcze ustalonej postaci.
1. Założenia ogólne
- Kontrakt jest anglojęzyczny. Ścieżki, nazwy pól, wartości kodowane, opisy (
description) i komunikaty błędów są po angielsku. - Wyjątkiem są dane i nazwy czytelne w słownikach (
display, np.active→ „Aktywny") — te opisują treść dziedzinową i pozostają po polsku. - Ten przewodnik jest po polsku; język dokumentacji nie jest językiem kontraktu.
2. Adresy bazowe (Base URL)
| Element | Opis (do uzupełnienia) |
|---|---|
| Wzorzec URL | Np. https://<środowisko>.<domena>/api — do doprecyzowania |
| Środowiska | Produkcja, test, dev — do uzupełnienia |
| Uwagi | Punkt wejścia API, ewentualne prefixy — do doprecyzowania |
3. Nazewnictwo endpointów
3.1 Ogólne zasady
- Nazwy zasobów: proste, czytelne, odzwierciedlające reprezentowane dane.
- Rzeczowniki w liczbie mnogiej:
/parties,/purchase-requisitions,/posting-instructions. - Liczba pojedyncza tylko dla zasobów jednoelementowych:
/metadata.
3.2 Konwencje zapisu
- Kebab-case w ścieżkach:
/product-definitions,/purchase-orders,/inventory-documents. - Brak czasowników w endpointach — operacje reprezentują metody HTTP.
- Operacje na kolekcji (pełna lista tras: Kontrakty API):
GET /v1/<resource>— wyszukiwanie; zasób wskazuje parametridentifier=system|valuePOST /v1/<resource>— utworzenie; treść niesieidentifier[].system(przestrzeń wymagana,valueopcjonalne)PATCH /v1/<resource>?identifier=system|value— aktualizacja- Brak tras z
{id}oraz brak operacjiPUTiDELETE.
3.3 Operacje niestandardowe
- Prefiks
$na kolekcji:GET /v1/fixed-asset-documents/$document-content?identifier=…&format=…. Karta wdrożenia wymienia operację wrest[].resource[].operation[]z adresem definicjihttps://api-erp.kamsoft.pl/ns/OperationDefinition/<name>(karta wdrożenia).
3.4 Hierarchia zasobów
- Brak zagnieżdżeń w ścieżkach — powiązania wyraża się filtrami:
/v1/journal-entries?postingInstruction=…,/v1/party-roles?party=….
3.5 Parametry zapytań
- camelCase:
lastModified,issueDateFrom,issueDateTo,employeeId,productGroupId. - Wartości kodowane i identyfikatory jako para
system|value(np.identifier,owner,type,status); atrybuty jakocode|value. - Parametry jednoznaczne.
3.6 Bezpieczeństwo
- Nie umieszczać wrażliwych danych w ścieżkach endpointów.
4. Wersjonowanie API
- Wersja w ścieżce:
/v1/parties,/v1/purchase-orders. - Numeracja wersji: liczby całkowite (1, 2, 3…).
- Zasady zmian (breaking vs non-breaking, deprecation) — do uzupełnienia.
5. Autentykacja
- Model: Do uzupełnienia: np. OAuth 2.0, API key — wybór i uzasadnienie.
- Przepływ: Np. client credentials, resource owner — do doprecyzowania.
- Nagłówek:
Authorization: Bearer <token>(lub inny schemat po doprecyzowaniu). - Rejestracja aplikacji: Gdzie i w jakiej formie — do doprecyzowania.
6. Nagłówki HTTP
| Nagłówek | Wartość / uwagi |
|---|---|
| Authorization | Bearer <token> |
| Content-Type | application/json (request: POST/PATCH) |
| Accept | application/json (response) |
| Własne nagłówki | Prefiks ks-; małe litery, wyrazy oddzielone myślnikami (np. ks-report-execution-id w trybie raportowym). Spójnie w całym API. |
| Inne | Idempotency key, request-id — do doprecyzowania |
6.1 Zakres żądania: klient i instalacja
Wywołanie nie niesie identyfikacji klienta. Instancja API.ERP pracuje zawsze dla jednego klienta i to ona go wyznacza.
W instalacji klienta może pracować kilka systemów źródłowych. Odczyt ma trzy tory — rozstrzyga je para zawężeń profile i identifier:
| Co podaje integrator w odczycie | Kto odpowiada |
|---|---|
parametr profile |
tylko pierwszy w kolejności system honorujący ten profil; pozostałe nie są odpytywane |
parametr identifier=system\|value (przestrzeń OID) |
wyłącznie instalacja wskazana tą przestrzenią; gdy nie prowadzi tego zasobu albo profilu — 404 |
ani profile, ani identifier |
wszystkie instalacje rozumiejące ten zasób; odpowiedź jest złączeniem ich wyników |
Zapis (POST, PATCH) rozstrzyga się inaczej: dziedzinę wyznacza profil (meta.profile albo profil rozpoznany po treści), a przestrzeń identyfikatora — gdy podana — wskazuje instalację przyjmującą zapis (musi należeć do miejsca prawdy profilu, w przeciwnym razie 404); bez przestrzeni zapis idzie do pierwszego systemu w kolejności.
Kolejność systemów jest parametrem wdrożenia od opiekuna integracji KAMSOFT i nie wynika z żadnego endpointu — nie niesie jej ani GET /v1/metadata, ani GET /v1/naming-systems.
Przestrzenie identyfikatorów w odpowiedzi należą do instalacji, która żądanie obsłużyła. Szerzej: Identyfikacja i parametry wdrożenia.
7. Metoda PATCH (aktualizacja)
- Przestrzeń identyfikatora jest opcjonalna w
POST(identifier[].system;valuenadaje system prowadzący): podana wskazuje instalację, pominięta — rozstrzyga profil (rejestracja zasobu). WPATCHparametridentifier=system|valuewskazuje zasób do zmiany, więc jest konieczny. - Jeden endpoint PATCH na zasób, na kolekcji:
PATCH /v1/parties?identifier=system|value&owner=https://gov.pl/nip|<NIP>,PATCH /v1/fixed-asset-documents?identifier=…,PATCH /v1/document-references. - Cel wskazuje parametr
identifier=system|value(przestrzeń wewnętrzna instalacji); dla DocumentReference cel wynika zidentifier[]w treści. - Body: pełny zasób w postaci kanonicznej (ten sam model co w
POST); nie tablica operacji. - Content-Type:
application/json. Odpowiedź:200 OKz zasobem po stronie systemu prowadzącego. - Zasoby z PATCH: Party, FixedAssetDocument, DocumentReference (zmiana statusu dokumentu magazynowego) — Kontrakty API.
8. Paginacja i filtrowanie
- Mechanizm:
count(liczba elementów strony, domyślnie 20) ioffset(liczba pominiętych elementów, domyślnie 0):GET /v1/parties?count=50&offset=100. - Odpowiedź kolekcji: koperta
{ "items": [ … ], "nextToken": null };nextTokenjest zarezerwowany na kursor i obecnie zawszenull— kolejną stronę pobiera się zwiększającoffset. - Brak wyników:
200 OKzitems: []. - Filtrowanie: parametry zapytań w camelCase (p. 3.5); sortowanie nie jest parametryzowane.
8.1 Filtr podany jest stosowany albo odrzucany
- Zbiór parametrów wyszukiwania zasobu w danej instalacji wymienia karta wdrożenia (
rest[].resource[].searchParam[], karta). Każdy parametr z karty jest obsługiwany — nie ma parametrów przyjmowanych bez efektu. - Filtr kodowany (
category,type,statusi pokrewne) ma postaćsystem|value. Wartość jest rozpoznawana po każdym słowniku, który karta deklaruje dla tego zasobu i parametru, a nie po jednym wybranym. systemspoza tych słowników kończy się400z nazwą parametru wdetail. Filtr nigdy nie jest po cichu pomijany.- Kod nieznany w rozpoznanej przestrzeni to sytuacja danych, nie błąd żądania:
200 OKzitems: []. - Gdy filtr został podany, odpowiedź zawiera wyłącznie zasoby, które go spełniają — niezależnie od tego, która instalacja żądanie obsłużyła.
Zasób może mieć dla jednego parametru więcej niż jeden słownik; obie przestrzenie są wtedy poprawne:
GET /v1/product-definitions?category=https%3A%2F%2Fapi-erp.kamsoft.pl%2Fvs%2Fwarehouse%2Fproduct-definition-category%7Cmedications
GET /v1/product-definitions?category=https%3A%2F%2Fapi-erp.kamsoft.pl%2Fvs%2Fretail%2Fproduct-definition-category%7Ccatalog
Trzecia przestrzeń w tym samym parametrze (np. słownik innego zasobu) kończy się 400, a nie pełną listą.
9. Obsługa błędów (Problem Details)
- Błędy sygnalizujemy odpowiednimi statusami HTTP.
- Format błędów: RFC 9457 Problem Details (
application/problem+json). - Pola w odpowiedzi błędu:
status(numer HTTP)type—https://httpstatuses.com/{status}title— stały tytuł per status:Invalid request(400),Resource not found(404),Request cannot be processed(422),Operation not implemented(501),Source system unavailable(503)detail(szczegóły; dla błędów, których treść zostaje w logu — tekst odsyłający dotraceId)instance(ścieżka żądania)traceId(identyfikator śladu do zgłoszenia problemu)- Zalecenie dla klientów: sprawdzać status HTTP i parsować body błędu; logować
traceIddo wsparcia.
10. Statusy HTTP
- Sukces: 200 OK (odczyt oraz zapis
POST/PATCH— odpowiedź niesie zasób), 202 Accepted (POST /v1/reports). - Błędy klienta: 400 Bad Request (zły format parametru, wartość filtra kodowanego z przestrzeni spoza słowników zadeklarowanych dla zasobu, zapis bez rozpoznanego profilu, nieznany
profile), 401 Unauthorized, 403 Forbidden (brak roliAPI.<Zasób>.Read/.Write), 404 Not Found (przestrzeń identyfikatora wskazuje instalację nieobsługującą profilu, nieznany raport), 422 Unprocessable Entity (profil nieobsługiwany w instalacji, zasób tylko do odczytu, odrzucenie przez system prowadzący). - Serwer: 500 Internal Server Error, 501 Not Implemented, 503 Service Unavailable (system prowadzący nie odpowiada).
10.1 Operacje asynchroniczne
202 Acceptedstosujemy dla operacji przyjętych do przetwarzania, których wynik nie jest jeszcze gotowy w momencie odpowiedzi.- W odpowiedzi warto zwracać identyfikator zlecenia oraz link do statusu lub artefaktu, np.
id,status,statusUrl,resultUrl. - Dla zleceń raportów i eksportów klient przekazuje publiczny klucz RSA, a serwer odsyła jednorazowy
dataKeypo jego zaszyfrowaniu. - Artefakty raportów są szyfrowane hybrydowo PGP; dla
csvużywamyAES-256, dlaparquetstosujemy flowPME. - Opcjonalna kompresja
zstdmoże zostać wykonana przed szyfrowaniem, jeśli dany typ raportu to wspiera.
11. Modele Request i Response
- Format: JSON. Request:
Content-Type: application/json; response:application/json. - Nazwy pól w JSON: camelCase (spójnie w całym API).
- POST/PATCH: body — zasób kanoniczny z
resourceType,meta.profile— listą adresów kanonicznych profili, np.["https://api-erp.kamsoft.pl/ns/StructureDefinition/Contractor"](albo cechami rozpoznającymi profil),identifier[].system(przestrzeń wymagana;valueprzy rejestracji opcjonalne — nadaje je system prowadzący) i polami wymaganymi przez profil (sekcja 7). - Nie umieszczać w body danych wrażliwych, które powinny być w nagłówkach lub chronione inaczej.
- Definicje pól, typów i wymagalności — w schematach profili; niniejsze konwencje określają kształt (camelCase, koperta kolekcji, Problem Details).
- Wyjątek praktyczny dla zleceń raportów: publiczny klucz RSA klienta jest przekazywany w request, aby serwer mógł zwrócić zaszyfrowany
dataKeyw odpowiedzi202 Accepted.
11a. DomainResource — Model bazowy dla wszystkich zasobów biznesowych (wzorowanie na FHIR)
Wszystkie zasoby biznesowe w API.ERP (DocumentReference, Invoice, InventoryDocument, Party, Employment, PostingInstruction itp.) dziedziczą z abstrakcyjnego modelu DomainResource (wzorowany na FHIR DomainResource). Zapewnia to spójność, rozszerzalność i compliance ze standardem Kamsoft.FAIR (Fast Adaptive Interoperable Resources): zasoby są Findable (identyfikatory), Accessible (CRUD endpoints), Interoperable (Reference + słowniki kodowe), Reusable (DomainResource inheritance) we wszystkich domenach.
11a.1 Struktura DomainResource
Każdy zasób biznesowy zawiera:
| Pole | Typ | Opis | Wymagane |
|---|---|---|---|
id |
string | Unikatowy identyfikator zasobu w API (zazwyczaj nadawany przez serwer) | Tak (na GET) |
meta |
object | Metadane zasobu: lastModified (datetime), version, profile (lista adresów kanonicznych profili), itd. |
Opcjonalnie |
identifier |
Identifier[] | Tablica identyfikatorów z różnych systemów (wewnętrzny id, numer z ERP, itp.) — patrz sekcja 12.1 | Opcjonalnie |
status |
CodeableConcept | Status zasobu (np. active, inactive, draft, finalized) — semantyka zależy od typu zasobu | Opcjonalnie |
type |
CodeableConcept | Typ zasobu (np. rodzaj dokumentu, rodzaj Party, rodzaj produktu) — semantyka zależy od modelu | Opcjonalnie |
11a.2 Dziedziczenie i specjalizacja
- Konkretne zasoby (DocumentReference, Invoice, Employment itp.) rozszerzają DomainResource, dodając pola specyficzne dla danej domeny.
- Przykład:
Invoice extends DomainResource, dodając pola specyficzne:issueDate,saleDate,dueDate,seller,buyer,totalNet,totalVat,totalGross,lines[],ksefAcquisitionDate. - Przykład:
InventoryDocument extends DomainResource, dodając:movementType,fromLocation,toLocation,product[],quantity[]. - W JSON Schema: wykorzystujemy
allOfz referencją doDomainResource.schema.json+ pola dodatkowe.
Przykład w OpenAPI/JSON Schema:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Invoice",
"allOf": [
{ "$ref": "#/components/schemas/DomainResource" },
{
"type": "object",
"properties": {
"issueDate": { "type": "string", "format": "date" },
"seller": { "$ref": "#/components/schemas/Reference" },
"buyer": { "$ref": "#/components/schemas/Reference" },
"totalNet": { "$ref": "#/components/schemas/Money" },
"totalVat": { "$ref": "#/components/schemas/Money" },
"totalGross": { "$ref": "#/components/schemas/Money" },
"lines": {
"type": "array",
"items": { "$ref": "#/components/schemas/InvoicePosition" }
}
}
}
]
}
11a.3 Korzyści z DomainResource
- Spójność: Wszystkie zasoby mają wspólne pola rdzeniowe (id, meta, identifier, attribute, status, type).
- Rozszerzalność: Rozszerzanie modelu realizujemy przez
attribute[]oraz profile zasobów. - FAIR compliance:
- Findable:
identifier[]wspiera wiele systemów identyfikacji - Accessible: zasoby dostępne przez jednolite endpointy kolekcji (GET, a dla wybranych POST/PATCH)
- Interoperable:
Reference[]wspiera linki pomiędzy zasobami - Reusable: struktura spójna dla wszystkich domen
- FHIR kompatybilność: Ułatwia interoperacyjność z systemami zdrowotnymi (jeśli potrzebna).
11a.4 Reference (Odniesienia między zasobami)
Pola typu Reference (np. seller, buyer, partOf) zawierają:
| Pole | Typ | Opis |
|---|---|---|
identifier |
Identifier | Podstawa logiczna referencji — identyfikator biznesowy celu (system + value); zgodnie z Reference |
type |
string (opcjonalnie) | Typ zasobu docelowego (np. Party) — wraz z identifier tworzy referencję logiczną |
reference |
string (opcjonalnie) | Ścieżka zasobu (np. Party/123 lub pełny URL) — opcjonalny dodatek techniczny, nie zastępuje identifier |
display |
string (opcjonalnie) | Tekst czytelny dla człowieka (cached copy) |
Konwencja identifier-first: znaczenie biznesowe referencji niesie para type + identifier; rozstrzyganie odbywa się przez wyszukiwanie GET /v1/<kolekcja>?identifier=system|value (sekcja 12.4). Pełna definicja i reguły rozstrzygania: Reference.
Patrz sekcja 12 — Reference jest też dostępnym typem w Identifier.assigner i innych polach.
12. Rozszerzalna identyfikacja: Identifier i Coding (wzorowane na FHIR)
Wszystkie modele (zasoby) w API mogą — a w wielu przypadkach powinny — zawierać rozszerzalną identyfikację inspirowaną FHIR: Identifier (identyfikatory z różnych systemów) oraz Coding (kody z systemów terminologicznych). Umożliwia to wielozakresową identyfikację i klasyfikację bez sztywnego schematu na poziomie API.
12.1 Identifier (identyfikator)
Pozwala opisać jeden lub wiele identyfikatorów zasobu (np. wewnętrzny ID, numer dokumentu z ERP, identyfikator z systemu zewnętrznego). Pola w camelCase:
| Pole | Typ | Opis |
|---|---|---|
use |
string (opcjonalnie) | Kontekst użycia: usual, official, temp, secondary — do doprecyzowania wartości |
type |
CodeableConcept (opcjonalnie) | Cel identyfikatora, gdy przestrzeń nie jest znana — wyłącznie kody FHIR identifier-type (v2-0203, np. TAX); rodzaj identyfikatora niesie system |
system |
string (URI) | Przestrzeń nazw identyfikatora — niesie jego rodzaj: rejestr publiczny (np. https://gov.pl/nip) albo przestrzeń wewnętrzna instalacji urn:oid:1.2.616.1.113769.4.<instalacja>.<klucz> z NamingSystem (GET /v1/naming-systems) |
value |
string | Wartość identyfikatora |
period |
obiekt (opcjonalnie) | Okres ważności: start, end (np. ISO 8601) |
assigner |
Reference (opcjonalnie) | Kto lub jaki system przypisał identyfikator |
Zasób może mieć tablicę identifier[] (np. identifier: [{ system, value }, ...]). Minimalny użyteczny zestaw: system + value.
12.2 Coding (kod z systemu terminologicznego)
Pozwala przypisać zasobowi kody z zewnętrznych lub wewnętrznych słowników (np. typ dokumentu, status, jednostka miary). Pola w camelCase:
| Pole | Typ | Opis |
|---|---|---|
system |
string (URI) | System kodów (np. https://api-erp.kamsoft.pl/vs/warehouse/document-type) |
version |
string (opcjonalnie) | Wersja systemu kodów |
code |
string | Symbol kodu |
display |
string (opcjonalnie) | Tekst czytelny dla człowieka |
userSelected |
boolean (opcjonalnie) | Czy użytkownik wybrał ten kod z listy |
Zasób może mieć pola typu Coding (pojedynczy kod) lub CodeableConcept: obiekt z tablicą coding i opcjonalnym text (tekst swobodny). Przykład: type: { coding: [{ system: "https://api-erp.kamsoft.pl/vs/finance/document-type", code: "invoice", display: "Invoice" }], text: "Faktura" }.
12.3 Zastosowanie w modelach
- Identifier: np.
PurchaseOrder.identifier[],Party.identifier[]— wiele identyfikatorów (wewnętrzny id instalacji, NIP, REGON, numer w systemie księgowym). - Coding / CodeableConcept:
status,type,category,unit— wszędzie, gdzie potrzebna jest klasyfikacja z możliwością rozszerzenia o nowe systemy kodów.
Szczegóły per zasób (które pola są wymagane, dopuszczalne kody) — schematy profili i słowniki.
12.4 Wyszukiwanie po identyfikatorze biznesowym (query parameter ?identifier=)
Identifier to parametr filtrujący, przekazywany jako jedna para system|wartość.
Kolekcyjne GET endpoints z parametrem identifier (np. GET /v1/parties, GET /v1/invoices, GET /v1/product-definitions; pełna lista w Kontraktach API) wspierają wyszukiwanie po identyfikatorze biznesowym.
Format
system— URI przestrzeni nazw identyfikatora (np.https://gov.pl/nip,urn:oid:1.2.616.1.113769.4.<instalacja>.65)|(pipe) — separator między systemem a wartością- Przecinek w wartości parametru jest niedozwolony (
400): jedno wywołanie = jeden identyfikator. Kilka identyfikatorów sprawdza się kolejnymi wywołaniami.
Przykłady
-
Wyszukanie Party (kontrahenta) po NIP (Numerze Identyfikacji Podatkowej)
Zwraca zasoby Party z identyfikatorem w systemiehttps://gov.pl/nipo wartości9542685559. -
Wyszukanie Party po identyfikatorze wewnętrznym instalacji (system OID)
Część przed|to system (tu: przestrzeń wewnętrzna zapisana jako OID — w przykładach placeholder z łuku2.999, zob. konwencje przykładów), część po|to wartość identyfikatora w tym systemie. Przestrzeń wewnętrzna kieruje zapytanie do jednej instalacji; przestrzeń spoza miejsca prawdy zasobu kończy się404(deployment.md §2). -
Wyszukanie Invoice (faktury) z filtrem statusu
Szuka Invoice o podanym numerze KSeF I statusie (AND między filtrami).
Logika wyszukiwania
- Inne filtry (
?status=,?type=,?category=itp.) łączą się zidentifier: logika AND — zwracane zasoby spełniają zarówno warunek identyfikatora, jak i inne filtry. Każdy podany filtr jest stosowany albo odrzucany statusem400(sekcja 8.1). - Brak wyniku: Gdy identyfikator nie pasuje do żadnego zasobu, API zwraca 200 OK z pustą listą (
items: []), nie 404 — zasób jest wtedy nieodnaleziony (sytuacja danych, nie błąd składni żądania); zob. Reference — rozstrzyganie referencji.
Właściciel (owner)
Firmę (podmiot prowadzący dane) wskazuje parametr owner=system|value, zwykle NIP: owner=https://gov.pl/nip|1234567890. Jest wymagany przy POST /v1/parties i PATCH /v1/parties oraz przyjmowany jako filtr w większości odczytów. Parametru company nie ma.
Implementacja
- Parametr
identifierma postaćsystem|value; separator|w URL koduje się jako%7C. - Backend porównuje
systemivaluez tablicąresource.identifier[]po stronie systemu prowadzącego.
13. Idempotency
- Cel: Uniknięcie duplikatów przy retry (np. tworzenie zamówienia, faktury).
- Mechanizm: Nagłówek idempotency key / pole w body / zewnętrzny identyfikator — do doprecyzowania.
- Zasady: Retry z tym samym kluczem = ten sam efekt — do uzupełnienia dla wybranych operacji.
- Idempotency key można reprezentować także jako Identifier (sekcja 12) z odpowiednim
system.POST /v1/posting-instructionsdziała jako add-or-update po identyfikatorze dokumentu — ponowny POST z tym samym identyfikatorem nadpisuje bufor.
14. Dokumenty pionowe i terminologia
Dokumenty pionowe (profile wymiany dokumentów) są opisane w verticals/ — rejestr: verticals/README.md, indeks: verticals-index.md.
14.1 Typy pakietów pionowych
| Typ | Przykład | Artefakt główny |
|---|---|---|
rest-only |
eod-bos (historyczne API obiegu dokumentów) | dokumentacja początkowa (poza tym przewodnikiem) |
hybrid |
mp (skierowanie medycyny pracy) | Profil CDA + schemat JSON; REST — TBD |
cda |
(przyszłe) | Profil CDA |
Historyczne OpenAPI obiegu dokumentów — dokumentacja początkowa; wpis w rejestrze verticals bez przenoszenia plików. W openapi/ tego przewodnika są wyłącznie kontrakty odbiorcy: API-ERP-Notification-Receiver.yaml i API-ERP-Report-Receiver.yaml.
14.2 ValueSet.url (FHIR)
Kanoniczny adres value setów w rozwiązaniach ERP KAMSOFT:
https://api-erp.kamsoft.pl/vs/{slug}
{slug}— kebab-case (np.oh-exam-type,esm-document-type).- Prefiks value setów profilu pionowego w slug — skrót domeny po angielsku (np.
oh-dla occupational health / medycyny pracy; pionmp). ValueSet.urljest stabilny; warianty wydania przezValueSet.version, nie przez zmianę URL.- OID w CDA (
codeSystem,root) pozostają w profilu; powiązanie OID ↔ URL — wValueSet.identifierlub NamingSystem.
Przykład mapowania dla profilu mp: verticals/mp/profile/profil-cda.html.
14.3 Wiele powierzchni API, jeden kontrakt
Przy dokumentach wymienianych między ERP a MED (np. skierowanie MP):
- API.ERP — emisja (źródło prawdy, podpis, eksport CDA).
- API.MED — intake kliniczny (import, walidacja, rejestracja wizyty).
Wspólny model kontraktu (JSON schema / CDA / value sety) — jeden pakiet w verticals/{slug}/, bez duplikowania definicji.
14.4 OpenAPI per pion
Nowe specyfikacje REST dla dokumentów pionowych — w verticals/{slug}/contracts/ (osobny plik). Nie mieszać z kontraktami odbiorcy w openapi/ bez decyzji architektonicznej.