[{"data":1,"prerenderedAt":1040},["ShallowReactive",2],{"pf:\u002Fportfolio\u002Faviation-training-systems":3,"page-globals":153,"pf-related-src":208},{"id":4,"title":5,"body":6,"canonical":117,"client":118,"date":119,"description":105,"extension":120,"featured":121,"image":122,"meta":123,"navigation":121,"og":124,"path":128,"seo":129,"stack":139,"stem":144,"summary":145,"tags":146,"twitter":149,"type":151,"__hash__":152},"portfolio\u002Fportfolio\u002Faviation-training-systems.md","Cyfryzacja procesów w organizacji szkolenia lotniczego",{"type":7,"value":8,"toc":104},"minimark",[9,14,18,22,25,29,32,35,39,68,72,75,79,82,86,89,93],[10,11,13],"h2",{"id":12},"problem","Problem",[15,16,17],"p",{},"Organizacja szkoleniowa prowadziła ewidencję szkoleń i dokumentację operacyjną w sposób rozproszony: część w arkuszach, część w plikach, część w pamięci konkretnych osób. Przy audytach i codziennej pracy oznaczało to ryzyko niespójności oraz duży nakład czasu na odtworzenie stanu faktycznego.",[10,19,21],{"id":20},"kontekst","Kontekst",[15,23,24],{},"W lotnictwie dokumentacja nie jest formalnością — to element bezpieczeństwa i zgodności. Rozwiązanie musiało więc nie tylko usprawnić pracę, ale przede wszystkim być zgodne z wymaganiami i odporne na błędy wynikające z rutyny.",[10,26,28],{"id":27},"podejście","Podejście",[15,30,31],{},"Zamiast od razu wdrażać narzędzie, zacząłem od procesów. Zmapowałem realny przebieg szkolenia i obiegu dokumentów: gdzie powstają dane, kto za nie odpowiada i w którym momencie stają się wiążące. Dopiero na tej podstawie projektowałem uporządkowanie.",[15,33,34],{},"Przeniosłem podejście znane z operacji lotniczych: jasne role, checklisty dla kroków krytycznych oraz jeden, wiarygodny stan zamiast wielu równoległych wersji prawdy.",[10,36,38],{"id":37},"architektura-procesu","Architektura procesu",[40,41,42,50,56,62],"ul",{},[43,44,45,49],"li",{},[46,47,48],"strong",{},"Jedno źródło prawdy"," dla ewidencji szkoleń i statusów.",[43,51,52,55],{},[46,53,54],{},"Jawne role i odpowiedzialności"," na każdym etapie obiegu.",[43,57,58,61],{},[46,59,60],{},"Checklisty"," dla kroków, w których błąd jest kosztowny.",[43,63,64,67],{},[46,65,66],{},"Ślad zmian"," — kto, co i kiedy zatwierdził.",[10,69,71],{"id":70},"implementacja","Implementacja",[15,73,74],{},"Wdrożenie było etapowe. Najpierw uporządkowaliśmy dane i ustaliliśmy pojedyncze źródło prawdy, potem sformalizowaliśmy procedury, a na końcu — dopiero na końcu — dobraliśmy narzędzia wspierające. Taka kolejność ograniczyła ryzyko, że narzędzie wymusi zły proces.",[10,76,78],{"id":77},"stack","Stack",[15,80,81],{},"Praca koncepcyjna i procesowa: projektowanie procesów, dokumentacja, procedury oraz podejście do compliance. Warstwa narzędziowa była wtórna wobec uporządkowanego procesu.",[10,83,85],{"id":84},"rezultat","Rezultat",[15,87,88],{},"Dokumentacja i ewidencja stały się spójne i możliwe do szybkiego odtworzenia. Przygotowanie do audytu przestało być awaryjnym zrywem, a codzienna praca zyskała jasne punkty odpowiedzialności. Organizacja zyskała stan, któremu można zaufać.",[10,90,92],{"id":91},"lessons-learned","Lessons learned",[40,94,95,98,101],{},[43,96,97],{},"Narzędzie nie naprawi złego procesu — najpierw proces, potem software.",[43,99,100],{},"Checklisty sprawdzają się w dokumentacji tak samo dobrze jak w kokpicie.",[43,102,103],{},"Jedno źródło prawdy to najtańsza inwestycja w spokój podczas audytu.",{"title":105,"searchDepth":106,"depth":106,"links":107},"",3,[108,110,111,112,113,114,115,116],{"id":12,"depth":109,"text":13},2,{"id":20,"depth":109,"text":21},{"id":27,"depth":109,"text":28},{"id":37,"depth":109,"text":38},{"id":70,"depth":109,"text":71},{"id":77,"depth":109,"text":78},{"id":84,"depth":109,"text":85},{"id":91,"depth":109,"text":92},"https:\u002F\u002Fjetstreamaviation.pl\u002Fportfolio\u002Faviation-training-systems","Confidential","2024-03-2","md",true,"\u002Fimages\u002Fportfolio\u002Faviation-training-systems.jpg",{},{"title":5,"description":125,"image":126,"type":127},"Zgodność, powtarzalność i użyteczność operacyjna.","\u002Fimages\u002Fog\u002Faviation-training-systems.jpg","article","\u002Fportfolio\u002Faviation-training-systems",{"title":130,"description":131,"keywords":132,"robots":138},"Cyfryzacja procesów w ATO — case study","Case study porządkowania dokumentacji i procedur w organizacji szkolenia lotniczego: zgodność, powtarzalność i użyteczność operacyjna.",[133,134,135,136,137],"organizacja szkoleniowa","ATO","procedury lotnicze","compliance","dokumentacja","index,follow",[140,141,142,143],"Aviation","Compliance","Process design","Documentation","portfolio\u002Faviation-training-systems","Uporządkowanie dokumentacji, ewidencji szkoleń i procedur w organizacji szkoleniowej — z naciskiem na zgodność, powtarzalność i realną użyteczność.",[147,136,148],"aviation","process",{"card":150},"summary_large_image","Consulting \u002F Aviation IT","ivhmSUqIp6bgyU8lFp7Vuqv7lri6gNLjstlQqG0Tpcc",{"id":154,"title":155,"actions":156,"areas":156,"aviationList":156,"blogChrome":157,"body":172,"canonical":156,"cards":156,"contact":156,"cta":184,"description":191,"extension":120,"eyebrow":156,"hero":156,"heroImage":156,"list":156,"meta":192,"navigation":121,"og":156,"partners":156,"path":193,"perspective":156,"portfolioChrome":194,"process":156,"sectionHeader":156,"sections":156,"seo":204,"serviceLabels":156,"services":156,"stem":206,"twitter":156,"__hash__":207},"pages\u002Fpages\u002Fglobals.md","Globalne teksty UI",null,{"readingTimeSuffix":158,"tocTitle":159,"cta":160,"related":164,"tag":167},"min czytania","Spis treści",{"eyebrow":161,"title":162,"text":163},"Współpraca","Ten temat dotyczy Twojego systemu?","Jeśli mierzysz się z podobnym problemem w praktyce — napisz. Spojrzę na konkret i podpowiem kierunek.",{"eyebrow":165,"title":166},"Czytaj dalej","Powiązane wpisy",{"eyebrow":168,"bodyPrefix":169,"backLabel":170,"emptyText":171},"Tag","Wpisy powiązane z tematem","Wróć do wszystkich wpisów →","Brak wpisów dla tego tagu.",{"type":7,"value":173,"toc":182},[174],[15,175,176,177,181],{},"Ten dokument nie ma własnej strony (",[178,179,180],"code",{},"noindex","). Służy wyłącznie jako źródło współdzielonych tekstów interfejsu, które pojawiają się na wielu stronach naraz — dzięki temu można je edytować w jednym miejscu, bez wchodzenia w kod komponentów.",{"title":105,"searchDepth":106,"depth":106,"links":183},[],{"eyebrow":161,"title":185,"text":186,"primaryLabel":187,"primaryTo":188,"secondaryLabel":189,"secondaryTo":190},"Porozmawiajmy o projekcie","Opisz problem albo cel — odezwę się z konkretną propozycją następnego kroku: rozmowy, audytu, zakresu prac lub ofertą.","Napisz do mnie","\u002Fkontakt","Zobacz usługi IT","\u002Fuslugi-it","Współdzielone etykiety i domyślne treści renderowane na wielu stronach (CtaBlock, strony szczegółów blog\u002Fportfolio, tagi). Edytowane tutaj, bez zmian w kodzie.",{},"\u002Fpages\u002Fglobals",{"caseStudyEyebrow":195,"meta":196,"stackTitle":78,"areasTitle":200,"related":201},"Case study",{"type":197,"client":198,"date":199},"Typ","Klient","Data","Obszary",{"eyebrow":202,"title":203},"Więcej","Powiązane projekty",{"robots":205,"title":155,"description":191},"noindex,nofollow","pages\u002Fglobals","_s0SDmcqMxpaZUVz5yYm0sZItpGh6_JwnFv3nOsfADs",[209,643,756,832],{"id":210,"title":211,"body":212,"canonical":615,"client":118,"date":616,"description":105,"extension":120,"featured":121,"image":617,"meta":618,"navigation":121,"og":619,"path":621,"seo":622,"stack":631,"stem":635,"summary":636,"tags":637,"twitter":640,"type":641,"__hash__":642},"portfolio\u002Fportfolio\u002Fproxmox-provider-vps-platform.md","Proxmox Provider dla platformy VPS",{"type":7,"value":213,"toc":605},[214,216,219,221,224,226,246,266,270,296,298,301,575,578,580,583,585,588,590,601],[10,215,13],{"id":12},[15,217,218],{},"Platforma sprzedająca serwery VPS zdecydowała się wdrożyć nowe środowisko wirtualizacji - PVE (Proxmox Virtual Environment). W związku z tym należało zaprojektować usługę, która weźmnie całą odpowiedzialność za zarządzanie cyklem życia maszyn wirtualnych klientów oraz ich monitorowaniem. Wymagana była niezawodność, idempotencja oraz spójność przy jednocześnie rosnącej liczbie klientów.",[10,220,21],{"id":20},[15,222,223],{},"Warstwa wykonawcza opierała się na Proxmox VE. Panel klienta i panel administracyjny potrzebowały jednego, spójnego sposobu zlecania operacji na maszynach oraz wglądu w ich aktualny stan, a także możliwości monitorowania klastra — najlepiej w czasie rzeczywistym, bez ręcznego odświeżania. W celach administracyjnych wymagane było zarządzanie takimi funkcjami jak sieci wirtualne lub polityki migawek.",[10,225,28],{"id":27},[15,227,228,229,232,233,232,236,232,239,232,242,245],{},"Zaprojektowałem osobny moduł — „provider\" — odpowiedzialny wyłącznie za komunikację z Proxmox i tłumaczenie intencji biznesowych (",[178,230,231],{},"utwórz maszynę",", ",[178,234,235],{},"zmień plan",[178,237,238],{},"usuń",[178,240,241],{},"uruchom",[178,243,244],{},"wykonaj migawkę",") na konkretne operacje w infrastrukturze. Panel nigdy nie rozmawia z Proxmox bezpośrednio; zawsze przez jawny kontrakt providera.",[15,247,248,249,232,252,232,255,232,258,261,262,265],{},"Operacje długotrwałe potraktowałem jako zadania asynchroniczne z jawnym cyklem życia: ",[178,250,251],{},"zlecone",[178,253,254],{},"w toku",[178,256,257],{},"zakończone",[178,259,260],{},"błąd",". Za ich orkiestrację w obrębie modułu odpowiada mechanizm ",[178,263,264],{},"internal commands processor",". Dzięki temu interfejs mógł pokazywać rzeczywisty postęp, a nie tylko „proszę czekać\".",[10,267,269],{"id":268},"architektura","Architektura",[40,271,272,278,284,290],{},[43,273,274,277],{},[46,275,276],{},"Provider"," jako granica: cała wiedza o Proxmox zamknięta za jednym kontraktem.",[43,279,280,283],{},[46,281,282],{},"Kolejka zadań"," dla operacji długotrwałych, z idempotentnymi krokami.",[43,285,286,289],{},[46,287,288],{},"PostgreSQL"," jako źródło prawdy o stanie zamówień i maszyn.",[43,291,292,295],{},[46,293,294],{},"Redis"," do koordynacji zadań i cache'owania stanu odpytywanego często.",[10,297,71],{"id":70},[15,299,300],{},"Kluczowa była idempotentność. Ponowienie zadania po awarii nie mogło tworzyć drugiej maszyny ani pozostawiać systemu w stanie niespójnym. Każdy krok sprawdzał najpierw, czy jego efekt już nie istnieje.",[302,303,307],"pre",{"className":304,"code":305,"language":306,"meta":105,"style":105},"language-csharp shiki shiki-themes one-dark-pro one-dark-pro","public async Task\u003CResult> Handle(ProvisionVm task, CancellationToken ct)\n{\n    var existing = await proxmox.FindByTagAsync(task.CorrelationId, ct);\n    if (existing is not null)\n        return Result.AlreadyDone(existing.VmId); \u002F\u002F idempotentnie: brak duplikatu\n\n    var vm = await proxmox.CreateAsync(task.Spec, task.CorrelationId, ct);\n    await progress.PublishAsync(task.OrderId, VmState.Provisioned, ct);\n    return Result.Ok(vm.VmId);\n}\n","csharp",[178,308,309,359,364,407,428,458,464,506,545,569],{"__ignoreMap":105},[310,311,314,318,321,325,329,332,335,339,342,345,348,350,353,356],"span",{"class":312,"line":313},"line",1,[310,315,317],{"class":316},"sCyHM","public",[310,319,320],{"class":316}," async",[310,322,324],{"class":323},"sZsuq"," Task",[310,326,328],{"class":327},"shasQ","\u003C",[310,330,331],{"class":323},"Result",[310,333,334],{"class":327},"> ",[310,336,338],{"class":337},"sw6ri","Handle",[310,340,341],{"class":327},"(",[310,343,344],{"class":323},"ProvisionVm",[310,346,347],{"class":323}," task",[310,349,232],{"class":327},[310,351,352],{"class":323},"CancellationToken",[310,354,355],{"class":323}," ct",[310,357,358],{"class":327},")\n",[310,360,361],{"class":312,"line":109},[310,362,363],{"class":327},"{\n",[310,365,366,369,373,377,380,383,386,389,391,394,396,399,401,404],{"class":312,"line":106},[310,367,368],{"class":316},"    var",[310,370,372],{"class":371},"sh-OU"," existing",[310,374,376],{"class":375},"seqx8"," =",[310,378,379],{"class":327}," await ",[310,381,382],{"class":323},"proxmox",[310,384,385],{"class":327},".",[310,387,388],{"class":337},"FindByTagAsync",[310,390,341],{"class":327},[310,392,393],{"class":323},"task",[310,395,385],{"class":327},[310,397,398],{"class":323},"CorrelationId",[310,400,232],{"class":327},[310,402,403],{"class":371},"ct",[310,405,406],{"class":327},");\n",[310,408,410,413,416,419,422,426],{"class":312,"line":409},4,[310,411,412],{"class":316},"    if",[310,414,415],{"class":327}," (",[310,417,418],{"class":371},"existing",[310,420,421],{"class":327}," is not ",[310,423,425],{"class":424},"sDrLb","null",[310,427,358],{"class":327},[310,429,431,434,437,439,442,444,446,448,451,454],{"class":312,"line":430},5,[310,432,433],{"class":316},"        return",[310,435,436],{"class":323}," Result",[310,438,385],{"class":327},[310,440,441],{"class":337},"AlreadyDone",[310,443,341],{"class":327},[310,445,418],{"class":323},[310,447,385],{"class":327},[310,449,450],{"class":323},"VmId",[310,452,453],{"class":327},"); ",[310,455,457],{"class":456},"sIbxt","\u002F\u002F idempotentnie: brak duplikatu\n",[310,459,461],{"class":312,"line":460},6,[310,462,463],{"emptyLinePlaceholder":121},"\n",[310,465,467,469,472,474,476,478,480,483,485,487,489,492,494,496,498,500,502,504],{"class":312,"line":466},7,[310,468,368],{"class":316},[310,470,471],{"class":371}," vm",[310,473,376],{"class":375},[310,475,379],{"class":327},[310,477,382],{"class":323},[310,479,385],{"class":327},[310,481,482],{"class":337},"CreateAsync",[310,484,341],{"class":327},[310,486,393],{"class":323},[310,488,385],{"class":327},[310,490,491],{"class":323},"Spec",[310,493,232],{"class":327},[310,495,393],{"class":323},[310,497,385],{"class":327},[310,499,398],{"class":323},[310,501,232],{"class":327},[310,503,403],{"class":371},[310,505,406],{"class":327},[310,507,509,512,515,517,520,522,524,526,529,531,534,536,539,541,543],{"class":312,"line":508},8,[310,510,511],{"class":327},"    await ",[310,513,514],{"class":323},"progress",[310,516,385],{"class":327},[310,518,519],{"class":337},"PublishAsync",[310,521,341],{"class":327},[310,523,393],{"class":323},[310,525,385],{"class":327},[310,527,528],{"class":323},"OrderId",[310,530,232],{"class":327},[310,532,533],{"class":323},"VmState",[310,535,385],{"class":327},[310,537,538],{"class":323},"Provisioned",[310,540,232],{"class":327},[310,542,403],{"class":371},[310,544,406],{"class":327},[310,546,548,551,553,555,558,560,563,565,567],{"class":312,"line":547},9,[310,549,550],{"class":316},"    return",[310,552,436],{"class":323},[310,554,385],{"class":327},[310,556,557],{"class":337},"Ok",[310,559,341],{"class":327},[310,561,562],{"class":323},"vm",[310,564,385],{"class":327},[310,566,450],{"class":323},[310,568,406],{"class":327},[310,570,572],{"class":312,"line":571},10,[310,573,574],{"class":327},"}\n",[15,576,577],{},"Stan każdego zadania był publikowany na bieżąco, więc panel administracyjny i panel klienta widziały te same, aktualne informacje.",[10,579,78],{"id":77},[15,581,582],{},".NET, ASP.NET Core, PostgreSQL, Redis, Docker oraz API Proxmox VE.",[10,584,85],{"id":84},[15,586,587],{},"Provisioning maszyn stał się w pełni automatyczny i powtarzalny. Czas realizacji typowego zamówienia skrócił się z minut liczonych ręcznie do operacji wykonywanej bez udziału człowieka. Panele pokazują rzeczywisty stan maszyn na żywo, a operacje można bezpiecznie ponawiać po awarii.",[10,589,92],{"id":91},[40,591,592,595,598],{},[43,593,594],{},"Idempotentność nie jest dodatkiem — przy operacjach na infrastrukturze to warunek bezpieczeństwa.",[43,596,597],{},"Zamknięcie integracji za jednym kontraktem opłaciło się przy każdej późniejszej zmianie w Proxmox.",[43,599,600],{},"Komunikacja w czasie rzeczywistym najbardziej pomogła nie klientom, lecz administracji — skróciła czas reakcji na problemy.",[602,603,604],"style",{},"html pre.shiki code .sCyHM, html code.shiki .sCyHM{--shiki-default:#C678DD;--shiki-dark:#C678DD}html pre.shiki code .sZsuq, html code.shiki .sZsuq{--shiki-default:#E5C07B;--shiki-dark:#E5C07B}html pre.shiki code .shasQ, html code.shiki .shasQ{--shiki-default:#ABB2BF;--shiki-dark:#ABB2BF}html pre.shiki code .sw6ri, html code.shiki .sw6ri{--shiki-default:#61AFEF;--shiki-dark:#61AFEF}html pre.shiki code .sh-OU, html code.shiki .sh-OU{--shiki-default:#E06C75;--shiki-dark:#E06C75}html pre.shiki code .seqx8, html code.shiki .seqx8{--shiki-default:#56B6C2;--shiki-dark:#56B6C2}html pre.shiki code .sDrLb, html code.shiki .sDrLb{--shiki-default:#D19A66;--shiki-dark:#D19A66}html pre.shiki code .sIbxt, html code.shiki .sIbxt{--shiki-default:#7F848E;--shiki-default-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":105,"searchDepth":106,"depth":106,"links":606},[607,608,609,610,611,612,613,614],{"id":12,"depth":109,"text":13},{"id":20,"depth":109,"text":21},{"id":27,"depth":109,"text":28},{"id":268,"depth":109,"text":269},{"id":70,"depth":109,"text":71},{"id":77,"depth":109,"text":78},{"id":84,"depth":109,"text":85},{"id":91,"depth":109,"text":92},"https:\u002F\u002Fjetstreamaviation.pl\u002Fportfolio\u002Fproxmox-provider-vps-platform","2026-07-13","\u002Fimages\u002Fportfolio\u002Fproxmox-provider.webp",{},{"title":211,"description":620,"type":127},"Automatyzacja cyklu życia maszyn wirtualnych na Proxmox.","\u002Fportfolio\u002Fproxmox-provider-vps-platform",{"title":623,"description":624,"keywords":625,"robots":138},"Proxmox Provider — case study integracji platformy VPS","Case study systemu automatyzującego provisioning maszyn wirtualnych na Proxmox: architektura, kolejki zadań i komunikacja w czasie rzeczywistym.",[626,627,628,629,630,288],"Proxmox",".NET","VPS","infrastructure","Docker",[632,626,630,288,294,633,634],".NET Core","YARP","Grafana\u002FPrometheus\u002FLoki","portfolio\u002Fproxmox-provider-vps-platform","System integrujący panel platformy VPS z infrastrukturą Proxmox — automatyczne provisionowanie, cykl życia maszyn i komunikacja w czasie rzeczywistym.",[629,638,639],"backend","devops",{"card":150},"Software \u002F Infrastructure","XoEMuTt59FnMAoRcEmjDmSb_DQZQwFyH1Ag8vW7t7Z0",{"id":644,"title":645,"body":646,"canonical":726,"client":118,"date":727,"description":105,"extension":120,"featured":728,"image":729,"meta":730,"navigation":121,"og":731,"path":733,"seo":734,"stack":744,"stem":747,"summary":748,"tags":749,"twitter":753,"type":754,"__hash__":755},"portfolio\u002Fportfolio\u002Fcomarch-erp-optima-ksef-integration.md","Automatyczna integracja Comarch ERP Optima z KSeF",{"type":7,"value":647,"toc":718},[648,650,653,656,658,661,664,666,692,694,697,699,702,705,707],[10,649,13],{"id":12},[15,651,652],{},"Proces wysyłania faktur z Comarch ERP Optima do KSeF wymagał automatyzacji bez pomijania mechanizmów biznesowych i ewidencyjnych systemu ERP.",[15,654,655],{},"Rozwiązanie musiało poprawnie przetwarzać dokumenty, przekazywać je do KSeF, odbierać Urzędowe Poświadczenie Odbioru oraz zapisywać rezultat w taki sposób, aby cały proces pozostawał widoczny dla użytkowników Optimy.",[10,657,28],{"id":27},[15,659,660],{},"Zaprojektowałem i wdrożyłem usługę Windows działającą w tle. Co 10 sekund wyszukuje ona w bazie Microsoft SQL Server faktury oczekujące na przetworzenie.",[15,662,663],{},"Dostęp do danych został zaimplementowany przy użyciu Dappera, natomiast właściwa wysyłka dokumentów odbywa się przez bibliotekę DLL API Comarch ERP Optima. Dzięki temu faktury są obsługiwane zgodnie z mechanizmami Optimy, a informacje o wysyłce i odebranym UPO pozostają dostępne bezpośrednio w systemie ERP.",[10,665,269],{"id":268},[40,667,668,674,680,686],{},[43,669,670,673],{},[46,671,672],{},"Windows Service"," realizujący cykliczne przetwarzanie dokumentów.",[43,675,676,679],{},[46,677,678],{},"Dapper i SQL Server"," do szybkiego wyszukiwania faktur oczekujących na wysłanie.",[43,681,682,685],{},[46,683,684],{},"Comarch ERP Optima API"," do przetwarzania dokumentów i komunikacji z KSeF.",[43,687,688,691],{},[46,689,690],{},"Obsługa UPO"," wraz z zapisaniem wyniku procesu w Optimie.",[10,693,78],{"id":77},[15,695,696],{},".NET Framework 4.7.2, Windows Service, Microsoft SQL Server, Dapper oraz DLL API Comarch ERP Optima.",[10,698,85],{"id":84},[15,700,701],{},"Proces wysyłania faktur do KSeF został całkowicie zautomatyzowany. Dokumenty są regularnie wykrywane, poprawnie przetwarzane przez API Optimy i wysyłane do KSeF, a następnie uzupełniane o odebrane UPO.",[15,703,704],{},"Użytkownicy mogą kontrolować status faktur bezpośrednio w Comarch ERP Optima, bez korzystania z dodatkowego panelu lub ręcznego uruchamiania wysyłki.",[10,706,92],{"id":91},[40,708,709,712,715],{},[43,710,711],{},"Integracja przez oficjalne API systemu ERP pozwala zachować spójność jego procesów biznesowych.",[43,713,714],{},"Usługa działająca w tle dobrze sprawdza się przy regularnym przetwarzaniu niewielkich kolejek dokumentów.",[43,716,717],{},"Rezultat integracji powinien być widoczny w systemie, z którego użytkownicy korzystają na co dzień.",{"title":105,"searchDepth":106,"depth":106,"links":719},[720,721,722,723,724,725],{"id":12,"depth":109,"text":13},{"id":27,"depth":109,"text":28},{"id":268,"depth":109,"text":269},{"id":77,"depth":109,"text":78},{"id":84,"depth":109,"text":85},{"id":91,"depth":109,"text":92},"https:\u002F\u002Fjetstreamaviation.pl\u002Fportfolio\u002Fcomarch-optima-ksef-integration","2026-04-01",false,"\u002Fimages\u002Fportfolio\u002Foptima-ksef.webp",{},{"title":645,"description":732,"type":127},"Automatyczna wysyłka faktur do KSeF i odbieranie UPO bezpośrednio w środowisku Comarch ERP Optima.","\u002Fportfolio\u002Fcomarch-erp-optima-ksef-integration",{"title":735,"description":736,"keywords":737,"robots":138},"Integracja Comarch ERP Optima z KSeF | Case study","Usługa Windows automatyzująca wysyłkę faktur z Comarch ERP Optima do KSeF oraz pobieranie UPO.",[738,739,740,741,742,743],"Comarch ERP Optima","KSeF",".NET Framework","SQL Server","Dapper","integracja ERP",[745,684,746,742,672,739],".NET Framework 4.7.2","Microsoft SQL Server","portfolio\u002Fcomarch-erp-optima-ksef-integration","Usługa Windows automatyzująca przetwarzanie faktur z Comarch ERP Optima, wysyłkę do KSeF oraz odbieranie Urzędowego Poświadczenia Odbioru.",[638,750,751,752],"integration","erp","automation",{"card":150},"Software \u002F ERP Integration","pLQ3RV8OBlrJ-g4BY6Lv1mG64n_dKjWPXIPhvt0PHy0",{"id":4,"title":5,"body":757,"canonical":117,"client":118,"date":119,"description":105,"extension":120,"featured":121,"image":122,"meta":825,"navigation":121,"og":826,"path":128,"seo":827,"stack":829,"stem":144,"summary":145,"tags":830,"twitter":831,"type":151,"__hash__":152},{"type":7,"value":758,"toc":815},[759,761,763,765,767,769,771,773,775,793,795,797,799,801,803,805,807],[10,760,13],{"id":12},[15,762,17],{},[10,764,21],{"id":20},[15,766,24],{},[10,768,28],{"id":27},[15,770,31],{},[15,772,34],{},[10,774,38],{"id":37},[40,776,777,781,785,789],{},[43,778,779,49],{},[46,780,48],{},[43,782,783,55],{},[46,784,54],{},[43,786,787,61],{},[46,788,60],{},[43,790,791,67],{},[46,792,66],{},[10,794,71],{"id":70},[15,796,74],{},[10,798,78],{"id":77},[15,800,81],{},[10,802,85],{"id":84},[15,804,88],{},[10,806,92],{"id":91},[40,808,809,811,813],{},[43,810,97],{},[43,812,100],{},[43,814,103],{},{"title":105,"searchDepth":106,"depth":106,"links":816},[817,818,819,820,821,822,823,824],{"id":12,"depth":109,"text":13},{"id":20,"depth":109,"text":21},{"id":27,"depth":109,"text":28},{"id":37,"depth":109,"text":38},{"id":70,"depth":109,"text":71},{"id":77,"depth":109,"text":78},{"id":84,"depth":109,"text":85},{"id":91,"depth":109,"text":92},{},{"title":5,"description":125,"image":126,"type":127},{"title":130,"description":131,"keywords":828,"robots":138},[133,134,135,136,137],[140,141,142,143],[147,136,148],{"card":150},{"id":833,"title":834,"body":835,"canonical":1012,"client":118,"date":1013,"description":105,"extension":120,"featured":728,"image":1014,"meta":1015,"navigation":121,"og":1016,"path":1019,"seo":1020,"stack":1029,"stem":1031,"summary":1032,"tags":1033,"twitter":1037,"type":1038,"__hash__":1039},"portfolio\u002Fportfolio\u002Femvo-notification-system.md","EMVO EVI — system powiadomień o zdarzeniach EMVS",{"type":7,"value":836,"toc":1002},[837,839,842,845,847,850,853,856,858,861,864,884,887,889,932,934,937,940,961,964,967,969,972,974,977,980,983,985],[10,838,13],{"id":12},[15,840,841],{},"Europejska infrastruktura weryfikacji leków składa się z wielu współpracujących ze sobą systemów krajowych i centralnych. Wystąpienie awarii, planowanej przerwy technicznej lub znanego problemu wymagało szybkiego przekazania precyzyjnej informacji do zainteresowanych organizacji i użytkowników.",[15,843,844],{},"Dotychczasowa obsługa takich komunikatów była trudna do skalowania. Odbiorcy potrzebowali informacji dotyczących wyłącznie wybranych krajów, systemów i rodzajów zdarzeń, natomiast operatorzy musieli kontrolować cały cykl życia zgłoszenia — od jego utworzenia, przez aktualizacje, aż po zamknięcie incydentu.",[10,846,21],{"id":20},[15,848,849],{},"EVI — European Medicines Verification System Information — pełniło rolę centralnego źródła informacji o zdarzeniach operacyjnych w ramach EMVS.",[15,851,852],{},"System musiał obsługiwać zdarzenia dotyczące wielu krajów, środowisk i komponentów infrastruktury. Każda publikacja mogła zmieniać się w czasie: otrzymywać aktualizacje, nowe przewidywane terminy rozwiązania, informacje o przyczynach lub potwierdzenie przywrócenia prawidłowego działania.",[15,854,855],{},"Równocześnie użytkownicy powinni otrzymywać tylko te wiadomości, które odpowiadały ich subskrypcjom, bez konieczności ręcznego śledzenia wszystkich komunikatów.",[10,857,28],{"id":27},[15,859,860],{},"Zaprojektowałem i rozwijałem backend systemu jako Web API w ASP.NET Core. Aplikacja rozdzielała odpowiedzialność za zarządzanie zgłoszeniami, publikowanie zdarzeń, obsługę subskrypcji oraz wysyłkę powiadomień.",[15,862,863],{},"Zdarzenie było traktowane jako obiekt posiadający własny cykl życia. Operator mógł określić między innymi:",[40,865,866,869,872,875,878,881],{},[43,867,868],{},"kraj lub grupę krajów,",[43,870,871],{},"system i środowisko, którego dotyczy zdarzenie,",[43,873,874],{},"rodzaj oraz poziom wpływu,",[43,876,877],{},"czas rozpoczęcia i zakończenia,",[43,879,880],{},"aktualny status,",[43,882,883],{},"opis problemu i kolejne aktualizacje.",[15,885,886],{},"Po opublikowaniu lub zmianie zgłoszenia system identyfikował właściwych subskrybentów i przygotowywał dla nich odpowiednie powiadomienia.",[10,888,269],{"id":268},[40,890,891,897,902,908,914,920,926],{},[43,892,893,896],{},[46,894,895],{},"ASP.NET Core Web API"," jako warstwa udostępniająca operacje związane ze zgłoszeniami, użytkownikami i subskrypcjami.",[43,898,899,901],{},[46,900,746],{}," jako źródło prawdy o zdarzeniach, odbiorcach, konfiguracji subskrypcji i historii wysyłki.",[43,903,904,907],{},[46,905,906],{},"SSO"," zapewniające kontrolowany dostęp do funkcji administracyjnych.",[43,909,910,913],{},[46,911,912],{},"Quartz.NET"," do realizacji zadań cyklicznych i przetwarzania operacji wykonywanych poza żądaniem HTTP.",[43,915,916,919],{},[46,917,918],{},"SendGrid"," jako usługa odpowiedzialna za dystrybucję wiadomości e-mail.",[43,921,922,925],{},[46,923,924],{},"Microsoft Azure"," jako środowisko uruchomieniowe aplikacji i jej infrastruktury.",[43,927,928,931],{},[46,929,930],{},"GitOps"," do kontrolowanego, powtarzalnego wdrażania zmian pomiędzy środowiskami.",[10,933,71],{"id":70},[15,935,936],{},"Jednym z kluczowych elementów był mechanizm dopasowywania zgłoszeń do subskrypcji. Użytkownik mógł określić zakres interesujących go informacji, a system oceniał każde nowe lub zaktualizowane zdarzenie na podstawie kilku kryteriów jednocześnie.",[15,938,939],{},"Proces obejmował:",[941,942,943,946,949,952,955,958],"ol",{},[43,944,945],{},"zapisanie lub aktualizację zgłoszenia,",[43,947,948],{},"określenie krajów, systemów i środowisk objętych zdarzeniem,",[43,950,951],{},"wyszukanie pasujących subskrypcji,",[43,953,954],{},"utworzenie powiadomień dla właściwych odbiorców,",[43,956,957],{},"przekazanie wiadomości do SendGrid,",[43,959,960],{},"zapisanie wyniku wysyłki i historii komunikacji.",[15,962,963],{},"Operacje wysyłania zostały oddzielone od podstawowej obsługi żądań API. Dzięki temu publikowanie zgłoszenia nie było uzależnione od czasu odpowiedzi zewnętrznego dostawcy poczty, a nieudane próby mogły być bezpiecznie ponawiane przez zadania Quartz.NET.",[15,965,966],{},"Istotnym elementem była również audytowalność. System przechowywał historię zmian zgłoszeń oraz informacje o wygenerowanych i wysłanych powiadomieniach, co ułatwiało analizowanie przebiegu komunikacji.",[10,968,78],{"id":77},[15,970,971],{},"ASP.NET Core Web API, Microsoft SQL Server, Microsoft Azure, Quartz.NET, SendGrid, SSO oraz proces wdrożeniowy oparty na GitOps.",[10,973,85],{"id":84},[15,975,976],{},"Powstał centralny system umożliwiający uporządkowane zarządzanie informacjami o zdarzeniach operacyjnych dotyczących wielu krajów i komponentów EMVS.",[15,978,979],{},"Operatorzy mogli prowadzić zgłoszenie przez cały jego cykl życia i publikować kolejne aktualizacje, natomiast odbiorcy automatycznie otrzymywali tylko te informacje, które odpowiadały zakresowi ich subskrypcji.",[15,981,982],{},"Rozdzielenie obsługi zgłoszeń od mechanizmu dystrybucji wiadomości zwiększyło odporność rozwiązania na błędy usług zewnętrznych i umożliwiło bezpieczne ponawianie niedostarczonych powiadomień.",[10,984,92],{"id":91},[40,986,987,990,993,996,999],{},[43,988,989],{},"W systemach wielokrajowych filtrowanie odbiorców jest równie istotne jak samo publikowanie komunikatów.",[43,991,992],{},"Powiadomienie powinno być osobnym elementem domeny z własnym statusem, historią i możliwością ponowienia wysyłki.",[43,994,995],{},"Operacje zależne od zewnętrznych dostawców nie powinny blokować podstawowego procesu publikowania zgłoszenia.",[43,997,998],{},"Historia zmian i wysyłki jest niezbędna w systemach, w których liczy się możliwość odtworzenia pełnego przebiegu komunikacji.",[43,1000,1001],{},"GitOps ułatwia utrzymanie spójnej konfiguracji aplikacji działającej w kilku środowiskach.",{"title":105,"searchDepth":106,"depth":106,"links":1003},[1004,1005,1006,1007,1008,1009,1010,1011],{"id":12,"depth":109,"text":13},{"id":20,"depth":109,"text":21},{"id":27,"depth":109,"text":28},{"id":268,"depth":109,"text":269},{"id":70,"depth":109,"text":71},{"id":77,"depth":109,"text":78},{"id":84,"depth":109,"text":85},{"id":91,"depth":109,"text":92},"https:\u002F\u002Fjetstreamaviation.pl\u002Fportfolio\u002Femvo-notification-system","2022-05-01","\u002Fimages\u002Fportfolio\u002Femvo-evi.webp",{},{"title":1017,"description":1018,"type":127},"EMVO EVI — powiadomienia o zdarzeniach EMVS","System obsługi zgłoszeń, subskrypcji i wielokrajowej dystrybucji powiadomień dla infrastruktury weryfikacji leków.","\u002Fportfolio\u002Femvo-notification-system",{"title":1021,"description":1022,"keywords":1023,"robots":138},"EMVO EVI — system powiadomień EMVS | Case study","Case study systemu EMVO EVI do obsługi zdarzeń operacyjnych, subskrypcji i automatycznych powiadomień dla europejskiej infrastruktury weryfikacji leków.",[1024,1025,1026,1027,1028,741,918,912],"EMVO","EVI","EMVS","ASP.NET Core","Azure",[895,1030,1028,912,918,906,930],"MSSQL","portfolio\u002Femvo-notification-system","Wielokrajowy system obsługi zdarzeń operacyjnych i powiadomień dla europejskiej infrastruktury weryfikacji leków — od rejestracji zgłoszenia po dystrybucję informacji do subskrybentów.",[638,1034,1035,1036,639],"healthcare","notifications","cloud",{"card":150},"Software \u002F Healthcare","N28g6OVh1jB1P1osWC_T6GYRKJxpvVqGOMbQvwz4G-c",1784052984643]