[{"data":1,"prerenderedAt":2112},["ShallowReactive",2],{"navigation_docs_hu":3,"-hu-framework-realtime":449,"-hu-framework-realtime-surround":2107},[4,45,120,158,174,204,234,260,272,288,308,327,340,357,374,387,399,426],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":44},"Kezdő lépések","i-lucide-rocket","\u002Fhu\u002Fgetting-started","hu\u002F01.getting-started",[10,15,20,25,30,35,40],{"title":11,"path":12,"stem":13,"icon":14},"Bevezetés","\u002Fhu\u002Fgetting-started\u002Fintroduction","hu\u002F01.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Telepítés","\u002Fhu\u002Fgetting-started\u002Finstallation","hu\u002F01.getting-started\u002F2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Az első modulod","\u002Fhu\u002Fgetting-started\u002Ffirst-module","hu\u002F01.getting-started\u002F3.first-module","i-lucide-package-plus",{"title":26,"path":27,"stem":28,"icon":29},"Projektstruktúra","\u002Fhu\u002Fgetting-started\u002Fproject-structure","hu\u002F01.getting-started\u002F4.project-structure","i-lucide-folder-tree",{"title":31,"path":32,"stem":33,"icon":34},"A shop mintaalkalmazás","\u002Fhu\u002Fgetting-started\u002Fsample-app","hu\u002F01.getting-started\u002F5.sample-app","i-lucide-shopping-cart",{"title":36,"path":37,"stem":38,"icon":39},"Laravelből érkezőknek","\u002Fhu\u002Fgetting-started\u002Fcoming-from-laravel","hu\u002F01.getting-started\u002F6.coming-from-laravel","i-lucide-arrow-right-left",{"title":41,"path":42,"stem":43,"icon":39},"Symfonyból érkezőknek","\u002Fhu\u002Fgetting-started\u002Fcoming-from-symfony","hu\u002F01.getting-started\u002F7.coming-from-symfony",false,{"title":46,"icon":47,"path":48,"stem":49,"children":50,"page":44},"CLI referencia","i-lucide-terminal","\u002Fhu\u002Fcli","hu\u002F02.cli",[51,55,60,65,70,75,80,85,90,95,100,105,110,115],{"title":52,"path":53,"stem":54,"icon":47},"Áttekintés","\u002Fhu\u002Fcli\u002Foverview","hu\u002F02.cli\u002F1.overview",{"title":56,"path":57,"stem":58,"icon":59},"add compose \u002F add docker","\u002Fhu\u002Fcli\u002Fadd-compose","hu\u002F02.cli\u002F10.add-compose","i-lucide-container",{"title":61,"path":62,"stem":63,"icon":64},"add mail","\u002Fhu\u002Fcli\u002Fadd-mail","hu\u002F02.cli\u002F11.add-mail","i-lucide-mail-plus",{"title":66,"path":67,"stem":68,"icon":69},"add notification","\u002Fhu\u002Fcli\u002Fadd-notification","hu\u002F02.cli\u002F12.add-notification","i-lucide-bell-plus",{"title":71,"path":72,"stem":73,"icon":74},"add realtime","\u002Fhu\u002Fcli\u002Fadd-realtime","hu\u002F02.cli\u002F13.add-realtime","i-lucide-radio-tower",{"title":76,"path":77,"stem":78,"icon":79},"add seeder","\u002Fhu\u002Fcli\u002Fadd-seeder","hu\u002F02.cli\u002F14.add-seeder","i-lucide-sprout",{"title":81,"path":82,"stem":83,"icon":84},"new project","\u002Fhu\u002Fcli\u002Fnew-project","hu\u002F02.cli\u002F2.new-project","i-lucide-folder-plus",{"title":86,"path":87,"stem":88,"icon":89},"new module","\u002Fhu\u002Fcli\u002Fnew-module","hu\u002F02.cli\u002F3.new-module","i-lucide-blocks",{"title":91,"path":92,"stem":93,"icon":94},"add surface","\u002Fhu\u002Fcli\u002Fadd-surface","hu\u002F02.cli\u002F4.add-surface","i-lucide-layers-2",{"title":96,"path":97,"stem":98,"icon":99},"add domain","\u002Fhu\u002Fcli\u002Fadd-domain","hu\u002F02.cli\u002F5.add-domain","i-lucide-box",{"title":101,"path":102,"stem":103,"icon":104},"add handler","\u002Fhu\u002Fcli\u002Fadd-handler","hu\u002F02.cli\u002F6.add-handler","i-lucide-webhook",{"title":106,"path":107,"stem":108,"icon":109},"new migration","\u002Fhu\u002Fcli\u002Fnew-migration","hu\u002F02.cli\u002F7.new-migration","i-lucide-file-plus",{"title":111,"path":112,"stem":113,"icon":114},"worker generátorok","\u002Fhu\u002Fcli\u002Fworker-generators","hu\u002F02.cli\u002F8.worker-generators","i-lucide-cog",{"title":116,"path":117,"stem":118,"icon":119},"add db","\u002Fhu\u002Fcli\u002Fadd-db","hu\u002F02.cli\u002F9.add-db","i-lucide-database-zap",{"title":121,"icon":99,"path":122,"stem":123,"children":124,"page":44},"A framework","\u002Fhu\u002Fframework","hu\u002F03.framework",[125,129,134,139,143,148,153],{"title":126,"path":127,"stem":128,"icon":99},"A framework áttekintése","\u002Fhu\u002Fframework\u002Foverview","hu\u002F03.framework\u002F1.overview",{"title":130,"path":131,"stem":132,"icon":133},"Alkalmazás-életciklus","\u002Fhu\u002Fframework\u002Fapp","hu\u002F03.framework\u002F2.app","i-lucide-power",{"title":135,"path":136,"stem":137,"icon":138},"Szerver","\u002Fhu\u002Fframework\u002Fserver","hu\u002F03.framework\u002F3.server","i-lucide-server",{"title":140,"path":141,"stem":142,"icon":114},"Worker","\u002Fhu\u002Fframework\u002Fworker","hu\u002F03.framework\u002F4.worker",{"title":144,"path":145,"stem":146,"icon":147},"Realtime","\u002Fhu\u002Fframework\u002Frealtime","hu\u002F03.framework\u002F5.realtime","i-lucide-radio",{"title":149,"path":150,"stem":151,"icon":152},"Migrációk","\u002Fhu\u002Fframework\u002Fmigrations","hu\u002F03.framework\u002F6.migrations","i-lucide-file-stack",{"title":154,"path":155,"stem":156,"icon":157},"Social login","\u002Fhu\u002Fframework\u002Fsocial-login","hu\u002F03.framework\u002F7.social-login","i-lucide-log-in",{"title":159,"icon":160,"path":161,"stem":162,"children":163,"page":44},"Referencia","i-lucide-book-open","\u002Fhu\u002Freference","hu\u002F04.reference",[164,169],{"title":165,"path":166,"stem":167,"icon":168},"Konfiguráció","\u002Fhu\u002Freference\u002Fconfiguration","hu\u002F04.reference\u002F1.configuration","i-lucide-settings",{"title":170,"path":171,"stem":172,"icon":173},"Külső függőségek","\u002Fhu\u002Freference\u002Fdependencies","hu\u002F04.reference\u002F2.dependencies","i-lucide-package",{"title":175,"icon":176,"path":177,"stem":178,"children":179,"page":44},"Koncepciók","i-lucide-lightbulb","\u002Fhu\u002Fconcepts","hu\u002F05.concepts",[180,185,190,194,199],{"title":181,"path":182,"stem":183,"icon":184},"Architektúra","\u002Fhu\u002Fconcepts\u002Farchitecture","hu\u002F05.concepts\u002F1.architecture","i-lucide-layers",{"title":186,"path":187,"stem":188,"icon":189},"Hibamodell","\u002Fhu\u002Fconcepts\u002Ferror-model","hu\u002F05.concepts\u002F2.error-model","i-lucide-shield-alert",{"title":165,"path":191,"stem":192,"icon":193},"\u002Fhu\u002Fconcepts\u002Fconfiguration","hu\u002F05.concepts\u002F3.configuration","i-lucide-settings-2",{"title":195,"path":196,"stem":197,"icon":198},"Codegen pipeline","\u002Fhu\u002Fconcepts\u002Fcodegen-pipeline","hu\u002F05.concepts\u002F4.codegen-pipeline","i-lucide-file-json",{"title":200,"path":201,"stem":202,"icon":203},"Design patternek","\u002Fhu\u002Fconcepts\u002Fdesign-patterns","hu\u002F05.concepts\u002F5.design-patterns","i-lucide-puzzle",{"title":205,"icon":206,"path":207,"stem":208,"children":209,"page":44},"auth","i-lucide-shield-check","\u002Fhu\u002Fauth","hu\u002F06.auth",[210,215,220,225,230],{"title":211,"path":212,"stem":213,"icon":214},"Autentikáció","\u002Fhu\u002Fauth\u002Foverview","hu\u002F06.auth\u002F1.overview","i-lucide-key-round",{"title":216,"path":217,"stem":218,"icon":219},"RBAC","\u002Fhu\u002Fauth\u002Frbac","hu\u002F06.auth\u002F2.rbac","i-lucide-users",{"title":221,"path":222,"stem":223,"icon":224},"Policy-k","\u002Fhu\u002Fauth\u002Fpolicy","hu\u002F06.auth\u002F3.policy","i-lucide-gavel",{"title":226,"path":227,"stem":228,"icon":229},"Az auth önálló használata","\u002Fhu\u002Fauth\u002Fstandalone","hu\u002F06.auth\u002F4.standalone","i-lucide-plug",{"title":231,"path":232,"stem":233,"icon":157},"Social login goth-tal, önállóan","\u002Fhu\u002Fauth\u002Fsocial-standalone","hu\u002F06.auth\u002F5.social-standalone",{"title":235,"icon":236,"path":237,"stem":238,"children":239,"page":44},"dbx","i-lucide-database","\u002Fhu\u002Fdbx","hu\u002F07.dbx",[240,243,247,251,256],{"title":52,"path":241,"stem":242,"icon":236},"\u002Fhu\u002Fdbx\u002Foverview","hu\u002F07.dbx\u002F1.overview",{"title":244,"path":245,"stem":246,"icon":229},"pgx","\u002Fhu\u002Fdbx\u002Fpg","hu\u002F07.dbx\u002F2.pg",{"title":248,"path":249,"stem":250,"icon":184},"bun","\u002Fhu\u002Fdbx\u002Fbunx","hu\u002F07.dbx\u002F3.bunx",{"title":252,"path":253,"stem":254,"icon":255},"Tranzakciók","\u002Fhu\u002Fdbx\u002Ftransactions","hu\u002F07.dbx\u002F4.transactions","i-lucide-git-merge",{"title":257,"path":258,"stem":259,"icon":79},"Seederek","\u002Fhu\u002Fdbx\u002Fseed","hu\u002F07.dbx\u002F5.seed",{"title":261,"icon":193,"path":262,"stem":263,"children":264,"page":44},"envconf","\u002Fhu\u002Fenvconf","hu\u002F08.envconf",[265,268],{"title":52,"path":266,"stem":267,"icon":193},"\u002Fhu\u002Fenvconf\u002Foverview","hu\u002F08.envconf\u002F1.overview",{"title":269,"path":270,"stem":271,"icon":193},"Receptek","\u002Fhu\u002Fenvconf\u002Frecipes","hu\u002F08.envconf\u002F2.recipes",{"title":273,"icon":189,"path":274,"stem":275,"children":276,"page":44},"errs","\u002Fhu\u002Ferrs","hu\u002F09.errs",[277,280,284],{"title":52,"path":278,"stem":279,"icon":189},"\u002Fhu\u002Ferrs\u002Foverview","hu\u002F09.errs\u002F1.overview",{"title":281,"path":282,"stem":283,"icon":189},"API","\u002Fhu\u002Ferrs\u002Fapi","hu\u002F09.errs\u002F2.api",{"title":285,"path":286,"stem":287,"icon":189},"Integráció","\u002Fhu\u002Ferrs\u002Fintegration","hu\u002F09.errs\u002F3.integration",{"title":289,"icon":290,"path":291,"stem":292,"children":293,"page":44},"events","i-lucide-workflow","\u002Fhu\u002Fevents","hu\u002F10.events",[294,298,303],{"title":295,"path":296,"stem":297,"icon":147},"Események","\u002Fhu\u002Fevents\u002Foverview","hu\u002F10.events\u002F1.overview",{"title":299,"path":300,"stem":301,"icon":302},"Outbox","\u002Fhu\u002Fevents\u002Foutbox","hu\u002F10.events\u002F2.outbox","i-lucide-inbox",{"title":304,"path":305,"stem":306,"icon":307},"Ütemezés","\u002Fhu\u002Fevents\u002Fscheduler","hu\u002F10.events\u002F3.scheduler","i-lucide-calendar-clock",{"title":309,"icon":310,"path":311,"stem":312,"children":313,"page":44},"httperr","i-lucide-globe","\u002Fhu\u002Fhttperr","hu\u002F11.httperr",[314,317,322],{"title":52,"path":315,"stem":316,"icon":310},"\u002Fhu\u002Fhttperr\u002Foverview","hu\u002F11.httperr\u002F1.overview",{"title":318,"path":319,"stem":320,"icon":321},"Hibaválaszok","\u002Fhu\u002Fhttperr\u002Ferror-responses","hu\u002F11.httperr\u002F2.error-responses","i-lucide-octagon-alert",{"title":323,"path":324,"stem":325,"icon":326},"Validáció","\u002Fhu\u002Fhttperr\u002Fvalidation","hu\u002F11.httperr\u002F3.validation","i-lucide-badge-check",{"title":328,"icon":329,"path":330,"stem":331,"children":332,"page":44},"logx","i-lucide-scroll-text","\u002Fhu\u002Flogx","hu\u002F12.logx",[333,336],{"title":52,"path":334,"stem":335,"icon":329},"\u002Fhu\u002Flogx\u002Foverview","hu\u002F12.logx\u002F1.overview",{"title":337,"path":338,"stem":339,"icon":47},"Monolog-formázó","\u002Fhu\u002Flogx\u002Fmonolog","hu\u002F12.logx\u002F2.monolog",{"title":341,"icon":342,"path":343,"stem":344,"children":345,"page":44},"mail","i-lucide-mail","\u002Fhu\u002Fmail","hu\u002F13.mail",[346,349,353],{"title":52,"path":347,"stem":348,"icon":342},"\u002Fhu\u002Fmail\u002Foverview","hu\u002F13.mail\u002F1.overview",{"title":350,"path":351,"stem":352,"icon":342},"SMTP","\u002Fhu\u002Fmail\u002Fsmtp","hu\u002F13.mail\u002F2.smtp",{"title":354,"path":355,"stem":356,"icon":342},"MJML","\u002Fhu\u002Fmail\u002Fmjml","hu\u002F13.mail\u002F3.mjml",{"title":358,"icon":359,"path":360,"stem":361,"children":362,"page":44},"notify","i-lucide-bell","\u002Fhu\u002Fnotify","hu\u002F14.notify",[363,366,370],{"title":52,"path":364,"stem":365,"icon":359},"\u002Fhu\u002Fnotify\u002Foverview","hu\u002F14.notify\u002F1.overview",{"title":367,"path":368,"stem":369,"icon":359},"Database csatorna","\u002Fhu\u002Fnotify\u002Fdatabase","hu\u002F14.notify\u002F2.database",{"title":371,"path":372,"stem":373,"icon":359},"Broadcast csatorna","\u002Fhu\u002Fnotify\u002Fbroadcast","hu\u002F14.notify\u002F3.broadcast",{"title":375,"icon":376,"path":377,"stem":378,"children":379,"page":44},"paginate","i-lucide-list-ordered","\u002Fhu\u002Fpaginate","hu\u002F15.paginate",[380,383],{"title":52,"path":381,"stem":382,"icon":376},"\u002Fhu\u002Fpaginate\u002Foverview","hu\u002F15.paginate\u002F1.overview",{"title":384,"path":385,"stem":386,"icon":39},"Cursor-lapozás","\u002Fhu\u002Fpaginate\u002Fcursor","hu\u002F15.paginate\u002F2.cursor",{"title":388,"icon":184,"path":389,"stem":390,"children":391,"page":44},"queue","\u002Fhu\u002Fqueue","hu\u002F16.queue",[392,395],{"title":52,"path":393,"stem":394,"icon":376},"\u002Fhu\u002Fqueue\u002Foverview","hu\u002F16.queue\u002F1.overview",{"title":396,"path":397,"stem":398,"icon":184},"Taskok","\u002Fhu\u002Fqueue\u002Ftasks","hu\u002F16.queue\u002F2.tasks",{"title":400,"icon":401,"path":402,"stem":403,"children":404,"page":44},"storage","i-lucide-hard-drive","\u002Fhu\u002Fstorage","hu\u002F17.storage",[405,408,412,416,421],{"title":52,"path":406,"stem":407,"icon":401},"\u002Fhu\u002Fstorage\u002Foverview","hu\u002F17.storage\u002F1.overview",{"title":409,"path":410,"stem":411,"icon":401},"Disk API","\u002Fhu\u002Fstorage\u002Fdisk-api","hu\u002F17.storage\u002F2.disk-api",{"title":413,"path":414,"stem":415,"icon":401},"Memória és helyi lemez","\u002Fhu\u002Fstorage\u002Flocal","hu\u002F17.storage\u002F3.local",{"title":417,"path":418,"stem":419,"icon":420},"S3","\u002Fhu\u002Fstorage\u002Fs3","hu\u002F17.storage\u002F4.s3","i-lucide-cloud",{"title":422,"path":423,"stem":424,"icon":425},"Tesztelés","\u002Fhu\u002Fstorage\u002Ftesting","hu\u002F17.storage\u002F5.testing","i-lucide-flask-conical",{"title":427,"icon":428,"path":429,"stem":430,"children":431,"page":44},"telemetry","i-lucide-activity","\u002Fhu\u002Ftelemetry","hu\u002F18.telemetry",[432,435,439,444],{"title":52,"path":433,"stem":434,"icon":428},"\u002Fhu\u002Ftelemetry\u002Foverview","hu\u002F18.telemetry\u002F1.overview",{"title":436,"path":437,"stem":438,"icon":329},"Logolás","\u002Fhu\u002Ftelemetry\u002Flogging","hu\u002F18.telemetry\u002F2.logging",{"title":440,"path":441,"stem":442,"icon":443},"OpenTelemetry","\u002Fhu\u002Ftelemetry\u002Fopentelemetry","hu\u002F18.telemetry\u002F3.opentelemetry","i-lucide-radar",{"title":445,"path":446,"stem":447,"icon":448},"Sentry","\u002Fhu\u002Ftelemetry\u002Fsentry","hu\u002F18.telemetry\u002F4.sentry","i-lucide-bug",{"id":450,"title":144,"body":451,"description":2100,"extension":2101,"links":2102,"meta":2103,"navigation":2104,"path":145,"seo":2105,"stem":146,"__hash__":2106},"docs_hu\u002Fhu\u002F03.framework\u002F5.realtime.md",{"type":452,"value":453,"toc":2087},"minimark",[454,469,474,495,508,512,701,715,719,740,757,947,953,962,1079,1088,1092,1110,1287,1324,1327,1331,1341,1423,1434,1497,1507,1511,1514,1559,1563,1710,1736,1741,1767,1788,1792,1947,1961,1971,2029,2042,2046,2083],[455,456,457,458,463,464,468],"p",{},"A ",[459,460,462],"a",{"href":461},"\u002Fhu\u002Fnotify\u002Fbroadcast#broadcast","broadcast csatorna"," egy notificationt a recipiens élő kapcsolatára kézbesít, abban a pillanatban, amikor történik: egy \"poke\" a durable ",[459,465,467],{"href":466},"\u002Fhu\u002Fnotify\u002Fdatabase#database","database csatorna"," tetején, nem annak helyettesítője. Ez az oldal a kapcsolatokat tartó gatewayről szól.",[470,471,473],"h2",{"id":472},"miért-külön-gateway","Miért külön gateway",[455,475,476,477,481,482,485,486,489,490,494],{},"A notificationök küldése bármely processből történhet, gyakran a workerből, egy listenerből. A kliens-kapcsolatok tartása más feladat, más skálázási alakkal: sok, hosszú élettartamú stream, egy csatlakozott userenként, aminek túl kell élnie a példányok szabad jövés-menését. A framework ezeket szétválasztja: a ",[478,479,480],"code",{},"notify\u002Fbroadcast"," egy pici publisher, amit bármely process importálhat (szerver nélkül, állapot nélkül); a ",[478,483,484],{},"realtime"," egy dedikált binary (",[478,487,488],{},"cmd\u002Frealtime",", az ",[459,491,492],{"href":72},[478,493,71],{}," scaffoldolja), ami csak kapcsolatokat tart és relay-eli, amit publikálnak.",[455,496,497,498,500,501,503,504,507],{},"A driver-seam szándékos: a ",[478,499,480],{},"-on és a ",[478,502,484],{},"-on kívül semmi nem importálja közvetlenül a ",[478,505,506],{},"centrifuge","-ot, így egy másik transport később lecserélheti anélkül, hogy az alkalmazáskódhoz nyúlna.",[470,509,511],{"id":510},"publikálás","Publikálás",[513,514,519],"pre",{"className":515,"code":516,"language":517,"meta":518,"style":518},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import \"github.com\u002Fgp-system\u002Fnotify\u002Fbroadcast\"\n\npub := broadcast.MustNewPublisher(ctx, cfg.Realtime.BroadcastValkey(), cfg.Realtime.Broadcast)\nnotifier := notify.NewHub(\n    notify.NewMailChannel(mailer),\n    notifydatabase.NewChannel(store),\n    notify.NewBroadcastChannel(pub, cfg.Realtime.Broadcast.ChannelPrefix),\n)\n","go","",[478,520,521,541,548,606,625,644,662,696],{"__ignoreMap":518},[522,523,526,530,534,538],"span",{"class":524,"line":525},"line",1,[522,527,529],{"class":528},"s7zQu","import",[522,531,533],{"class":532},"sMK4o"," \"",[522,535,537],{"class":536},"sBMFI","github.com\u002Fgp-system\u002Fnotify\u002Fbroadcast",[522,539,540],{"class":532},"\"\n",[522,542,544],{"class":524,"line":543},2,[522,545,547],{"emptyLinePlaceholder":546},true,"\n",[522,549,551,555,558,561,564,568,571,574,577,580,582,584,586,589,592,594,596,598,600,603],{"class":524,"line":550},3,[522,552,554],{"class":553},"sTEyZ","pub ",[522,556,557],{"class":532},":=",[522,559,560],{"class":553}," broadcast",[522,562,563],{"class":532},".",[522,565,567],{"class":566},"s2Zo4","MustNewPublisher",[522,569,570],{"class":532},"(",[522,572,573],{"class":553},"ctx",[522,575,576],{"class":532},",",[522,578,579],{"class":553}," cfg",[522,581,563],{"class":532},[522,583,144],{"class":553},[522,585,563],{"class":532},[522,587,588],{"class":566},"BroadcastValkey",[522,590,591],{"class":532},"(),",[522,593,579],{"class":553},[522,595,563],{"class":532},[522,597,144],{"class":553},[522,599,563],{"class":532},[522,601,602],{"class":553},"Broadcast",[522,604,605],{"class":532},")\n",[522,607,609,612,614,617,619,622],{"class":524,"line":608},4,[522,610,611],{"class":553},"notifier ",[522,613,557],{"class":532},[522,615,616],{"class":553}," notify",[522,618,563],{"class":532},[522,620,621],{"class":566},"NewHub",[522,623,624],{"class":532},"(\n",[522,626,628,631,633,636,638,641],{"class":524,"line":627},5,[522,629,630],{"class":553},"    notify",[522,632,563],{"class":532},[522,634,635],{"class":566},"NewMailChannel",[522,637,570],{"class":532},[522,639,640],{"class":553},"mailer",[522,642,643],{"class":532},"),\n",[522,645,647,650,652,655,657,660],{"class":524,"line":646},6,[522,648,649],{"class":553},"    notifydatabase",[522,651,563],{"class":532},[522,653,654],{"class":566},"NewChannel",[522,656,570],{"class":532},[522,658,659],{"class":553},"store",[522,661,643],{"class":532},[522,663,665,667,669,672,674,677,679,681,683,685,687,689,691,694],{"class":524,"line":664},7,[522,666,630],{"class":553},[522,668,563],{"class":532},[522,670,671],{"class":566},"NewBroadcastChannel",[522,673,570],{"class":532},[522,675,676],{"class":553},"pub",[522,678,576],{"class":532},[522,680,579],{"class":553},[522,682,563],{"class":532},[522,684,144],{"class":553},[522,686,563],{"class":532},[522,688,602],{"class":553},[522,690,563],{"class":532},[522,692,693],{"class":553},"ChannelPrefix",[522,695,643],{"class":532},[522,697,699],{"class":524,"line":698},8,[522,700,605],{"class":532},[455,702,457,703,706,707,710,711,714],{},[478,704,705],{},"Publisher"," egy publish-only ",[478,708,709],{},"centrifuge.Node",", ami osztozik a projekt Valkey brokerén; sosem fogad kapcsolatot, így egy worker-process semmi mástól nem függ, csak egy hálózati klienstől. A publikálás fire-and-forget: egy sikertelen publish visszaadódik a hívónak, nincs újrapróbálva: a durability a database csatornából jön, egy kliens, aki lemarad egy élő push-ról, reconnectkor onnan backfillel. Az insert-majd-publish kontraktust maga a ",[478,712,713],{},"notify.Hub.Send"," már kikényszeríti (database csatorna a broadcast előtt, ugyanaz a delivery ID mindkettőben).",[470,716,718],{"id":717},"a-gateway","A gateway",[455,720,457,721,723,724,727,728,731,732,735,736,739],{},[478,722,488],{}," nem hordoz üzleti függőséget (nincs adatbázis-pool, nincs outbox), pont ezért skálázódik szabadon. WebSocketet exponál egy HTTP-streaming\u002FSSE fallbackkal (mindkettő a ",[478,725,726],{},"centrifugal\u002Fcentrifuge","-on keresztül, ami a Centrifugo és a Grafana Live mögötti library) a ",[478,729,730],{},"\u002Frealtime\u002F*"," alatt, minden kapcsolat JWT-jét a connect frame-ben authentikálja (nincs külön ",[478,733,734],{},"\u002Fbroadcasting\u002Fauth"," endpoint; v1-ben az egyetlen privát csatorna egy kapcsolat saját subjectje, így elég egyszer, connectkor authentikálni), és minden kapcsolatot server-side feliratkoztat a saját ",[478,737,738],{},"user:\u003Csubject>"," csatornájára. A gyakori esetben nincs szükség kliens-oldali subscribe-logikára.",[455,741,742,743,748,749,752,753,756],{},"A megosztott topic-csatornák opt-in és explicit módon authorizáltak: minden kapcsolat JWT-je egy ",[459,744,745],{"href":217},[478,746,747],{},"rbac.Identity","-ra oldódik fel, és egy topic csak akkor iratkoztatható fel, ha valamelyik ",[478,750,751],{},"Allow","\u002F",[478,754,755],{},"AllowPrefix"," callback jótáll érte.",[513,758,761],{"className":515,"code":759,"filename":760,"language":517,"meta":518,"style":518},"err := realtime.Run(ctx, cfg.Realtime, func(topics *realtime.TopicAuth) error {\n    topics.Allow(\"announcements\", func(id *rbac.Identity) bool { return true })\n    topics.Allow(\"admin-alerts\", func(id *rbac.Identity) bool { return id.HasRole(\"admin\") })\n    return nil\n})\n","cmd\u002Frealtime\u002Fmain.go",[478,762,763,819,874,934,942],{"__ignoreMap":518},[522,764,765,768,770,773,775,778,780,782,784,786,788,790,792,795,799,802,804,806,809,812,816],{"class":524,"line":525},[522,766,767],{"class":553},"err ",[522,769,557],{"class":532},[522,771,772],{"class":553}," realtime",[522,774,563],{"class":532},[522,776,777],{"class":566},"Run",[522,779,570],{"class":532},[522,781,573],{"class":553},[522,783,576],{"class":532},[522,785,579],{"class":553},[522,787,563],{"class":532},[522,789,144],{"class":553},[522,791,576],{"class":532},[522,793,794],{"class":532}," func(",[522,796,798],{"class":797},"sHdIc","topics",[522,800,801],{"class":532}," *",[522,803,484],{"class":536},[522,805,563],{"class":532},[522,807,808],{"class":536},"TopicAuth",[522,810,811],{"class":532},")",[522,813,815],{"class":814},"spNyl"," error",[522,817,818],{"class":532}," {\n",[522,820,821,824,826,828,830,833,837,839,841,843,846,848,851,853,856,858,861,864,867,871],{"class":524,"line":543},[522,822,823],{"class":553},"    topics",[522,825,563],{"class":532},[522,827,751],{"class":566},[522,829,570],{"class":532},[522,831,832],{"class":532},"\"",[522,834,836],{"class":835},"sfazB","announcements",[522,838,832],{"class":532},[522,840,576],{"class":532},[522,842,794],{"class":532},[522,844,845],{"class":797},"id",[522,847,801],{"class":532},[522,849,850],{"class":536},"rbac",[522,852,563],{"class":532},[522,854,855],{"class":536},"Identity",[522,857,811],{"class":532},[522,859,860],{"class":814}," bool",[522,862,863],{"class":532}," {",[522,865,866],{"class":528}," return",[522,868,870],{"class":869},"sfNiH"," true",[522,872,873],{"class":532}," })\n",[522,875,876,878,880,882,884,886,889,891,893,895,897,899,901,903,905,907,909,911,913,916,918,921,923,925,928,930,932],{"class":524,"line":550},[522,877,823],{"class":553},[522,879,563],{"class":532},[522,881,751],{"class":566},[522,883,570],{"class":532},[522,885,832],{"class":532},[522,887,888],{"class":835},"admin-alerts",[522,890,832],{"class":532},[522,892,576],{"class":532},[522,894,794],{"class":532},[522,896,845],{"class":797},[522,898,801],{"class":532},[522,900,850],{"class":536},[522,902,563],{"class":532},[522,904,855],{"class":536},[522,906,811],{"class":532},[522,908,860],{"class":814},[522,910,863],{"class":532},[522,912,866],{"class":528},[522,914,915],{"class":553}," id",[522,917,563],{"class":532},[522,919,920],{"class":566},"HasRole",[522,922,570],{"class":532},[522,924,832],{"class":532},[522,926,927],{"class":835},"admin",[522,929,832],{"class":532},[522,931,811],{"class":532},[522,933,873],{"class":532},[522,935,936,939],{"class":524,"line":608},[522,937,938],{"class":528},"    return",[522,940,941],{"class":532}," nil\n",[522,943,944],{"class":524,"line":627},[522,945,946],{"class":532},"})\n",[455,948,949,950,952],{},"Egy topic, aminek nincs regisztrált ",[478,951,751],{}," callbackje, sosem iratkoztatható fel.",[455,954,955,956,958,959,961],{},"Ha egy csatorna-család teljes neve csak futásidőben ismert (egy dinamikus\nerőforrás soronként: egy tenant, egy projekt, egy repository), az ",[478,957,751],{},"-val\negyenként, induláskor való elnevezés nem lehetséges: helyette ",[478,960,755],{},"\nhasználandó, aminek a callbackje megkapja a teljes topic stringet, hogy meg\ntudja állapítani, épp melyik konkrét instance-t kérik.",[513,963,965],{"className":515,"code":964,"language":517,"meta":518,"style":518},"topics.AllowPrefix(\"project:\", func(id *rbac.Identity, topic string) bool {\n    projectID, _ := strings.CutPrefix(topic, \"project:\")\n    return projectAccess.CanView(id.Subject, projectID)\n})\n",[478,966,967,1012,1047,1075],{"__ignoreMap":518},[522,968,969,971,973,975,977,979,982,984,986,988,990,992,994,996,998,1000,1003,1006,1008,1010],{"class":524,"line":525},[522,970,798],{"class":553},[522,972,563],{"class":532},[522,974,755],{"class":566},[522,976,570],{"class":532},[522,978,832],{"class":532},[522,980,981],{"class":835},"project:",[522,983,832],{"class":532},[522,985,576],{"class":532},[522,987,794],{"class":532},[522,989,845],{"class":797},[522,991,801],{"class":532},[522,993,850],{"class":536},[522,995,563],{"class":532},[522,997,855],{"class":536},[522,999,576],{"class":532},[522,1001,1002],{"class":797}," topic",[522,1004,1005],{"class":814}," string",[522,1007,811],{"class":532},[522,1009,860],{"class":814},[522,1011,818],{"class":532},[522,1013,1014,1017,1019,1022,1024,1027,1029,1032,1034,1037,1039,1041,1043,1045],{"class":524,"line":543},[522,1015,1016],{"class":553},"    projectID",[522,1018,576],{"class":532},[522,1020,1021],{"class":553}," _ ",[522,1023,557],{"class":532},[522,1025,1026],{"class":553}," strings",[522,1028,563],{"class":532},[522,1030,1031],{"class":566},"CutPrefix",[522,1033,570],{"class":532},[522,1035,1036],{"class":553},"topic",[522,1038,576],{"class":532},[522,1040,533],{"class":532},[522,1042,981],{"class":835},[522,1044,832],{"class":532},[522,1046,605],{"class":532},[522,1048,1049,1051,1054,1056,1059,1061,1063,1065,1068,1070,1073],{"class":524,"line":550},[522,1050,938],{"class":528},[522,1052,1053],{"class":553}," projectAccess",[522,1055,563],{"class":532},[522,1057,1058],{"class":566},"CanView",[522,1060,570],{"class":532},[522,1062,845],{"class":553},[522,1064,563],{"class":532},[522,1066,1067],{"class":553},"Subject",[522,1069,576],{"class":532},[522,1071,1072],{"class":553}," projectID",[522,1074,605],{"class":532},[522,1076,1077],{"class":524,"line":608},[522,1078,946],{"class":532},[455,1080,1081,1082,1084,1085,1087],{},"Egy pontos ",[478,1083,751],{},"-egyezés mindig elsőbbséget élvez egy illeszkedő\n",[478,1086,755],{},"-szel szemben; a prefixek közül az elsőként regisztrált,\nilleszkedő nyer.",[470,1089,1091],{"id":1090},"kliens-szerver-rpc","Kliens-szerver RPC",[455,1093,1094,1095,1098,1099,1102,1103,1106,1107,1109],{},"A gateway alapból kizárólag szerver→kliens: a kapcsolat a publish-okat kapja, de\nnem tud írni semmit. A ",[478,1096,1097],{},"WithRPC"," bekapcsolja a fordított irányt is: a kliens egy\n",[478,1100,1101],{},"method"," nevet és egy nyers payloadot küld, a szerver egy regisztrált\n",[478,1104,1105],{},"RPCHandler","-rel válaszol, ugyanazzal a JWT-ből feloldott identitással, amit a\n",[478,1108,808],{}," callbackek is látnak.",[513,1111,1113],{"className":515,"code":1112,"filename":760,"language":517,"meta":518,"style":518},"err := realtime.Run(ctx, cfg.Realtime, register, realtime.WithRPC(func(rpc *realtime.RPCRegistry) error {\n    rpc.Handle(\"chat.send\", func(ctx context.Context, id *rbac.Identity, data []byte) ([]byte, error) {\n        return chatService.SendViaRPC(ctx, id, data)\n    })\n    return nil\n}))\n",[478,1114,1115,1173,1244,1271,1276,1282],{"__ignoreMap":518},[522,1116,1117,1119,1121,1123,1125,1127,1129,1131,1133,1135,1137,1139,1141,1144,1146,1148,1150,1152,1155,1158,1160,1162,1164,1167,1169,1171],{"class":524,"line":525},[522,1118,767],{"class":553},[522,1120,557],{"class":532},[522,1122,772],{"class":553},[522,1124,563],{"class":532},[522,1126,777],{"class":566},[522,1128,570],{"class":532},[522,1130,573],{"class":553},[522,1132,576],{"class":532},[522,1134,579],{"class":553},[522,1136,563],{"class":532},[522,1138,144],{"class":553},[522,1140,576],{"class":532},[522,1142,1143],{"class":553}," register",[522,1145,576],{"class":532},[522,1147,772],{"class":553},[522,1149,563],{"class":532},[522,1151,1097],{"class":566},[522,1153,1154],{"class":532},"(func(",[522,1156,1157],{"class":797},"rpc",[522,1159,801],{"class":532},[522,1161,484],{"class":536},[522,1163,563],{"class":532},[522,1165,1166],{"class":536},"RPCRegistry",[522,1168,811],{"class":532},[522,1170,815],{"class":814},[522,1172,818],{"class":532},[522,1174,1175,1178,1180,1183,1185,1187,1190,1192,1194,1196,1198,1201,1203,1206,1208,1210,1212,1214,1216,1218,1220,1223,1226,1229,1231,1234,1236,1238,1240,1242],{"class":524,"line":543},[522,1176,1177],{"class":553},"    rpc",[522,1179,563],{"class":532},[522,1181,1182],{"class":566},"Handle",[522,1184,570],{"class":532},[522,1186,832],{"class":532},[522,1188,1189],{"class":835},"chat.send",[522,1191,832],{"class":532},[522,1193,576],{"class":532},[522,1195,794],{"class":532},[522,1197,573],{"class":797},[522,1199,1200],{"class":536}," context",[522,1202,563],{"class":532},[522,1204,1205],{"class":536},"Context",[522,1207,576],{"class":532},[522,1209,915],{"class":797},[522,1211,801],{"class":532},[522,1213,850],{"class":536},[522,1215,563],{"class":532},[522,1217,855],{"class":536},[522,1219,576],{"class":532},[522,1221,1222],{"class":797}," data",[522,1224,1225],{"class":532}," []",[522,1227,1228],{"class":814},"byte",[522,1230,811],{"class":532},[522,1232,1233],{"class":532}," ([]",[522,1235,1228],{"class":814},[522,1237,576],{"class":532},[522,1239,815],{"class":814},[522,1241,811],{"class":532},[522,1243,818],{"class":532},[522,1245,1246,1249,1252,1254,1257,1259,1261,1263,1265,1267,1269],{"class":524,"line":550},[522,1247,1248],{"class":528},"        return",[522,1250,1251],{"class":553}," chatService",[522,1253,563],{"class":532},[522,1255,1256],{"class":566},"SendViaRPC",[522,1258,570],{"class":532},[522,1260,573],{"class":553},[522,1262,576],{"class":532},[522,1264,915],{"class":553},[522,1266,576],{"class":532},[522,1268,1222],{"class":553},[522,1270,605],{"class":532},[522,1272,1273],{"class":524,"line":608},[522,1274,1275],{"class":532},"    })\n",[522,1277,1278,1280],{"class":524,"line":627},[522,1279,938],{"class":528},[522,1281,941],{"class":532},[522,1283,1284],{"class":524,"line":646},[522,1285,1286],{"class":532},"}))\n",[455,1288,1289,1290,1293,1294,1296,1297,1300,1301,1304,1305,1308,1309,1312,1313,1316,1317,1319,1320,1323],{},"Egy methodnak, amire nincs regisztrált handler, a kliens\n",[478,1291,1292],{},"centrifuge.ErrorMethodNotFound","-ot kap. A handler visszatérési hibája\n",[478,1295,309],{},"-hez hasonlóan térképeződik le: egy ",[478,1298,1299],{},"errs.Status","-szal ellátott hiba a\nstátusznak megfelelő ",[478,1302,1303],{},"centrifuge.Error","-t adja (400\u002F422 → ",[478,1306,1307],{},"ErrorBadRequest",",\n401\u002F403 → ",[478,1310,1311],{},"ErrorPermissionDenied",", 404 → egy framework-definiálta \"not found\" hiba),\n",[478,1314,1315],{},"errs.Public","-ja pedig a kliens felé látható üzenet; egy sima, ",[478,1318,1299],{},"\nnélküli hiba ",[478,1321,1322],{},"ErrorInternal","-ra esik, belső részlet nélkül.",[455,1325,1326],{},"A gatewaynek nincs adatbázis-hozzáférése (lásd fentebb: \"nem hordoz üzleti\nfüggőséget\"), így egy RPC handler tipikusan egy meglévő HTTP endpointot hív meg\n(a validáció, a policy és a tranzakció ott van), nem duplikálja az üzleti\nlogikát.",[470,1328,1330],{"id":1329},"opciók-és-a-middleware-lánc","Opciók és a middleware-lánc",[455,1332,457,1333,1336,1337,1340],{},[478,1334,1335],{},"realtime.Run"," a ",[478,1338,1339],{},"server.Run","-nal azonos stílusú opciókat fogad:",[1342,1343,1344,1357],"table",{},[1345,1346,1347],"thead",{},[1348,1349,1350,1354],"tr",{},[1351,1352,1353],"th",{},"Opció",[1351,1355,1356],{},"Hatás",[1358,1359,1360,1371,1385,1395,1409],"tbody",{},[1348,1361,1362,1368],{},[1363,1364,1365],"td",{},[478,1366,1367],{},"WithCloser(name, fn)",[1363,1369,1370],{},"takarítás graceful shutdownkor, miután minden tartott kapcsolat lekapcsolódott (LIFO; a telemetria utolsóként flush-ol)",[1348,1372,1373,1378],{},[1363,1374,1375],{},[478,1376,1377],{},"WithMiddleware(...func(http.Handler) http.Handler)",[1363,1379,1380,1381,1384],{},"net\u002Fhttp middleware-ek fűzése a framework defaultjai után, a transport-endpointok elé; ugyanaz a kontraktus, mint a ",[478,1382,1383],{},"server.WithMiddleware","-é",[1348,1386,1387,1392],{},[1363,1388,1389],{},[478,1390,1391],{},"WithRPC(register)",[1363,1393,1394],{},"kliens által hívható RPC-metódusok (lásd fent)",[1348,1396,1397,1402],{},[1363,1398,1399],{},[478,1400,1401],{},"WithHTTPServer(func(*http.Server))",[1363,1403,1404,1405,1408],{},"escape hatch a ",[478,1406,1407],{},"http.Server"," azon mezőihez, amiket a framework nem exponál",[1348,1410,1411,1416],{},[1363,1412,1413],{},[478,1414,1415],{},"WithoutTelemetry()",[1363,1417,1418,1419,1422],{},"kihagyja a ",[478,1420,1421],{},"telemetry.Setup","-ot és az otel middleware-t; tesztekhez, vagy ha a processz maga konfigurálja a telemetriát",[455,1424,1425,1426,1429,1430,1433],{},"A transport-endpointok körüli framework-lánc a ",[459,1427,1428],{"href":136},"szerver-chassis-éval"," van összehangolva, ugyanazokból az exportált ",[478,1431,1432],{},"gpsystem\u002Fhttpmw"," építőkockákból, legkülsőtől befelé:",[1435,1436,1437,1449,1462,1479,1488],"ol",{},[1438,1439,1440,1444,1445,1448],"li",{},[1441,1442,1443],"strong",{},"CORS, streaming preset"," (",[478,1446,1447],{},"httpmw.CORSStreaming","): az API-presettel szemben a credentialök engedélyezettek (egyes streaming-setupok cookie-val autentikálnak), ezért az originenkénti döntést a lentebb leírt origin-ellenőrzés hozza meg wildcard helyett.",[1438,1450,1451,1444,1454,1457,1458,1461],{},[1441,1452,1453],{},"request id",[478,1455,1456],{},"httpmw.RequestID","): minden válasz ",[478,1459,1460],{},"X-Request-Id"," fejlécet hordoz, az API-oldallal azonos szemantikával.",[1438,1463,1464,1444,1467,1470,1471,1474,1475,1478],{},[1441,1465,1466],{},"otel",[478,1468,1469],{},"httpmw.Otel(\"realtime\")","): a gateway spanje; a ",[478,1472,1473],{},"\u002Frealtime\u002Fhealthz"," ki van szűrve a trace-elésből, ",[478,1476,1477],{},"WithoutTelemetry"," mellett pedig a teljes bejegyzés kimarad.",[1438,1480,1481,1444,1484,1487],{},[1441,1482,1483],{},"Sentry request hub",[478,1485,1486],{},"httpmw.RequestHub","): kérésenkénti breadcrumb-izoláció.",[1438,1489,1490,1444,1493,1496],{},[1441,1491,1492],{},"panic recovery",[478,1494,1495],{},"httpmw.Recoverer","): a HTTP-rétegben történő panicból sima 500 lesz, plusz egy stacket hordozó error-log; a gatewaynek nincs Problem-írója, és a streaming kliensek bármely 5xx-re amúgy is újracsatlakoznak.",[455,1498,457,1499,1502,1503,1506],{},[478,1500,1501],{},"WithMiddleware"," extrák ezeken belül futnak, közvetlenül a transport-endpointok előtt. Access log szándékosan ",[1441,1504,1505],{},"nincs",": a kapcsolat-endpointok hosszú életű streameket tartanak, egy kérésenkénti rekord félrevezető lenne.",[470,1508,1510],{"id":1509},"skálázás-a-példányok-szabadon-jönnek-mennek","Skálázás: a példányok szabadon jönnek-mennek",[455,1512,1513],{},"Minden gateway-példány stateless: csak azokat a csatornákat tartja, amikre a saját kapcsolatainak szükségük van, és a közös Valkey broker minden érintett példányhoz eljuttat egy publish-t, bármely processből, sticky session-igény nélkül.",[1515,1516,1517,1527,1544,1550],"ul",{},[1438,1518,1519,1522,1523,1526],{},[1441,1520,1521],{},"Felskálázás",": ",[478,1524,1525],{},"docker compose up -d --scale realtime=N","; egy új példány nulla állapottal indul, és csak akkor gyűlnek a szubszkripciói, amikor kliensek landolnak rajta.",[1438,1528,1529,1532,1533,1536,1537,1539,1540,1543],{},[1441,1530,1531],{},"Leskálázás \u002F rolling restart",": a ",[478,1534,1535],{},"SIGTERM"," bekapcsol egy draining flaget (a ",[478,1538,1473],{}," és az új connect-kísérletek 503-at adnak, így a load balancer health checkje kiejti a példányt), a ",[478,1541,1542],{},"node.Shutdown"," minden tartott kapcsolatot reconnect-jogosult kóddal zár, a closerek lefutnak, a telemetria flush-öl. A kliens saját reconnect-logikája (backoff, beépítve a JS kliensbe) egy túlélő példányra viszi, ami frissen feliratkoztatja; ami a rés alatt publikálódott, azt a database csatornából állítja helyre, nem a gateway replay-eli.",[1438,1545,1546,1549],{},[1441,1547,1548],{},"Crash",": a kliens oldala ugyanaz, mint egy graceful restartnál, csak a drain lépés nélkül.",[1438,1551,1552,1555,1556,1558],{},[1441,1553,1554],{},"Valkey restart",": a reconnect és az újra-subscribe a ",[478,1557,506],{}," dolga; a publikálás a kiesés alatt logolva és eldobva (ugyanaz a fire-and-forget kontraktus), ugyanúgy helyreállítva, mint egy kliens saját reconnectje alatt lemaradt publish.",[470,1560,1562],{"id":1561},"config","Config",[1342,1564,1565,1578],{},[1345,1566,1567],{},[1348,1568,1569,1572,1575],{},[1351,1570,1571],{},"Változó",[1351,1573,1574],{},"Alapérték",[1351,1576,1577],{},"Jelentés",[1358,1579,1580,1595,1610,1625,1642,1658,1675,1691],{},[1348,1581,1582,1587,1592],{},[1363,1583,1584],{},[478,1585,1586],{},"REALTIME_LISTEN_ADDR",[1363,1588,1589],{},[478,1590,1591],{},":3000",[1363,1593,1594],{},"konténer-belső listen address",[1348,1596,1597,1602,1607],{},[1363,1598,1599],{},[478,1600,1601],{},"REALTIME_DRAIN_TIMEOUT",[1363,1603,1604],{},[478,1605,1606],{},"20s",[1363,1608,1609],{},"graceful-shutdown budget; tartsd a deployment stop-grace-periódusa alatt",[1348,1611,1612,1617,1622],{},[1363,1613,1614],{},[478,1615,1616],{},"REALTIME_READ_HEADER_TIMEOUT",[1363,1618,1619],{},[478,1620,1621],{},"5s",[1363,1623,1624],{},"Slowloris-védelem a connect handshake-en",[1348,1626,1627,1632,1635],{},[1363,1628,1629],{},[478,1630,1631],{},"REALTIME_CHANNEL_PREFIX",[1363,1633,1634],{},"a projekt neve",[1363,1636,1637,1638,1641],{},"Valkey csatorna-névtér, közös minden ",[478,1639,1640],{},"notify\u002Fbroadcast.Publisher","-rel",[1348,1643,1644,1649,1655],{},[1363,1645,1646],{},[478,1647,1648],{},"REALTIME_MAX_CONNECTIONS",[1363,1650,1651,1654],{},[478,1652,1653],{},"0"," (korlátlan)",[1363,1656,1657],{},"példányonkénti stream-plafon; felette a connect-kísérletek 503-at kapnak",[1348,1659,1660,1665,1668],{},[1363,1661,1662],{},[478,1663,1664],{},"VALKEY_*",[1363,1666,1667],{},"örökölt",[1363,1669,1670,1671,1674],{},"újrahasznosítva a ",[478,1672,1673],{},"queue.Config","-ból: a gateway brokere ugyanaz a Valkey, amit a queue használ",[1348,1676,1677,1682,1684],{},[1363,1678,1679],{},[478,1680,1681],{},"JWT_*",[1363,1683,1667],{},[1363,1685,1686,1687,1690],{},"újrahasznosítva az ",[478,1688,1689],{},"auth.Config","-ból: ugyanaz a token-issuer, amiben minden modul megbízik",[1348,1692,1693,1698,1703],{},[1363,1694,1695],{},[478,1696,1697],{},"CORS_ORIGINS",[1363,1699,1700],{},[478,1701,1702],{},"*",[1363,1704,1705,1706,1709],{},"közös a ",[478,1707,1708],{},"server.Config","-gal; a gateway origin-politikáját vezérli mindhárom transporton (websocket, http_stream, sse) és a CORS headereken egyaránt",[455,1711,1712,1713,1718,1719,1722,1723,1726,1727,1731,1732,1735],{},"Lásd az ",[459,1714,1715,1717],{"href":72},[478,1716,71],{}," referenciát"," a scaffoldolt elemekért (a binary, a ",[478,1720,1721],{},"compose.yml"," Traefik-routolt service-e, a ",[478,1724,1725],{},".env.example","), és az ",[459,1728,1729],{"href":67},[478,1730,66],{}," oldalt a broadcast csatorna egy notification ",[478,1733,1734],{},"Via","-jába drótozásához.",[1737,1738,1740],"h3",{"id":1739},"origin-ellenőrzés","Origin-ellenőrzés",[455,1742,457,1743,1745,1746,1749,1750,1752,1753,1755,1756,1758,1759,1762,1763,1766],{},[478,1744,1697],{}," egyetlen szabályt ad mindhárom transportnak: a same-origin\nkapcsolatok (az ",[478,1747,1748],{},"Origin"," hostja megegyezik a kérés Host fejlécével, a dokumentált\nproduction-felállás) és az ",[478,1751,1748],{}," fejléc nélküli kliensek (szerver-szerver\nhívások, health check-ek) mindig átmennek, függetlenül a listától; minden más\nesetben a lista dönt (",[478,1754,1702],{}," mindent enged, egyébként pontos egyezés vagy ",[478,1757,1702],{},"-ot\ntartalmazó minta, pl. ",[478,1760,1761],{},"https:\u002F\u002F*.example.com","). Idegen origin elutasításakor a\ngateway ",[478,1764,1765],{},"Warn"," szinten logol.",[455,1768,1769,1770,1773,1774,1777,1778,1781,1782,1784,1785,1787],{},"Fejlesztésben gyakori, hogy a frontend és a gateway más originről szolgál ki (pl.\negy ",[478,1771,1772],{},"next dev"," a hoston, ",[478,1775,1776],{},"http:\u002F\u002Flocalhost:3000",", a gateway pedig\n",[478,1779,1780],{},"http:\u002F\u002F\u003Capp>.localhost"," mögött Traefikkel): ilyenkor a ",[478,1783,1697],{},"-nek\ntartalmaznia kell a frontend originjét (vagy dev módban maradhat ",[478,1786,1702],{},"), különben a\nwebsocket handshake 403-at kap.",[470,1789,1791],{"id":1790},"kliens","Kliens",[513,1793,1797],{"className":1794,"code":1795,"language":1796,"meta":518,"style":518},"language-js shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { Centrifuge } from 'centrifuge'\n\nconst client = new Centrifuge('wss:\u002F\u002Fyour-app.example\u002Frealtime\u002Fconnection\u002Fwebsocket', {\n    getToken: async () => fetchAccessToken(), \u002F\u002F ugyanaz a JWT, amit az API használ\n})\nclient.on('publication', (ctx) => {\n    \u002F\u002F ctx.data: { id, name, payload, at }, az id visszaköti a database csatorna sorához\n})\nclient.connect()\n","js",[478,1798,1799,1822,1826,1856,1885,1892,1923,1928,1934],{"__ignoreMap":518},[522,1800,1801,1803,1805,1808,1811,1814,1817,1819],{"class":524,"line":525},[522,1802,529],{"class":528},[522,1804,863],{"class":532},[522,1806,1807],{"class":553}," Centrifuge",[522,1809,1810],{"class":532}," }",[522,1812,1813],{"class":528}," from",[522,1815,1816],{"class":532}," '",[522,1818,506],{"class":835},[522,1820,1821],{"class":532},"'\n",[522,1823,1824],{"class":524,"line":543},[522,1825,547],{"emptyLinePlaceholder":546},[522,1827,1828,1831,1834,1837,1840,1842,1844,1847,1850,1852,1854],{"class":524,"line":550},[522,1829,1830],{"class":814},"const",[522,1832,1833],{"class":553}," client ",[522,1835,1836],{"class":532},"=",[522,1838,1839],{"class":532}," new",[522,1841,1807],{"class":566},[522,1843,570],{"class":553},[522,1845,1846],{"class":532},"'",[522,1848,1849],{"class":835},"wss:\u002F\u002Fyour-app.example\u002Frealtime\u002Fconnection\u002Fwebsocket",[522,1851,1846],{"class":532},[522,1853,576],{"class":532},[522,1855,818],{"class":532},[522,1857,1858,1861,1864,1867,1870,1873,1876,1879,1881],{"class":524,"line":608},[522,1859,1860],{"class":566},"    getToken",[522,1862,1863],{"class":532},":",[522,1865,1866],{"class":814}," async",[522,1868,1869],{"class":532}," ()",[522,1871,1872],{"class":814}," =>",[522,1874,1875],{"class":566}," fetchAccessToken",[522,1877,1878],{"class":553},"()",[522,1880,576],{"class":532},[522,1882,1884],{"class":1883},"sHwdD"," \u002F\u002F ugyanaz a JWT, amit az API használ\n",[522,1886,1887,1890],{"class":524,"line":627},[522,1888,1889],{"class":532},"}",[522,1891,605],{"class":553},[522,1893,1894,1897,1899,1902,1904,1906,1909,1911,1913,1915,1917,1919,1921],{"class":524,"line":646},[522,1895,1896],{"class":553},"client",[522,1898,563],{"class":532},[522,1900,1901],{"class":566},"on",[522,1903,570],{"class":553},[522,1905,1846],{"class":532},[522,1907,1908],{"class":835},"publication",[522,1910,1846],{"class":532},[522,1912,576],{"class":532},[522,1914,1444],{"class":532},[522,1916,573],{"class":797},[522,1918,811],{"class":532},[522,1920,1872],{"class":814},[522,1922,818],{"class":532},[522,1924,1925],{"class":524,"line":664},[522,1926,1927],{"class":1883},"    \u002F\u002F ctx.data: { id, name, payload, at }, az id visszaköti a database csatorna sorához\n",[522,1929,1930,1932],{"class":524,"line":698},[522,1931,1889],{"class":532},[522,1933,605],{"class":553},[522,1935,1937,1939,1941,1944],{"class":524,"line":1936},9,[522,1938,1896],{"class":553},[522,1940,563],{"class":532},[522,1942,1943],{"class":566},"connect",[522,1945,1946],{"class":553},"()\n",[455,1948,457,1949,1952,1953,1956,1957,1960],{},[478,1950,1951],{},"centrifuge-js"," kezeli a reconnect-backoffot és a token-refresht; a server-side subscription a recipiens saját csatornájára azt jelenti, hogy a kliensnek nincs szüksége explicit ",[478,1954,1955],{},"subscribe"," hívásra a neki szóló notificationökhöz. Reconnectkor kérd le az olvasatlan notificationöket a saját modulod inbox-endpointjából (a ",[459,1958,1959],{"href":466},"database csatornára"," építve), hogy backfilleld, ami a kapcsolat megszakadása alatt lemaradt. A socket egy élő poke, a database az igazságforrás.",[455,1962,1963,1964,1966,1967,1970],{},"Ha a gateway ",[478,1965,1097],{},"-vel regisztrált egy methodot, a kliens ",[478,1968,1969],{},"client.rpc(...)","-vel hívja:",[513,1972,1974],{"className":1794,"code":1973,"language":1796,"meta":518,"style":518},"const reply = await client.rpc('chat.send', { body: 'szia' })\n\u002F\u002F reply.data: a handler nyers válasza, JSON.parse a hívó dolga\n",[478,1975,1976,2024],{"__ignoreMap":518},[522,1977,1978,1980,1983,1985,1988,1991,1993,1995,1997,1999,2001,2003,2005,2007,2011,2013,2015,2018,2020,2022],{"class":524,"line":525},[522,1979,1830],{"class":814},[522,1981,1982],{"class":553}," reply ",[522,1984,1836],{"class":532},[522,1986,1987],{"class":528}," await",[522,1989,1990],{"class":553}," client",[522,1992,563],{"class":532},[522,1994,1157],{"class":566},[522,1996,570],{"class":553},[522,1998,1846],{"class":532},[522,2000,1189],{"class":835},[522,2002,1846],{"class":532},[522,2004,576],{"class":532},[522,2006,863],{"class":532},[522,2008,2010],{"class":2009},"swJcz"," body",[522,2012,1863],{"class":532},[522,2014,1816],{"class":532},[522,2016,2017],{"class":835},"szia",[522,2019,1846],{"class":532},[522,2021,1810],{"class":532},[522,2023,605],{"class":553},[522,2025,2026],{"class":524,"line":543},[522,2027,2028],{"class":1883},"\u002F\u002F reply.data: a handler nyers válasza, JSON.parse a hívó dolga\n",[455,2030,2031,2032,2034,2035,2037,2038,2041],{},"Egy sikertelen hívás a ",[478,2033,1303],{},"-t (",[478,2036,478],{},", ",[478,2039,2040],{},"message",") dobja: lásd fentebb a \"Kliens-szerver RPC\" szekciót a hibatérképért.",[470,2043,2045],{"id":2044},"kapcsolódó-oldalak","Kapcsolódó oldalak",[1515,2047,2048,2055,2071],{},[1438,2049,2050,2054],{},[459,2051,2052],{"href":372},[478,2053,480],{},": a publish-only oldal, amit bármely process importálhat.",[1438,2056,2057,2062,2063,2065,2066,752,2068,2070],{},[459,2058,2059],{"href":217},[478,2060,2061],{},"auth\u002Frbac",": az ",[478,2064,855],{},", amire egy kapcsolat JWT-je feloldódik, és amit az ",[478,2067,751],{},[478,2069,755],{}," ellenőriz.",[1438,2072,2073,2075,2076,2079,2080,2082],{},[459,2074,130],{"href":131},": a közös ",[478,2077,2078],{},"app.Run"," váz, amire a ",[478,2081,1335],{}," épül.",[2084,2085,2086],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"title":518,"searchDepth":543,"depth":543,"links":2088},[2089,2090,2091,2092,2093,2094,2095,2098,2099],{"id":472,"depth":543,"text":473},{"id":510,"depth":543,"text":511},{"id":717,"depth":543,"text":718},{"id":1090,"depth":543,"text":1091},{"id":1329,"depth":543,"text":1330},{"id":1509,"depth":543,"text":1510},{"id":1561,"depth":543,"text":1562,"children":2096},[2097],{"id":1739,"depth":550,"text":1740},{"id":1790,"depth":543,"text":1791},{"id":2044,"depth":543,"text":2045},"Dedikált, horizontálisan skálázható gateway, ami élőben pusholja a notificationöket a csatlakozott klienseknek: csak szerver→kliens, centrifuge-ra épülve.","md",null,{},{"icon":147},{"title":144,"description":2100},"M9vXROL18bqncAt_gnGuc3Ue8pzhgVFXGweU5uq6xuY",[2108,2110],{"title":140,"path":141,"stem":142,"description":2109,"icon":114,"children":-1},"A háttérmunka-chassis, asynq szerver, outbox relay és schedule runner egyetlen binárisban, közös graceful shutdownnal.",{"title":149,"path":150,"stem":151,"description":2111,"icon":152,"children":-1},"Időbélyeg-prefixes SQL-fájlok a binárisba ágyazva, saját cmd\u002Fmigrate futtatóval, külső tool nélkül.",1787346795460]