[{"data":1,"prerenderedAt":2693},["ShallowReactive",2],{"case-study-aurum-aurora-technical-report-pl":3},{"id":4,"title":5,"body":6,"description":2663,"extension":2664,"featured":2665,"interactive":2665,"meta":2666,"navigation":199,"path":2667,"seo":2668,"stem":2669,"subtitle":2670,"tags":2671,"technologies":2677,"__hash__":2692},"caseStudiesPl\u002Fcase-studies\u002Fpl\u002Faurum-aurora-technical-report.md","Aurum 2.0 & Aurora — raport techniczny",{"type":7,"value":8,"toc":2646},"minimark",[9,14,18,21,25,28,47,50,54,57,72,75,79,82,85,102,106,109,112,116,119,122,126,134,141,637,643,647,650,1114,1118,1124,1588,1599,1603,1610,1712,1727,1734,1745,2030,2048,2052,2055,2076,2079,2409,2420,2424,2427,2476,2479,2621,2624,2632,2636,2639,2642],[10,11,13],"h2",{"id":12},"cel-platformy","Cel platformy",[15,16,17],"p",{},"Aurum 2.0 oddziela unikalne doświadczenie użytkownika od powtarzalnej pracy operacyjnej. Serwisy nadal powstają jako niezależne aplikacje Vue i Nuxt, natomiast treści, uprawnienia, dane domenowe, publikacja oraz wdrożenia korzystają ze wspólnych kontraktów.",[15,19,20],{},"Platforma nie jest związana z jedną branżą. Funkcje biznesowe są dostarczane przez wersjonowane pluginy, dzięki czemu kolejne domeny mogą rozwijać się bez rozbudowywania rdzenia.",[10,22,24],{"id":23},"mały-rdzeń-i-pluginy-produktowe","Mały rdzeń i pluginy produktowe",[15,26,27],{},"Rdzeń Aurum odpowiada za elementy wymagające wspólnego zaufania:",[29,30,31,35,38,41,44],"ul",{},[32,33,34],"li",{},"tożsamość, sesje i role;",[32,36,37],{},"katalog pluginów i ich wersje;",[32,39,40],{},"audyt oraz obserwowalność;",[32,42,43],{},"walidację kontraktów;",[32,45,46],{},"kontrolowaną aktywację nowych wersji.",[15,48,49],{},"Plugin wnosi kompletną możliwość produktową: endpointy backendowe, interfejs administracyjny, konfigurację, uprawnienia i prywatną przestrzeń danych. Aurora Editor, Contact Messages czy plugin domenowy są równorzędnymi rozszerzeniami platformy.",[10,51,53],{"id":52},"izolacja-i-kod-wspomagany-przez-ai","Izolacja i kod wspomagany przez AI",[15,55,56],{},"Kod wygenerowany lub zmodyfikowany z pomocą AI nie otrzymuje dodatkowego zaufania. Każdy plugin przechodzi przez tę samą granicę kontraktową:",[58,59,60,63,66,69],"ol",{},[32,61,62],{},"Manifest deklaruje zgodność SDK, konfigurację, endpointy oraz uprawnienia.",[32,64,65],{},"Dostęp jest przyznawany per capability zgodnie z zasadą minimalnych uprawnień.",[32,67,68],{},"Dane i migracje pozostają prywatne dla pluginu.",[32,70,71],{},"Kandydat jest sprawdzany przed aktywacją i przejęciem ruchu.",[15,73,74],{},"Takie podejście nie zakłada bezbłędności wygenerowanego kodu. Ogranicza natomiast obszar potencjalnych konsekwencji i utrudnia przypadkowe sprzężenie modułów.",[10,76,78],{"id":77},"aurora-editor","Aurora Editor",[15,80,81],{},"Aurora zamienia finalną stronę w powierzchnię edycji. Deweloper oznacza edytowalne elementy stabilnymi kluczami, wartościami domyślnymi i kontekstem dla redaktora. Layout, responsywność oraz sposób renderowania pozostają własnością aplikacji klienckiej.",[15,83,84],{},"Osadzona strona nie otrzymuje tokenu administracyjnego i nie zapisuje danych bezpośrednio. Komunikuje intencje edycji do zaufanej aplikacji nadrzędnej przez wersjonowany protokół wiadomości z:",[29,86,87,90,93,96,99],{},[32,88,89],{},"kontrolą origin;",[32,91,92],{},"handshake opartym o nonce i identyfikator sesji;",[32,94,95],{},"walidacją schematów;",[32,97,98],{},"identyfikatorami korelacyjnymi;",[32,100,101],{},"wersjonowanymi aktualizacjami stanu.",[10,103,105],{"id":104},"szkice-publikacja-i-historia","Szkice, publikacja i historia",[15,107,108],{},"Aurora zarządza szkicem, autosave, rewizją, konfliktami oraz stanem opublikowanym. Zapis zawiera oczekiwaną rewizję i klucz idempotencji. Konflikt nie nadpisuje cicho zmian innej osoby.",[15,110,111],{},"Publikacja tworzy niezmienny release wskazanej rewizji. Rollback powstaje jako kolejny release oparty na wcześniejszym snapshotcie, dzięki czemu historia pozostaje liniowa i audytowalna.",[10,113,115],{"id":114},"bezpieczna-aktywacja","Bezpieczna aktywacja",[15,117,118],{},"Nowa wersja pluginu jest przygotowywana poza aktywnym ruchem. Aurum waliduje manifest, konfigurację, trasy backendowe i metadane interfejsu. Dopiero kompletny kandydat zastępuje poprzednią wersję atomowo.",[15,120,121],{},"Jeżeli aktywacja się nie powiedzie, ostatnia zdrowa wersja pozostaje aktywna. Operator Kubernetes i GitOps łączą wersję obrazu, konfigurację oraz oczekiwany stan klastra w jeden audytowalny proces.",[10,123,125],{"id":124},"manifest-backendowego-pluginu","Manifest backendowego pluginu",[15,127,128,129,133],{},"Plugin jest zwykłym modułem TypeScript eksportującym manifest zdefiniowany przez ",[130,131,132],"code",{},"@aurum\u002Fbackend-plugin-sdk",". Kontrakt zawiera semantyczną wersję pluginu, zakres kompatybilności SDK, katalog uprawnień, schemat konfiguracji i endpointy.",[15,135,136,137,140],{},"Poniższy fragment odpowiada strukturze pluginu ",[130,138,139],{},"contact-message",":",[142,143,148],"pre",{"className":144,"code":145,"language":146,"meta":147,"style":147},"language-ts shiki shiki-themes github-light github-dark","import {\n  definePlugin,\n  type PluginManifest,\n} from \"@aurum\u002Fbackend-plugin-sdk\";\n\nconst READ = \"contact-messages.read\";\nconst WRITE = \"contact-messages.write\";\n\nexport const manifest: PluginManifest = definePlugin({\n  id: \"contact-message\",\n  name: \"Kontakt\",\n  version: \"1.0.0\",\n  sdkVersion: \"^1.0.0\",\n  permissions: [READ, WRITE],\n\n  configurationSchema: {\n    type: \"object\",\n    required: [\n      \"retentionDays\",\n      \"publicRateLimit\",\n      \"publicRateLimitWindowSeconds\",\n      \"allowedOrigins\",\n    ],\n    additionalProperties: false,\n    properties: {\n      retentionDays: { type: \"integer\" },\n      publicRateLimit: { type: \"integer\" },\n      publicRateLimitWindowSeconds: { type: \"integer\" },\n      allowedOrigins: { type: \"array\" },\n    },\n  },\n\n  backend: {\n    endpoints: [\n      {\n        method: \"GET\",\n        path: \"\u002Fapi\u002Fcontact-messages\",\n        requireAuth: true,\n        requirePermission: [READ],\n        handler: async (request) => {\n          return request.platform.storage.find(\n            \"contactMessages\",\n            {},\n            { sort: { createdAt: -1 } },\n          );\n        },\n      },\n    ],\n  },\n});\n","ts","",[130,149,150,163,169,178,194,201,219,234,239,265,277,288,299,310,328,333,339,350,356,364,372,380,388,394,405,411,423,433,443,454,460,466,471,477,483,489,500,511,522,532,559,574,582,588,603,609,615,621,626,631],{"__ignoreMap":147},[151,152,155,159],"span",{"class":153,"line":154},"line",1,[151,156,158],{"class":157},"szBVR","import",[151,160,162],{"class":161},"sVt8B"," {\n",[151,164,166],{"class":153,"line":165},2,[151,167,168],{"class":161},"  definePlugin,\n",[151,170,172,175],{"class":153,"line":171},3,[151,173,174],{"class":157},"  type",[151,176,177],{"class":161}," PluginManifest,\n",[151,179,181,184,187,191],{"class":153,"line":180},4,[151,182,183],{"class":161},"} ",[151,185,186],{"class":157},"from",[151,188,190],{"class":189},"sZZnC"," \"@aurum\u002Fbackend-plugin-sdk\"",[151,192,193],{"class":161},";\n",[151,195,197],{"class":153,"line":196},5,[151,198,200],{"emptyLinePlaceholder":199},true,"\n",[151,202,204,207,211,214,217],{"class":153,"line":203},6,[151,205,206],{"class":157},"const",[151,208,210],{"class":209},"sj4cs"," READ",[151,212,213],{"class":157}," =",[151,215,216],{"class":189}," \"contact-messages.read\"",[151,218,193],{"class":161},[151,220,222,224,227,229,232],{"class":153,"line":221},7,[151,223,206],{"class":157},[151,225,226],{"class":209}," WRITE",[151,228,213],{"class":157},[151,230,231],{"class":189}," \"contact-messages.write\"",[151,233,193],{"class":161},[151,235,237],{"class":153,"line":236},8,[151,238,200],{"emptyLinePlaceholder":199},[151,240,242,245,248,251,253,257,259,262],{"class":153,"line":241},9,[151,243,244],{"class":157},"export",[151,246,247],{"class":157}," const",[151,249,250],{"class":209}," manifest",[151,252,140],{"class":157},[151,254,256],{"class":255},"sScJk"," PluginManifest",[151,258,213],{"class":157},[151,260,261],{"class":255}," definePlugin",[151,263,264],{"class":161},"({\n",[151,266,268,271,274],{"class":153,"line":267},10,[151,269,270],{"class":161},"  id: ",[151,272,273],{"class":189},"\"contact-message\"",[151,275,276],{"class":161},",\n",[151,278,280,283,286],{"class":153,"line":279},11,[151,281,282],{"class":161},"  name: ",[151,284,285],{"class":189},"\"Kontakt\"",[151,287,276],{"class":161},[151,289,291,294,297],{"class":153,"line":290},12,[151,292,293],{"class":161},"  version: ",[151,295,296],{"class":189},"\"1.0.0\"",[151,298,276],{"class":161},[151,300,302,305,308],{"class":153,"line":301},13,[151,303,304],{"class":161},"  sdkVersion: ",[151,306,307],{"class":189},"\"^1.0.0\"",[151,309,276],{"class":161},[151,311,313,316,319,322,325],{"class":153,"line":312},14,[151,314,315],{"class":161},"  permissions: [",[151,317,318],{"class":209},"READ",[151,320,321],{"class":161},", ",[151,323,324],{"class":209},"WRITE",[151,326,327],{"class":161},"],\n",[151,329,331],{"class":153,"line":330},15,[151,332,200],{"emptyLinePlaceholder":199},[151,334,336],{"class":153,"line":335},16,[151,337,338],{"class":161},"  configurationSchema: {\n",[151,340,342,345,348],{"class":153,"line":341},17,[151,343,344],{"class":161},"    type: ",[151,346,347],{"class":189},"\"object\"",[151,349,276],{"class":161},[151,351,353],{"class":153,"line":352},18,[151,354,355],{"class":161},"    required: [\n",[151,357,359,362],{"class":153,"line":358},19,[151,360,361],{"class":189},"      \"retentionDays\"",[151,363,276],{"class":161},[151,365,367,370],{"class":153,"line":366},20,[151,368,369],{"class":189},"      \"publicRateLimit\"",[151,371,276],{"class":161},[151,373,375,378],{"class":153,"line":374},21,[151,376,377],{"class":189},"      \"publicRateLimitWindowSeconds\"",[151,379,276],{"class":161},[151,381,383,386],{"class":153,"line":382},22,[151,384,385],{"class":189},"      \"allowedOrigins\"",[151,387,276],{"class":161},[151,389,391],{"class":153,"line":390},23,[151,392,393],{"class":161},"    ],\n",[151,395,397,400,403],{"class":153,"line":396},24,[151,398,399],{"class":161},"    additionalProperties: ",[151,401,402],{"class":209},"false",[151,404,276],{"class":161},[151,406,408],{"class":153,"line":407},25,[151,409,410],{"class":161},"    properties: {\n",[151,412,414,417,420],{"class":153,"line":413},26,[151,415,416],{"class":161},"      retentionDays: { type: ",[151,418,419],{"class":189},"\"integer\"",[151,421,422],{"class":161}," },\n",[151,424,426,429,431],{"class":153,"line":425},27,[151,427,428],{"class":161},"      publicRateLimit: { type: ",[151,430,419],{"class":189},[151,432,422],{"class":161},[151,434,436,439,441],{"class":153,"line":435},28,[151,437,438],{"class":161},"      publicRateLimitWindowSeconds: { type: ",[151,440,419],{"class":189},[151,442,422],{"class":161},[151,444,446,449,452],{"class":153,"line":445},29,[151,447,448],{"class":161},"      allowedOrigins: { type: ",[151,450,451],{"class":189},"\"array\"",[151,453,422],{"class":161},[151,455,457],{"class":153,"line":456},30,[151,458,459],{"class":161},"    },\n",[151,461,463],{"class":153,"line":462},31,[151,464,465],{"class":161},"  },\n",[151,467,469],{"class":153,"line":468},32,[151,470,200],{"emptyLinePlaceholder":199},[151,472,474],{"class":153,"line":473},33,[151,475,476],{"class":161},"  backend: {\n",[151,478,480],{"class":153,"line":479},34,[151,481,482],{"class":161},"    endpoints: [\n",[151,484,486],{"class":153,"line":485},35,[151,487,488],{"class":161},"      {\n",[151,490,492,495,498],{"class":153,"line":491},36,[151,493,494],{"class":161},"        method: ",[151,496,497],{"class":189},"\"GET\"",[151,499,276],{"class":161},[151,501,503,506,509],{"class":153,"line":502},37,[151,504,505],{"class":161},"        path: ",[151,507,508],{"class":189},"\"\u002Fapi\u002Fcontact-messages\"",[151,510,276],{"class":161},[151,512,514,517,520],{"class":153,"line":513},38,[151,515,516],{"class":161},"        requireAuth: ",[151,518,519],{"class":209},"true",[151,521,276],{"class":161},[151,523,525,528,530],{"class":153,"line":524},39,[151,526,527],{"class":161},"        requirePermission: [",[151,529,318],{"class":209},[151,531,327],{"class":161},[151,533,535,538,541,544,547,551,554,557],{"class":153,"line":534},40,[151,536,537],{"class":255},"        handler",[151,539,540],{"class":161},": ",[151,542,543],{"class":157},"async",[151,545,546],{"class":161}," (",[151,548,550],{"class":549},"s4XuR","request",[151,552,553],{"class":161},") ",[151,555,556],{"class":157},"=>",[151,558,162],{"class":161},[151,560,562,565,568,571],{"class":153,"line":561},41,[151,563,564],{"class":157},"          return",[151,566,567],{"class":161}," request.platform.storage.",[151,569,570],{"class":255},"find",[151,572,573],{"class":161},"(\n",[151,575,577,580],{"class":153,"line":576},42,[151,578,579],{"class":189},"            \"contactMessages\"",[151,581,276],{"class":161},[151,583,585],{"class":153,"line":584},43,[151,586,587],{"class":161},"            {},\n",[151,589,591,594,597,600],{"class":153,"line":590},44,[151,592,593],{"class":161},"            { sort: { createdAt: ",[151,595,596],{"class":157},"-",[151,598,599],{"class":209},"1",[151,601,602],{"class":161}," } },\n",[151,604,606],{"class":153,"line":605},45,[151,607,608],{"class":161},"          );\n",[151,610,612],{"class":153,"line":611},46,[151,613,614],{"class":161},"        },\n",[151,616,618],{"class":153,"line":617},47,[151,619,620],{"class":161},"      },\n",[151,622,624],{"class":153,"line":623},48,[151,625,393],{"class":161},[151,627,629],{"class":153,"line":628},49,[151,630,465],{"class":161},[151,632,634],{"class":153,"line":633},50,[151,635,636],{"class":161},"});\n",[15,638,639,642],{},[130,640,641],{},"sdkVersion"," jest zakresem SemVer, a nie numerem dekoracyjnym. Registry odrzuca manifest, jeżeli aktywny runtime nie spełnia deklarowanego zakresu. Identyfikatory uprawnień muszą być unikalne, a każdy endpoint jawnie określa uwierzytelnienie i wymagane capabilities.",[10,644,646],{"id":645},"endpoint-publiczny-z-kontrolą-origin-i-rate-limitingiem","Endpoint publiczny z kontrolą origin i rate limitingiem",[15,648,649],{},"Publiczny formularz kontaktowy nie omija runtime. Endpoint może być anonimowy, ale nadal korzysta z walidowanej konfiguracji, limitera izolowanego per plugin, prywatnego storage i audytu:",[142,651,653],{"className":144,"code":652,"language":146,"meta":147,"style":147},"{\n  method: \"POST\",\n  path: \"\u002Fapi\u002Fcontact-messages\",\n  requireAuth: false,\n  requirePermission: [],\n  handler: async (request, reply) => {\n    const config = request.platform.configuration;\n    const origin = request.headers.origin;\n\n    if (\n      origin &&\n      !config.allowedOrigins.includes(origin)\n    ) {\n      return reply.code(403).send({\n        error: \"Origin is not allowed\",\n      });\n    }\n\n    const accepted = await request.platform.rateLimit.consume(\n      request.ip,\n      {\n        limit: config.publicRateLimit,\n        windowMilliseconds:\n          config.publicRateLimitWindowSeconds * 1_000,\n      },\n    );\n\n    if (!accepted) {\n      return reply.code(429).send({\n        error: \"Too many contact messages\",\n      });\n    }\n\n    const message = {\n      _id: crypto.randomUUID(),\n      ...request.body,\n      read: false,\n      createdAt: new Date().toISOString(),\n    };\n\n    await request.platform.storage.insertOne(\n      \"contactMessages\",\n      message,\n    );\n    await request.platform.audit.write(\n      \"contact_message.created\",\n      { messageId: message._id },\n    );\n\n    return reply.code(201).send(message);\n  },\n}\n",[130,654,655,660,672,683,694,702,726,739,751,755,763,771,785,790,814,824,829,834,838,858,863,867,872,877,890,894,899,903,915,934,943,947,951,955,966,977,985,994,1013,1018,1022,1034,1041,1046,1050,1062,1069,1074,1078,1082,1103,1108],{"__ignoreMap":147},[151,656,657],{"class":153,"line":154},[151,658,659],{"class":161},"{\n",[151,661,662,665,667,670],{"class":153,"line":165},[151,663,664],{"class":255},"  method",[151,666,540],{"class":161},[151,668,669],{"class":189},"\"POST\"",[151,671,276],{"class":161},[151,673,674,677,679,681],{"class":153,"line":171},[151,675,676],{"class":255},"  path",[151,678,540],{"class":161},[151,680,508],{"class":189},[151,682,276],{"class":161},[151,684,685,688,690,692],{"class":153,"line":180},[151,686,687],{"class":255},"  requireAuth",[151,689,540],{"class":161},[151,691,402],{"class":209},[151,693,276],{"class":161},[151,695,696,699],{"class":153,"line":196},[151,697,698],{"class":255},"  requirePermission",[151,700,701],{"class":161},": [],\n",[151,703,704,707,709,711,713,715,717,720,722,724],{"class":153,"line":203},[151,705,706],{"class":255},"  handler",[151,708,540],{"class":161},[151,710,543],{"class":157},[151,712,546],{"class":161},[151,714,550],{"class":549},[151,716,321],{"class":161},[151,718,719],{"class":549},"reply",[151,721,553],{"class":161},[151,723,556],{"class":157},[151,725,162],{"class":161},[151,727,728,731,734,736],{"class":153,"line":221},[151,729,730],{"class":157},"    const",[151,732,733],{"class":209}," config",[151,735,213],{"class":157},[151,737,738],{"class":161}," request.platform.configuration;\n",[151,740,741,743,746,748],{"class":153,"line":236},[151,742,730],{"class":157},[151,744,745],{"class":209}," origin",[151,747,213],{"class":157},[151,749,750],{"class":161}," request.headers.origin;\n",[151,752,753],{"class":153,"line":241},[151,754,200],{"emptyLinePlaceholder":199},[151,756,757,760],{"class":153,"line":267},[151,758,759],{"class":157},"    if",[151,761,762],{"class":161}," (\n",[151,764,765,768],{"class":153,"line":279},[151,766,767],{"class":161},"      origin ",[151,769,770],{"class":157},"&&\n",[151,772,773,776,779,782],{"class":153,"line":290},[151,774,775],{"class":157},"      !",[151,777,778],{"class":161},"config.allowedOrigins.",[151,780,781],{"class":255},"includes",[151,783,784],{"class":161},"(origin)\n",[151,786,787],{"class":153,"line":301},[151,788,789],{"class":161},"    ) {\n",[151,791,792,795,798,800,803,806,809,812],{"class":153,"line":312},[151,793,794],{"class":157},"      return",[151,796,797],{"class":161}," reply.",[151,799,130],{"class":255},[151,801,802],{"class":161},"(",[151,804,805],{"class":209},"403",[151,807,808],{"class":161},").",[151,810,811],{"class":255},"send",[151,813,264],{"class":161},[151,815,816,819,822],{"class":153,"line":330},[151,817,818],{"class":161},"        error: ",[151,820,821],{"class":189},"\"Origin is not allowed\"",[151,823,276],{"class":161},[151,825,826],{"class":153,"line":335},[151,827,828],{"class":161},"      });\n",[151,830,831],{"class":153,"line":341},[151,832,833],{"class":161},"    }\n",[151,835,836],{"class":153,"line":352},[151,837,200],{"emptyLinePlaceholder":199},[151,839,840,842,845,847,850,853,856],{"class":153,"line":358},[151,841,730],{"class":157},[151,843,844],{"class":209}," accepted",[151,846,213],{"class":157},[151,848,849],{"class":157}," await",[151,851,852],{"class":161}," request.platform.rateLimit.",[151,854,855],{"class":255},"consume",[151,857,573],{"class":161},[151,859,860],{"class":153,"line":366},[151,861,862],{"class":161},"      request.ip,\n",[151,864,865],{"class":153,"line":374},[151,866,488],{"class":161},[151,868,869],{"class":153,"line":382},[151,870,871],{"class":161},"        limit: config.publicRateLimit,\n",[151,873,874],{"class":153,"line":390},[151,875,876],{"class":161},"        windowMilliseconds:\n",[151,878,879,882,885,888],{"class":153,"line":396},[151,880,881],{"class":161},"          config.publicRateLimitWindowSeconds ",[151,883,884],{"class":157},"*",[151,886,887],{"class":209}," 1_000",[151,889,276],{"class":161},[151,891,892],{"class":153,"line":407},[151,893,620],{"class":161},[151,895,896],{"class":153,"line":413},[151,897,898],{"class":161},"    );\n",[151,900,901],{"class":153,"line":425},[151,902,200],{"emptyLinePlaceholder":199},[151,904,905,907,909,912],{"class":153,"line":435},[151,906,759],{"class":157},[151,908,546],{"class":161},[151,910,911],{"class":157},"!",[151,913,914],{"class":161},"accepted) {\n",[151,916,917,919,921,923,925,928,930,932],{"class":153,"line":445},[151,918,794],{"class":157},[151,920,797],{"class":161},[151,922,130],{"class":255},[151,924,802],{"class":161},[151,926,927],{"class":209},"429",[151,929,808],{"class":161},[151,931,811],{"class":255},[151,933,264],{"class":161},[151,935,936,938,941],{"class":153,"line":456},[151,937,818],{"class":161},[151,939,940],{"class":189},"\"Too many contact messages\"",[151,942,276],{"class":161},[151,944,945],{"class":153,"line":462},[151,946,828],{"class":161},[151,948,949],{"class":153,"line":468},[151,950,833],{"class":161},[151,952,953],{"class":153,"line":473},[151,954,200],{"emptyLinePlaceholder":199},[151,956,957,959,962,964],{"class":153,"line":479},[151,958,730],{"class":157},[151,960,961],{"class":209}," message",[151,963,213],{"class":157},[151,965,162],{"class":161},[151,967,968,971,974],{"class":153,"line":485},[151,969,970],{"class":161},"      _id: crypto.",[151,972,973],{"class":255},"randomUUID",[151,975,976],{"class":161},"(),\n",[151,978,979,982],{"class":153,"line":491},[151,980,981],{"class":157},"      ...",[151,983,984],{"class":161},"request.body,\n",[151,986,987,990,992],{"class":153,"line":502},[151,988,989],{"class":161},"      read: ",[151,991,402],{"class":209},[151,993,276],{"class":161},[151,995,996,999,1002,1005,1008,1011],{"class":153,"line":513},[151,997,998],{"class":161},"      createdAt: ",[151,1000,1001],{"class":157},"new",[151,1003,1004],{"class":255}," Date",[151,1006,1007],{"class":161},"().",[151,1009,1010],{"class":255},"toISOString",[151,1012,976],{"class":161},[151,1014,1015],{"class":153,"line":524},[151,1016,1017],{"class":161},"    };\n",[151,1019,1020],{"class":153,"line":534},[151,1021,200],{"emptyLinePlaceholder":199},[151,1023,1024,1027,1029,1032],{"class":153,"line":561},[151,1025,1026],{"class":157},"    await",[151,1028,567],{"class":161},[151,1030,1031],{"class":255},"insertOne",[151,1033,573],{"class":161},[151,1035,1036,1039],{"class":153,"line":576},[151,1037,1038],{"class":189},"      \"contactMessages\"",[151,1040,276],{"class":161},[151,1042,1043],{"class":153,"line":584},[151,1044,1045],{"class":161},"      message,\n",[151,1047,1048],{"class":153,"line":590},[151,1049,898],{"class":161},[151,1051,1052,1054,1057,1060],{"class":153,"line":605},[151,1053,1026],{"class":157},[151,1055,1056],{"class":161}," request.platform.audit.",[151,1058,1059],{"class":255},"write",[151,1061,573],{"class":161},[151,1063,1064,1067],{"class":153,"line":611},[151,1065,1066],{"class":189},"      \"contact_message.created\"",[151,1068,276],{"class":161},[151,1070,1071],{"class":153,"line":617},[151,1072,1073],{"class":161},"      { messageId: message._id },\n",[151,1075,1076],{"class":153,"line":623},[151,1077,898],{"class":161},[151,1079,1080],{"class":153,"line":628},[151,1081,200],{"emptyLinePlaceholder":199},[151,1083,1084,1087,1089,1091,1093,1096,1098,1100],{"class":153,"line":633},[151,1085,1086],{"class":157},"    return",[151,1088,797],{"class":161},[151,1090,130],{"class":255},[151,1092,802],{"class":161},[151,1094,1095],{"class":209},"201",[151,1097,808],{"class":161},[151,1099,811],{"class":255},[151,1101,1102],{"class":161},"(message);\n",[151,1104,1106],{"class":153,"line":1105},51,[151,1107,465],{"class":161},[151,1109,1111],{"class":153,"line":1110},52,[151,1112,1113],{"class":161},"}\n",[10,1115,1117],{"id":1116},"capability-api-zamiast-surowego-dostępu","Capability API zamiast surowego dostępu",[15,1119,1120,1121,140],{},"Handler nie otrzymuje instancji klienta MongoDB ani swobodnego dostępu do serwera Fastify. Runtime wstrzykuje ograniczony ",[130,1122,1123],{},"PlatformCapabilities",[142,1125,1127],{"className":144,"code":1126,"language":146,"meta":147,"style":147},"export interface PlatformCapabilities {\n  readonly pluginId: string;\n  readonly requestId: string;\n  readonly configuration: Readonly\u003CRecord\u003Cstring, unknown>>;\n\n  readonly audit: {\n    write(\n      event: string,\n      details?: Record\u003Cstring, unknown>,\n    ): Promise\u003Cvoid>;\n  };\n\n  readonly storage: {\n    find\u003CT>(\n      collection: string,\n      filter?: Record\u003Cstring, unknown>,\n    ): Promise\u003CT[]>;\n    insertOne\u003CT>(\n      collection: string,\n      document: T,\n    ): Promise\u003Cvoid>;\n    ensureIndex(\n      collection: string,\n      keys: Record\u003Cstring, 1 | -1>,\n      options?: {\n        unique?: boolean;\n        expireAfterSeconds?: number;\n      },\n    ): Promise\u003Cvoid>;\n  };\n\n  readonly rateLimit: {\n    consume(\n      subject: string,\n      policy: {\n        limit: number;\n        windowMilliseconds: number;\n      },\n    ): Promise\u003Cboolean>;\n  };\n}\n",[130,1128,1129,1141,1156,1169,1200,1204,1215,1222,1233,1255,1273,1278,1282,1293,1306,1317,1336,1351,1362,1372,1384,1398,1405,1415,1442,1451,1463,1475,1479,1493,1497,1501,1512,1519,1530,1539,1550,1561,1565,1580,1584],{"__ignoreMap":147},[151,1130,1131,1133,1136,1139],{"class":153,"line":154},[151,1132,244],{"class":157},[151,1134,1135],{"class":157}," interface",[151,1137,1138],{"class":255}," PlatformCapabilities",[151,1140,162],{"class":161},[151,1142,1143,1146,1149,1151,1154],{"class":153,"line":165},[151,1144,1145],{"class":157},"  readonly",[151,1147,1148],{"class":549}," pluginId",[151,1150,140],{"class":157},[151,1152,1153],{"class":209}," string",[151,1155,193],{"class":161},[151,1157,1158,1160,1163,1165,1167],{"class":153,"line":171},[151,1159,1145],{"class":157},[151,1161,1162],{"class":549}," requestId",[151,1164,140],{"class":157},[151,1166,1153],{"class":209},[151,1168,193],{"class":161},[151,1170,1171,1173,1176,1178,1181,1184,1187,1189,1192,1194,1197],{"class":153,"line":180},[151,1172,1145],{"class":157},[151,1174,1175],{"class":549}," configuration",[151,1177,140],{"class":157},[151,1179,1180],{"class":255}," Readonly",[151,1182,1183],{"class":161},"\u003C",[151,1185,1186],{"class":255},"Record",[151,1188,1183],{"class":161},[151,1190,1191],{"class":209},"string",[151,1193,321],{"class":161},[151,1195,1196],{"class":209},"unknown",[151,1198,1199],{"class":161},">>;\n",[151,1201,1202],{"class":153,"line":196},[151,1203,200],{"emptyLinePlaceholder":199},[151,1205,1206,1208,1211,1213],{"class":153,"line":203},[151,1207,1145],{"class":157},[151,1209,1210],{"class":549}," audit",[151,1212,140],{"class":157},[151,1214,162],{"class":161},[151,1216,1217,1220],{"class":153,"line":221},[151,1218,1219],{"class":255},"    write",[151,1221,573],{"class":161},[151,1223,1224,1227,1229,1231],{"class":153,"line":236},[151,1225,1226],{"class":549},"      event",[151,1228,140],{"class":157},[151,1230,1153],{"class":209},[151,1232,276],{"class":161},[151,1234,1235,1238,1241,1244,1246,1248,1250,1252],{"class":153,"line":241},[151,1236,1237],{"class":549},"      details",[151,1239,1240],{"class":157},"?:",[151,1242,1243],{"class":255}," Record",[151,1245,1183],{"class":161},[151,1247,1191],{"class":209},[151,1249,321],{"class":161},[151,1251,1196],{"class":209},[151,1253,1254],{"class":161},">,\n",[151,1256,1257,1260,1262,1265,1267,1270],{"class":153,"line":267},[151,1258,1259],{"class":161},"    )",[151,1261,140],{"class":157},[151,1263,1264],{"class":255}," Promise",[151,1266,1183],{"class":161},[151,1268,1269],{"class":209},"void",[151,1271,1272],{"class":161},">;\n",[151,1274,1275],{"class":153,"line":279},[151,1276,1277],{"class":161},"  };\n",[151,1279,1280],{"class":153,"line":290},[151,1281,200],{"emptyLinePlaceholder":199},[151,1283,1284,1286,1289,1291],{"class":153,"line":301},[151,1285,1145],{"class":157},[151,1287,1288],{"class":549}," storage",[151,1290,140],{"class":157},[151,1292,162],{"class":161},[151,1294,1295,1298,1300,1303],{"class":153,"line":312},[151,1296,1297],{"class":255},"    find",[151,1299,1183],{"class":161},[151,1301,1302],{"class":255},"T",[151,1304,1305],{"class":161},">(\n",[151,1307,1308,1311,1313,1315],{"class":153,"line":330},[151,1309,1310],{"class":549},"      collection",[151,1312,140],{"class":157},[151,1314,1153],{"class":209},[151,1316,276],{"class":161},[151,1318,1319,1322,1324,1326,1328,1330,1332,1334],{"class":153,"line":335},[151,1320,1321],{"class":549},"      filter",[151,1323,1240],{"class":157},[151,1325,1243],{"class":255},[151,1327,1183],{"class":161},[151,1329,1191],{"class":209},[151,1331,321],{"class":161},[151,1333,1196],{"class":209},[151,1335,1254],{"class":161},[151,1337,1338,1340,1342,1344,1346,1348],{"class":153,"line":341},[151,1339,1259],{"class":161},[151,1341,140],{"class":157},[151,1343,1264],{"class":255},[151,1345,1183],{"class":161},[151,1347,1302],{"class":255},[151,1349,1350],{"class":161},"[]>;\n",[151,1352,1353,1356,1358,1360],{"class":153,"line":352},[151,1354,1355],{"class":255},"    insertOne",[151,1357,1183],{"class":161},[151,1359,1302],{"class":255},[151,1361,1305],{"class":161},[151,1363,1364,1366,1368,1370],{"class":153,"line":358},[151,1365,1310],{"class":549},[151,1367,140],{"class":157},[151,1369,1153],{"class":209},[151,1371,276],{"class":161},[151,1373,1374,1377,1379,1382],{"class":153,"line":366},[151,1375,1376],{"class":549},"      document",[151,1378,140],{"class":157},[151,1380,1381],{"class":255}," T",[151,1383,276],{"class":161},[151,1385,1386,1388,1390,1392,1394,1396],{"class":153,"line":374},[151,1387,1259],{"class":161},[151,1389,140],{"class":157},[151,1391,1264],{"class":255},[151,1393,1183],{"class":161},[151,1395,1269],{"class":209},[151,1397,1272],{"class":161},[151,1399,1400,1403],{"class":153,"line":382},[151,1401,1402],{"class":255},"    ensureIndex",[151,1404,573],{"class":161},[151,1406,1407,1409,1411,1413],{"class":153,"line":390},[151,1408,1310],{"class":549},[151,1410,140],{"class":157},[151,1412,1153],{"class":209},[151,1414,276],{"class":161},[151,1416,1417,1420,1422,1424,1426,1428,1430,1432,1435,1438,1440],{"class":153,"line":396},[151,1418,1419],{"class":549},"      keys",[151,1421,140],{"class":157},[151,1423,1243],{"class":255},[151,1425,1183],{"class":161},[151,1427,1191],{"class":209},[151,1429,321],{"class":161},[151,1431,599],{"class":209},[151,1433,1434],{"class":157}," |",[151,1436,1437],{"class":161}," -",[151,1439,599],{"class":209},[151,1441,1254],{"class":161},[151,1443,1444,1447,1449],{"class":153,"line":407},[151,1445,1446],{"class":549},"      options",[151,1448,1240],{"class":157},[151,1450,162],{"class":161},[151,1452,1453,1456,1458,1461],{"class":153,"line":413},[151,1454,1455],{"class":549},"        unique",[151,1457,1240],{"class":157},[151,1459,1460],{"class":209}," boolean",[151,1462,193],{"class":161},[151,1464,1465,1468,1470,1473],{"class":153,"line":425},[151,1466,1467],{"class":549},"        expireAfterSeconds",[151,1469,1240],{"class":157},[151,1471,1472],{"class":209}," number",[151,1474,193],{"class":161},[151,1476,1477],{"class":153,"line":435},[151,1478,620],{"class":161},[151,1480,1481,1483,1485,1487,1489,1491],{"class":153,"line":445},[151,1482,1259],{"class":161},[151,1484,140],{"class":157},[151,1486,1264],{"class":255},[151,1488,1183],{"class":161},[151,1490,1269],{"class":209},[151,1492,1272],{"class":161},[151,1494,1495],{"class":153,"line":456},[151,1496,1277],{"class":161},[151,1498,1499],{"class":153,"line":462},[151,1500,200],{"emptyLinePlaceholder":199},[151,1502,1503,1505,1508,1510],{"class":153,"line":468},[151,1504,1145],{"class":157},[151,1506,1507],{"class":549}," rateLimit",[151,1509,140],{"class":157},[151,1511,162],{"class":161},[151,1513,1514,1517],{"class":153,"line":473},[151,1515,1516],{"class":255},"    consume",[151,1518,573],{"class":161},[151,1520,1521,1524,1526,1528],{"class":153,"line":479},[151,1522,1523],{"class":549},"      subject",[151,1525,140],{"class":157},[151,1527,1153],{"class":209},[151,1529,276],{"class":161},[151,1531,1532,1535,1537],{"class":153,"line":485},[151,1533,1534],{"class":549},"      policy",[151,1536,140],{"class":157},[151,1538,162],{"class":161},[151,1540,1541,1544,1546,1548],{"class":153,"line":491},[151,1542,1543],{"class":549},"        limit",[151,1545,140],{"class":157},[151,1547,1472],{"class":209},[151,1549,193],{"class":161},[151,1551,1552,1555,1557,1559],{"class":153,"line":502},[151,1553,1554],{"class":549},"        windowMilliseconds",[151,1556,140],{"class":157},[151,1558,1472],{"class":209},[151,1560,193],{"class":161},[151,1562,1563],{"class":153,"line":513},[151,1564,620],{"class":161},[151,1566,1567,1569,1571,1573,1575,1578],{"class":153,"line":524},[151,1568,1259],{"class":161},[151,1570,140],{"class":157},[151,1572,1264],{"class":255},[151,1574,1183],{"class":161},[151,1576,1577],{"class":209},"boolean",[151,1579,1272],{"class":161},[151,1581,1582],{"class":153,"line":534},[151,1583,1277],{"class":161},[151,1585,1586],{"class":153,"line":561},[151,1587,1113],{"class":161},[15,1589,1590,1591,1594,1595,1598],{},"Warstwa storage automatycznie namespace’uje kolekcje identyfikatorem pluginu. Wywołanie ",[130,1592,1593],{},"storage.find(\"messages\")"," nie może odczytać kolekcji ",[130,1596,1597],{},"messages"," należącej do innego rozszerzenia.",[10,1600,1602],{"id":1601},"uprawnienia-per-endpoint-i-scope","Uprawnienia per endpoint i scope",[15,1604,1605,1606,1609],{},"Endpoint może wymagać wszystkich capabilities lub dowolnej z nich. Opcjonalny ",[130,1607,1608],{},"scopeParam"," łączy parametr trasy z ograniczonym grantem użytkownika:",[142,1611,1613],{"className":144,"code":1612,"language":146,"meta":147,"style":147},"{\n  method: \"PATCH\",\n  path: \"\u002Fapi\u002Fprojects\u002F:projectId\u002Fcontent\u002F:id\",\n  requireAuth: true,\n  requirePermission: [\n    \"content.read\",\n    \"content.write\",\n  ],\n  permissionMode: \"all\",\n  scopeParam: \"projectId\",\n  handler: updateContent,\n}\n",[130,1614,1615,1619,1630,1641,1651,1658,1665,1672,1677,1689,1701,1708],{"__ignoreMap":147},[151,1616,1617],{"class":153,"line":154},[151,1618,659],{"class":161},[151,1620,1621,1623,1625,1628],{"class":153,"line":165},[151,1622,664],{"class":255},[151,1624,540],{"class":161},[151,1626,1627],{"class":189},"\"PATCH\"",[151,1629,276],{"class":161},[151,1631,1632,1634,1636,1639],{"class":153,"line":171},[151,1633,676],{"class":255},[151,1635,540],{"class":161},[151,1637,1638],{"class":189},"\"\u002Fapi\u002Fprojects\u002F:projectId\u002Fcontent\u002F:id\"",[151,1640,276],{"class":161},[151,1642,1643,1645,1647,1649],{"class":153,"line":180},[151,1644,687],{"class":255},[151,1646,540],{"class":161},[151,1648,519],{"class":209},[151,1650,276],{"class":161},[151,1652,1653,1655],{"class":153,"line":196},[151,1654,698],{"class":255},[151,1656,1657],{"class":161},": [\n",[151,1659,1660,1663],{"class":153,"line":203},[151,1661,1662],{"class":189},"    \"content.read\"",[151,1664,276],{"class":161},[151,1666,1667,1670],{"class":153,"line":221},[151,1668,1669],{"class":189},"    \"content.write\"",[151,1671,276],{"class":161},[151,1673,1674],{"class":153,"line":236},[151,1675,1676],{"class":161},"  ],\n",[151,1678,1679,1682,1684,1687],{"class":153,"line":241},[151,1680,1681],{"class":255},"  permissionMode",[151,1683,540],{"class":161},[151,1685,1686],{"class":189},"\"all\"",[151,1688,276],{"class":161},[151,1690,1691,1694,1696,1699],{"class":153,"line":267},[151,1692,1693],{"class":255},"  scopeParam",[151,1695,540],{"class":161},[151,1697,1698],{"class":189},"\"projectId\"",[151,1700,276],{"class":161},[151,1702,1703,1705],{"class":153,"line":279},[151,1704,706],{"class":255},[151,1706,1707],{"class":161},": updateContent,\n",[151,1709,1710],{"class":153,"line":290},[151,1711,1113],{"class":161},[15,1713,1714,1715,1718,1719,1722,1723,1726],{},"Grant ",[130,1716,1717],{},"content.write"," dla scope ",[130,1720,1721],{},"gardenia"," nie daje prawa zapisu w scope ",[130,1724,1725],{},"park-43",". Weryfikacja odbywa się w gatewayu przed uruchomieniem handlera pluginu.",[10,1728,1730,1731],{"id":1729},"deklaratywny-plugin-setyaml","Deklaratywny ",[130,1732,1733],{},"plugin-set.yaml",[15,1735,1736,1737,1740,1741,1744],{},"Operator obserwuje zasoby ",[130,1738,1739],{},"AurumPluginSet"," w grupie ",[130,1742,1743],{},"aurum.dev\u002Fv1alpha1",". Zestaw opisuje docelowe Deploymenty oraz dokładne obrazy pluginów:",[142,1746,1750],{"className":1747,"code":1748,"language":1749,"meta":147,"style":147},"language-yaml shiki shiki-themes github-light github-dark","apiVersion: aurum.dev\u002Fv1alpha1\nkind: AurumPluginSet\nmetadata:\n  name: portfolio-platform\n  namespace: gardenia\nspec:\n  applicationRef:\n    targets:\n      - deployment: backend\n        container: backend\n        pluginMountPath: \u002Fapp\u002Fplugins\n      - deployment: frontend\n        container: nginx\n        pluginMountPath: \u002Fusr\u002Fshare\u002Fnginx\u002Fhtml\u002Fplugins\n\n  plugins:\n    - id: contact-message\n      image: europe-west1-docker.pkg.dev\u002Fplatform\u002Faurum\u002Fcontact-message\n      version: 1.0.0\n      digest: sha256:2f36f2c7e5b7c18d81d73ca5e5a7e3b1d9b08a358af7f9b0b1f44f617db45a12\n      configuration:\n        retentionDays: 365\n        publicRateLimit: 5\n        publicRateLimitWindowSeconds: 60\n        allowedOrigins:\n          - https:\u002F\u002Fgardenia.example\n\n    - id: real-estate\n      image: europe-west1-docker.pkg.dev\u002Fplatform\u002Faurum\u002Freal-estate\n      version: 1.0.0\n      tag: 1.0.0\n","yaml",[130,1751,1752,1763,1773,1781,1791,1801,1808,1815,1822,1835,1844,1854,1865,1874,1883,1887,1894,1907,1917,1927,1937,1944,1954,1964,1974,1981,1989,1993,2004,2013,2021],{"__ignoreMap":147},[151,1753,1754,1758,1760],{"class":153,"line":154},[151,1755,1757],{"class":1756},"s9eBZ","apiVersion",[151,1759,540],{"class":161},[151,1761,1762],{"class":189},"aurum.dev\u002Fv1alpha1\n",[151,1764,1765,1768,1770],{"class":153,"line":165},[151,1766,1767],{"class":1756},"kind",[151,1769,540],{"class":161},[151,1771,1772],{"class":189},"AurumPluginSet\n",[151,1774,1775,1778],{"class":153,"line":171},[151,1776,1777],{"class":1756},"metadata",[151,1779,1780],{"class":161},":\n",[151,1782,1783,1786,1788],{"class":153,"line":180},[151,1784,1785],{"class":1756},"  name",[151,1787,540],{"class":161},[151,1789,1790],{"class":189},"portfolio-platform\n",[151,1792,1793,1796,1798],{"class":153,"line":196},[151,1794,1795],{"class":1756},"  namespace",[151,1797,540],{"class":161},[151,1799,1800],{"class":189},"gardenia\n",[151,1802,1803,1806],{"class":153,"line":203},[151,1804,1805],{"class":1756},"spec",[151,1807,1780],{"class":161},[151,1809,1810,1813],{"class":153,"line":221},[151,1811,1812],{"class":1756},"  applicationRef",[151,1814,1780],{"class":161},[151,1816,1817,1820],{"class":153,"line":236},[151,1818,1819],{"class":1756},"    targets",[151,1821,1780],{"class":161},[151,1823,1824,1827,1830,1832],{"class":153,"line":241},[151,1825,1826],{"class":161},"      - ",[151,1828,1829],{"class":1756},"deployment",[151,1831,540],{"class":161},[151,1833,1834],{"class":189},"backend\n",[151,1836,1837,1840,1842],{"class":153,"line":267},[151,1838,1839],{"class":1756},"        container",[151,1841,540],{"class":161},[151,1843,1834],{"class":189},[151,1845,1846,1849,1851],{"class":153,"line":279},[151,1847,1848],{"class":1756},"        pluginMountPath",[151,1850,540],{"class":161},[151,1852,1853],{"class":189},"\u002Fapp\u002Fplugins\n",[151,1855,1856,1858,1860,1862],{"class":153,"line":290},[151,1857,1826],{"class":161},[151,1859,1829],{"class":1756},[151,1861,540],{"class":161},[151,1863,1864],{"class":189},"frontend\n",[151,1866,1867,1869,1871],{"class":153,"line":301},[151,1868,1839],{"class":1756},[151,1870,540],{"class":161},[151,1872,1873],{"class":189},"nginx\n",[151,1875,1876,1878,1880],{"class":153,"line":312},[151,1877,1848],{"class":1756},[151,1879,540],{"class":161},[151,1881,1882],{"class":189},"\u002Fusr\u002Fshare\u002Fnginx\u002Fhtml\u002Fplugins\n",[151,1884,1885],{"class":153,"line":330},[151,1886,200],{"emptyLinePlaceholder":199},[151,1888,1889,1892],{"class":153,"line":335},[151,1890,1891],{"class":1756},"  plugins",[151,1893,1780],{"class":161},[151,1895,1896,1899,1902,1904],{"class":153,"line":341},[151,1897,1898],{"class":161},"    - ",[151,1900,1901],{"class":1756},"id",[151,1903,540],{"class":161},[151,1905,1906],{"class":189},"contact-message\n",[151,1908,1909,1912,1914],{"class":153,"line":352},[151,1910,1911],{"class":1756},"      image",[151,1913,540],{"class":161},[151,1915,1916],{"class":189},"europe-west1-docker.pkg.dev\u002Fplatform\u002Faurum\u002Fcontact-message\n",[151,1918,1919,1922,1924],{"class":153,"line":358},[151,1920,1921],{"class":1756},"      version",[151,1923,540],{"class":161},[151,1925,1926],{"class":209},"1.0.0\n",[151,1928,1929,1932,1934],{"class":153,"line":366},[151,1930,1931],{"class":1756},"      digest",[151,1933,540],{"class":161},[151,1935,1936],{"class":189},"sha256:2f36f2c7e5b7c18d81d73ca5e5a7e3b1d9b08a358af7f9b0b1f44f617db45a12\n",[151,1938,1939,1942],{"class":153,"line":374},[151,1940,1941],{"class":1756},"      configuration",[151,1943,1780],{"class":161},[151,1945,1946,1949,1951],{"class":153,"line":382},[151,1947,1948],{"class":1756},"        retentionDays",[151,1950,540],{"class":161},[151,1952,1953],{"class":209},"365\n",[151,1955,1956,1959,1961],{"class":153,"line":390},[151,1957,1958],{"class":1756},"        publicRateLimit",[151,1960,540],{"class":161},[151,1962,1963],{"class":209},"5\n",[151,1965,1966,1969,1971],{"class":153,"line":396},[151,1967,1968],{"class":1756},"        publicRateLimitWindowSeconds",[151,1970,540],{"class":161},[151,1972,1973],{"class":209},"60\n",[151,1975,1976,1979],{"class":153,"line":407},[151,1977,1978],{"class":1756},"        allowedOrigins",[151,1980,1780],{"class":161},[151,1982,1983,1986],{"class":153,"line":413},[151,1984,1985],{"class":161},"          - ",[151,1987,1988],{"class":189},"https:\u002F\u002Fgardenia.example\n",[151,1990,1991],{"class":153,"line":425},[151,1992,200],{"emptyLinePlaceholder":199},[151,1994,1995,1997,1999,2001],{"class":153,"line":435},[151,1996,1898],{"class":161},[151,1998,1901],{"class":1756},[151,2000,540],{"class":161},[151,2002,2003],{"class":189},"real-estate\n",[151,2005,2006,2008,2010],{"class":153,"line":445},[151,2007,1911],{"class":1756},[151,2009,540],{"class":161},[151,2011,2012],{"class":189},"europe-west1-docker.pkg.dev\u002Fplatform\u002Faurum\u002Freal-estate\n",[151,2014,2015,2017,2019],{"class":153,"line":456},[151,2016,1921],{"class":1756},[151,2018,540],{"class":161},[151,2020,1926],{"class":209},[151,2022,2023,2026,2028],{"class":153,"line":462},[151,2024,2025],{"class":1756},"      tag",[151,2027,540],{"class":161},[151,2029,1926],{"class":209},[15,2031,2032,2033,2036,2037,2040,2041,2043,2044,2047],{},"Plugin musi używać dokładnie jednego poprawnego ",[130,2034,2035],{},"digest"," albo ",[130,2038,2039],{},"tag",". Dla wdrożeń produkcyjnych digest wiąże deklarację z niezmiennym obrazem. Duplikaty ",[130,2042,1901],{},", niepoprawne nazwy oraz względny ",[130,2045,2046],{},"pluginMountPath"," są odrzucane przed zmianą Deploymentu.",[10,2049,2051],{"id":2050},"jak-operator-modyfikuje-deployment","Jak operator modyfikuje Deployment",[15,2053,2054],{},"Dla każdego targetu operator:",[58,2056,2057,2064,2067,2070,2073],{},[32,2058,2059,2060,2063],{},"tworzy współdzielony wolumen ",[130,2061,2062],{},"emptyDir"," z limitem;",[32,2065,2066],{},"montuje go tylko do zadeklarowanej ścieżki pluginów;",[32,2068,2069],{},"generuje kontrolowany init container dla każdego obrazu;",[32,2071,2072],{},"przekazuje identyfikator, wersję i konfigurację jako jawne zmienne;",[32,2074,2075],{},"oblicza SHA-256 całego zestawu i zapisuje go w adnotacji PodTemplate.",[15,2077,2078],{},"Uproszczona transformacja wygląda tak:",[142,2080,2082],{"className":144,"code":2081,"language":146,"meta":147,"style":147},"const pluginMount = {\n  name: \"aurum-plugins\",\n  mountPath: target.pluginMountPath,\n  readOnly: true,\n};\n\ntemplate.spec.volumes = [{\n  name: \"aurum-plugins\",\n  emptyDir: { sizeLimit: \"256Mi\" },\n}];\n\ntemplate.spec.initContainers = set.spec.plugins.map(\n  (plugin) => ({\n    name: `aurum-plugin-${plugin.id}`,\n    image: plugin.digest\n      ? `${plugin.image}@${plugin.digest}`\n      : `${plugin.image}:${plugin.tag}`,\n    env: [\n      { name: \"PLUGIN_ID\", value: plugin.id },\n      { name: \"PLUGIN_VERSION\", value: plugin.version },\n      {\n        name: \"PLUGIN_CONFIGURATION\",\n        value: JSON.stringify(plugin.configuration ?? {}),\n      },\n    ],\n    volumeMounts: [{\n      name: \"aurum-plugins\",\n      mountPath: \"\u002Fplugins\",\n    }],\n  }),\n);\n\ntemplate.metadata.annotations[\n  \"aurum.dev\u002Fplugin-hash\"\n] = sha256({ target, plugins: set.spec.plugins });\n",[130,2083,2084,2095,2104,2109,2118,2123,2127,2138,2146,2156,2161,2165,2180,2195,2215,2220,2247,2273,2278,2289,2299,2303,2313,2335,2339,2343,2348,2357,2367,2372,2377,2382,2386,2391,2396],{"__ignoreMap":147},[151,2085,2086,2088,2091,2093],{"class":153,"line":154},[151,2087,206],{"class":157},[151,2089,2090],{"class":209}," pluginMount",[151,2092,213],{"class":157},[151,2094,162],{"class":161},[151,2096,2097,2099,2102],{"class":153,"line":165},[151,2098,282],{"class":161},[151,2100,2101],{"class":189},"\"aurum-plugins\"",[151,2103,276],{"class":161},[151,2105,2106],{"class":153,"line":171},[151,2107,2108],{"class":161},"  mountPath: target.pluginMountPath,\n",[151,2110,2111,2114,2116],{"class":153,"line":180},[151,2112,2113],{"class":161},"  readOnly: ",[151,2115,519],{"class":209},[151,2117,276],{"class":161},[151,2119,2120],{"class":153,"line":196},[151,2121,2122],{"class":161},"};\n",[151,2124,2125],{"class":153,"line":203},[151,2126,200],{"emptyLinePlaceholder":199},[151,2128,2129,2132,2135],{"class":153,"line":221},[151,2130,2131],{"class":161},"template.spec.volumes ",[151,2133,2134],{"class":157},"=",[151,2136,2137],{"class":161}," [{\n",[151,2139,2140,2142,2144],{"class":153,"line":236},[151,2141,282],{"class":161},[151,2143,2101],{"class":189},[151,2145,276],{"class":161},[151,2147,2148,2151,2154],{"class":153,"line":241},[151,2149,2150],{"class":161},"  emptyDir: { sizeLimit: ",[151,2152,2153],{"class":189},"\"256Mi\"",[151,2155,422],{"class":161},[151,2157,2158],{"class":153,"line":267},[151,2159,2160],{"class":161},"}];\n",[151,2162,2163],{"class":153,"line":279},[151,2164,200],{"emptyLinePlaceholder":199},[151,2166,2167,2170,2172,2175,2178],{"class":153,"line":290},[151,2168,2169],{"class":161},"template.spec.initContainers ",[151,2171,2134],{"class":157},[151,2173,2174],{"class":161}," set.spec.plugins.",[151,2176,2177],{"class":255},"map",[151,2179,573],{"class":161},[151,2181,2182,2185,2188,2190,2192],{"class":153,"line":301},[151,2183,2184],{"class":161},"  (",[151,2186,2187],{"class":549},"plugin",[151,2189,553],{"class":161},[151,2191,556],{"class":157},[151,2193,2194],{"class":161}," ({\n",[151,2196,2197,2200,2203,2205,2208,2210,2213],{"class":153,"line":312},[151,2198,2199],{"class":161},"    name: ",[151,2201,2202],{"class":189},"`aurum-plugin-${",[151,2204,2187],{"class":161},[151,2206,2207],{"class":189},".",[151,2209,1901],{"class":161},[151,2211,2212],{"class":189},"}`",[151,2214,276],{"class":161},[151,2216,2217],{"class":153,"line":330},[151,2218,2219],{"class":161},"    image: plugin.digest\n",[151,2221,2222,2225,2228,2230,2232,2235,2238,2240,2242,2244],{"class":153,"line":335},[151,2223,2224],{"class":157},"      ?",[151,2226,2227],{"class":189}," `${",[151,2229,2187],{"class":161},[151,2231,2207],{"class":189},[151,2233,2234],{"class":161},"image",[151,2236,2237],{"class":189},"}@${",[151,2239,2187],{"class":161},[151,2241,2207],{"class":189},[151,2243,2035],{"class":161},[151,2245,2246],{"class":189},"}`\n",[151,2248,2249,2252,2254,2256,2258,2260,2263,2265,2267,2269,2271],{"class":153,"line":341},[151,2250,2251],{"class":157},"      :",[151,2253,2227],{"class":189},[151,2255,2187],{"class":161},[151,2257,2207],{"class":189},[151,2259,2234],{"class":161},[151,2261,2262],{"class":189},"}:${",[151,2264,2187],{"class":161},[151,2266,2207],{"class":189},[151,2268,2039],{"class":161},[151,2270,2212],{"class":189},[151,2272,276],{"class":161},[151,2274,2275],{"class":153,"line":352},[151,2276,2277],{"class":161},"    env: [\n",[151,2279,2280,2283,2286],{"class":153,"line":358},[151,2281,2282],{"class":161},"      { name: ",[151,2284,2285],{"class":189},"\"PLUGIN_ID\"",[151,2287,2288],{"class":161},", value: plugin.id },\n",[151,2290,2291,2293,2296],{"class":153,"line":366},[151,2292,2282],{"class":161},[151,2294,2295],{"class":189},"\"PLUGIN_VERSION\"",[151,2297,2298],{"class":161},", value: plugin.version },\n",[151,2300,2301],{"class":153,"line":374},[151,2302,488],{"class":161},[151,2304,2305,2308,2311],{"class":153,"line":382},[151,2306,2307],{"class":161},"        name: ",[151,2309,2310],{"class":189},"\"PLUGIN_CONFIGURATION\"",[151,2312,276],{"class":161},[151,2314,2315,2318,2321,2323,2326,2329,2332],{"class":153,"line":390},[151,2316,2317],{"class":161},"        value: ",[151,2319,2320],{"class":209},"JSON",[151,2322,2207],{"class":161},[151,2324,2325],{"class":255},"stringify",[151,2327,2328],{"class":161},"(plugin.configuration ",[151,2330,2331],{"class":157},"??",[151,2333,2334],{"class":161}," {}),\n",[151,2336,2337],{"class":153,"line":396},[151,2338,620],{"class":161},[151,2340,2341],{"class":153,"line":407},[151,2342,393],{"class":161},[151,2344,2345],{"class":153,"line":413},[151,2346,2347],{"class":161},"    volumeMounts: [{\n",[151,2349,2350,2353,2355],{"class":153,"line":425},[151,2351,2352],{"class":161},"      name: ",[151,2354,2101],{"class":189},[151,2356,276],{"class":161},[151,2358,2359,2362,2365],{"class":153,"line":435},[151,2360,2361],{"class":161},"      mountPath: ",[151,2363,2364],{"class":189},"\"\u002Fplugins\"",[151,2366,276],{"class":161},[151,2368,2369],{"class":153,"line":445},[151,2370,2371],{"class":161},"    }],\n",[151,2373,2374],{"class":153,"line":456},[151,2375,2376],{"class":161},"  }),\n",[151,2378,2379],{"class":153,"line":462},[151,2380,2381],{"class":161},");\n",[151,2383,2384],{"class":153,"line":468},[151,2385,200],{"emptyLinePlaceholder":199},[151,2387,2388],{"class":153,"line":473},[151,2389,2390],{"class":161},"template.metadata.annotations[\n",[151,2392,2393],{"class":153,"line":479},[151,2394,2395],{"class":189},"  \"aurum.dev\u002Fplugin-hash\"\n",[151,2397,2398,2401,2403,2406],{"class":153,"line":485},[151,2399,2400],{"class":161},"] ",[151,2402,2134],{"class":157},[151,2404,2405],{"class":255}," sha256",[151,2407,2408],{"class":161},"({ target, plugins: set.spec.plugins });\n",[15,2410,2411,2412,2415,2416,2419],{},"Zmiana hasha powoduje kontrolowany rollout Kubernetes. Status custom resource przechodzi do ",[130,2413,2414],{},"Ready"," dopiero po zakończeniu reconcile; błąd walidacji lub modyfikacji ustawia fazę ",[130,2417,2418],{},"Error"," z komunikatem.",[10,2421,2423],{"id":2422},"deklaracja-treści-po-stronie-nuxt","Deklaracja treści po stronie Nuxt",[15,2425,2426],{},"Aurora nie analizuje przypadkowo całego DOM. Edytowalne punkty są jawne i typowane w kodzie strony:",[142,2428,2432],{"className":2429,"code":2430,"language":2431,"meta":147,"style":147},"language-vue shiki shiki-themes github-light github-dark","\u003CEditableText\n  translation-key=\"website.hero.title\"\n  fallback=\"Dom — przestrzeń Twojego oddechu\"\n  context=\"Główny nagłówek sekcji hero.\"\n\u002F>\n","vue",[130,2433,2434,2441,2451,2461,2471],{"__ignoreMap":147},[151,2435,2436,2438],{"class":153,"line":154},[151,2437,1183],{"class":161},[151,2439,2440],{"class":1756},"EditableText\n",[151,2442,2443,2446,2448],{"class":153,"line":165},[151,2444,2445],{"class":255},"  translation-key",[151,2447,2134],{"class":161},[151,2449,2450],{"class":189},"\"website.hero.title\"\n",[151,2452,2453,2456,2458],{"class":153,"line":171},[151,2454,2455],{"class":255},"  fallback",[151,2457,2134],{"class":161},[151,2459,2460],{"class":189},"\"Dom — przestrzeń Twojego oddechu\"\n",[151,2462,2463,2466,2468],{"class":153,"line":180},[151,2464,2465],{"class":255},"  context",[151,2467,2134],{"class":161},[151,2469,2470],{"class":189},"\"Główny nagłówek sekcji hero.\"\n",[151,2472,2473],{"class":153,"line":196},[151,2474,2475],{"class":161},"\u002F>\n",[15,2477,2478],{},"Integracja aplikacji ustala scope publikacji oraz origin zaufanego rodzica:",[142,2480,2482],{"className":144,"code":2481,"language":146,"meta":147,"style":147},"export default defineNuxtPlugin(() => {\n  const config = useRuntimeConfig();\n\n  const state = useState(\"aurora-published-state\", () => ({\n    mode: \"view\",\n    activeLocale: config.public.auroraDefaultLocale,\n    translations: {},\n  }));\n\n  installAurora({\n    state,\n    applicationId: config.public.auroraApplicationId,\n    parentOrigin: new URL(\n      config.public.auroraParentOrigin,\n    ).origin,\n  });\n});\n",[130,2483,2484,2501,2516,2520,2544,2554,2559,2564,2569,2573,2580,2585,2590,2602,2607,2612,2617],{"__ignoreMap":147},[151,2485,2486,2488,2491,2494,2497,2499],{"class":153,"line":154},[151,2487,244],{"class":157},[151,2489,2490],{"class":157}," default",[151,2492,2493],{"class":255}," defineNuxtPlugin",[151,2495,2496],{"class":161},"(() ",[151,2498,556],{"class":157},[151,2500,162],{"class":161},[151,2502,2503,2506,2508,2510,2513],{"class":153,"line":165},[151,2504,2505],{"class":157},"  const",[151,2507,733],{"class":209},[151,2509,213],{"class":157},[151,2511,2512],{"class":255}," useRuntimeConfig",[151,2514,2515],{"class":161},"();\n",[151,2517,2518],{"class":153,"line":171},[151,2519,200],{"emptyLinePlaceholder":199},[151,2521,2522,2524,2527,2529,2532,2534,2537,2540,2542],{"class":153,"line":180},[151,2523,2505],{"class":157},[151,2525,2526],{"class":209}," state",[151,2528,213],{"class":157},[151,2530,2531],{"class":255}," useState",[151,2533,802],{"class":161},[151,2535,2536],{"class":189},"\"aurora-published-state\"",[151,2538,2539],{"class":161},", () ",[151,2541,556],{"class":157},[151,2543,2194],{"class":161},[151,2545,2546,2549,2552],{"class":153,"line":196},[151,2547,2548],{"class":161},"    mode: ",[151,2550,2551],{"class":189},"\"view\"",[151,2553,276],{"class":161},[151,2555,2556],{"class":153,"line":203},[151,2557,2558],{"class":161},"    activeLocale: config.public.auroraDefaultLocale,\n",[151,2560,2561],{"class":153,"line":221},[151,2562,2563],{"class":161},"    translations: {},\n",[151,2565,2566],{"class":153,"line":236},[151,2567,2568],{"class":161},"  }));\n",[151,2570,2571],{"class":153,"line":241},[151,2572,200],{"emptyLinePlaceholder":199},[151,2574,2575,2578],{"class":153,"line":267},[151,2576,2577],{"class":255},"  installAurora",[151,2579,264],{"class":161},[151,2581,2582],{"class":153,"line":279},[151,2583,2584],{"class":161},"    state,\n",[151,2586,2587],{"class":153,"line":290},[151,2588,2589],{"class":161},"    applicationId: config.public.auroraApplicationId,\n",[151,2591,2592,2595,2597,2600],{"class":153,"line":301},[151,2593,2594],{"class":161},"    parentOrigin: ",[151,2596,1001],{"class":157},[151,2598,2599],{"class":255}," URL",[151,2601,573],{"class":161},[151,2603,2604],{"class":153,"line":312},[151,2605,2606],{"class":161},"      config.public.auroraParentOrigin,\n",[151,2608,2609],{"class":153,"line":330},[151,2610,2611],{"class":161},"    ).origin,\n",[151,2613,2614],{"class":153,"line":335},[151,2615,2616],{"class":161},"  });\n",[151,2618,2619],{"class":153,"line":341},[151,2620,636],{"class":161},[15,2622,2623],{},"W trybie publicznym Nuxt pobiera tylko opublikowany snapshot dla scope’u:",[142,2625,2630],{"className":2626,"code":2628,"language":2629,"meta":147},[2627],"language-text","tenant \u002F application \u002F environment \u002F locale\ndefault \u002F gardenia   \u002F production  \u002F pl\n","text",[130,2631,2628],{"__ignoreMap":147},[10,2633,2635],{"id":2634},"rezultat","Rezultat",[15,2637,2638],{},"Architektura pozwala rozwijać platformę w dwóch niezależnych kierunkach: zespoły frontendowe zachowują pełną swobodę projektowania stron, a możliwości operacyjne mogą być ponownie wykorzystywane jako izolowane produkty.",[15,2640,2641],{},"Aurum standaryzuje zaufanie, kontrakty i dostarczanie. Pluginy definiują domenę. Aurora pozwala redaktorowi pracować bezpośrednio w finalnym doświadczeniu.",[2643,2644,2645],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}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);}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":147,"searchDepth":165,"depth":165,"links":2647},[2648,2649,2650,2651,2652,2653,2654,2655,2656,2657,2658,2660,2661,2662],{"id":12,"depth":165,"text":13},{"id":23,"depth":165,"text":24},{"id":52,"depth":165,"text":53},{"id":77,"depth":165,"text":78},{"id":104,"depth":165,"text":105},{"id":114,"depth":165,"text":115},{"id":124,"depth":165,"text":125},{"id":645,"depth":165,"text":646},{"id":1116,"depth":165,"text":1117},{"id":1601,"depth":165,"text":1602},{"id":1729,"depth":165,"text":2659},"Deklaratywny plugin-set.yaml",{"id":2050,"depth":165,"text":2051},{"id":2422,"depth":165,"text":2423},{"id":2634,"depth":165,"text":2635},"Techniczny opis architektury Aurum 2.0, runtime pluginów, Aurora Editor, granic bezpieczeństwa oraz procesu wdrażania.","md",false,{},"\u002Fcase-studies\u002Fpl\u002Faurum-aurora-technical-report",{"title":5,"description":2663},"case-studies\u002Fpl\u002Faurum-aurora-technical-report","Architektura modułowej platformy, izolowanych pluginów i wizualnego edytora",[2672,2673,2674,2675,2676],"Platform Engineering","Runtime Plugins","Visual Editor","Security","Kubernetes",[2678,2681,2684,2687,2690],{"name":2679,"icon":2680},"Vue.js","logos:vue",{"name":2682,"icon":2683},"Nuxt","logos:nuxt-icon",{"name":2685,"icon":2686},"TypeScript","logos:typescript-icon",{"name":2688,"icon":2689},"MongoDB","logos:mongodb-icon",{"name":2676,"icon":2691},"logos:kubernetes","WnaXkK5uv_95rHqakUYgIYYOiJ5coXrl_HQIJp5_Nsk",1787647490088]