[{"data":1,"prerenderedAt":5814},["ShallowReactive",2],{"navigation_docs":3,"-docs-reference-go-modules-addons":968,"-docs-reference-go-modules-addons-surround":5809},[4,27,63,129,287,311,893,902,950,964],{"title":5,"path":6,"stem":7,"children":8,"order":10,"icon":11},"Overview","\u002Fdocs\u002Foverview","docs\u002F1.overview\u002Findex",[9,12,18,24],{"title":5,"path":6,"stem":7,"order":10,"icon":11},1,"i-lucide-info",{"title":13,"path":14,"stem":15,"order":16,"icon":17},"Getting Started","\u002Fdocs\u002Foverview\u002Fgetting-started","docs\u002F1.overview\u002F2.getting-started",2,"i-lucide-rocket",{"title":19,"path":20,"stem":21,"order":22,"icon":23},"Contributing","\u002Fdocs\u002Foverview\u002Fcontributing","docs\u002F1.overview\u002F3.contributing",3,"i-lucide-heart",{"title":5,"path":25,"stem":26,"order":10},"\u002Fdocs\u002Foverview\u002F_dir","docs\u002F1.overview\u002F_dir",{"title":28,"path":29,"stem":30,"children":31,"page":62},"Concepts","\u002Fdocs\u002Fconcepts","docs\u002F2.concepts",[32,37,42,47,53,59],{"title":33,"path":34,"stem":35,"order":10,"icon":36},"Events","\u002Fdocs\u002Fconcepts\u002Fevents","docs\u002F2.concepts\u002F1.events","i-lucide-zap",{"title":38,"path":39,"stem":40,"order":16,"icon":41},"Transports","\u002Fdocs\u002Fconcepts\u002Ftransports","docs\u002F2.concepts\u002F2.transports","i-lucide-network",{"title":43,"path":44,"stem":45,"order":22,"icon":46},"Module System","\u002Fdocs\u002Fconcepts\u002Fmodules","docs\u002F2.concepts\u002F3.modules","i-lucide-puzzle",{"title":48,"path":49,"stem":50,"order":51,"icon":52},"Flows","\u002Fdocs\u002Fconcepts\u002Fflows","docs\u002F2.concepts\u002F4.flows",4,"i-lucide-workflow",{"title":54,"path":55,"stem":56,"order":57,"icon":58},"Scheduler","\u002Fdocs\u002Fconcepts\u002Fscheduler","docs\u002F2.concepts\u002F5.scheduler",5,"i-lucide-clock",{"title":28,"path":60,"stem":61,"order":16},"\u002Fdocs\u002Fconcepts\u002F_dir","docs\u002F2.concepts\u002F_dir",false,{"title":64,"path":65,"stem":66,"children":67,"page":62},"Guides","\u002Fdocs\u002Fguides","docs\u002F3.guides",[68,73,77,81,85,89,93,98,104,110,116,122,126],{"title":69,"path":70,"stem":71,"order":10,"icon":72},"Creating a Go App","\u002Fdocs\u002Fguides\u002Fcreating-go-app","docs\u002F3.guides\u002F1.creating-go-app","i-lucide-terminal",{"title":74,"path":75,"stem":76},"E2E tests & demo videos","\u002Fdocs\u002Fguides\u002Fe2e-and-demo-videos","docs\u002F3.guides\u002F10.e2e-and-demo-videos",{"title":78,"path":79,"stem":80,"icon":17},"Deploying to production","\u002Fdocs\u002Fguides\u002Fdeploying-to-production","docs\u002F3.guides\u002F11.deploying-to-production",{"title":82,"path":83,"stem":84,"order":16,"icon":46},"Creating a Go Module","\u002Fdocs\u002Fguides\u002Fcreating-go-module","docs\u002F3.guides\u002F2.creating-go-module",{"title":86,"path":87,"stem":88,"order":22,"icon":36},"Adding Events","\u002Fdocs\u002Fguides\u002Fadding-events-to-go-module","docs\u002F3.guides\u002F3.adding-events-to-go-module",{"title":90,"path":91,"stem":92,"order":51,"icon":52},"FlowDSL to Service","\u002Fdocs\u002Fguides\u002Fflowdsl-to-redelay","docs\u002F3.guides\u002F4.flowdsl-to-redelay",{"title":94,"path":95,"stem":96,"order":57,"icon":97},"Choosing a Transport","\u002Fdocs\u002Fguides\u002Fchoosing-a-transport","docs\u002F3.guides\u002F5.choosing-a-transport","i-lucide-git-branch",{"title":99,"path":100,"stem":101,"order":102,"icon":103},"Module Browser (\u002Fmodules)","\u002Fdocs\u002Fguides\u002Fmodules-browser","docs\u002F3.guides\u002F6.modules-browser",6,"i-lucide-layout-dashboard",{"title":105,"path":106,"stem":107,"order":108,"icon":109},"Running Flows","\u002Fdocs\u002Fguides\u002Frunning-flows","docs\u002F3.guides\u002F7.running-flows",7,"i-lucide-play-circle",{"title":111,"path":112,"stem":113,"order":114,"icon":115},"Trace + Live Observability","\u002Fdocs\u002Fguides\u002Fobservability","docs\u002F3.guides\u002F8.observability",8,"i-lucide-activity",{"title":117,"path":118,"stem":119,"order":120,"icon":121},"Project AI Assistant","\u002Fdocs\u002Fguides\u002Fai-assistant","docs\u002F3.guides\u002F9.ai-assistant",9,"i-lucide-sparkles",{"title":123,"path":124,"stem":125},"Debug taps — trace live data through any node","\u002Fdocs\u002Fguides\u002Fdebug-taps","docs\u002F3.guides\u002F9.debug-taps",{"title":64,"path":127,"stem":128,"order":22},"\u002Fdocs\u002Fguides\u002F_dir","docs\u002F3.guides\u002F_dir",{"title":130,"path":131,"stem":132,"children":133,"page":62},"Reference","\u002Fdocs\u002Freference","docs\u002F4.reference",[134,139,143,148,153,158,163,168,172,177,182,187,193,199,205,210,215,219,225,230,236,242,247,253,259,263,267,273,278,284],{"title":135,"path":136,"stem":137,"order":10,"icon":138},"Go Framework","\u002Fdocs\u002Freference\u002Fgo-framework","docs\u002F4.reference\u002F01.go-framework","i-simple-icons-go",{"title":140,"path":141,"stem":142,"order":16,"icon":46},"Built-in Modules","\u002Fdocs\u002Freference\u002Fgo-modules","docs\u002F4.reference\u002F02.go-modules",{"title":144,"path":145,"stem":146,"order":22,"icon":147},"Domain Addon Modules","\u002Fdocs\u002Freference\u002Fgo-modules-addons","docs\u002F4.reference\u002F03.go-modules-addons","i-lucide-blocks",{"title":149,"path":150,"stem":151,"order":51,"icon":152},"Go Events","\u002Fdocs\u002Freference\u002Fgo-events","docs\u002F4.reference\u002F04.go-events","i-lucide-radio",{"title":154,"path":155,"stem":156,"order":57,"icon":157},"Email Module","\u002Fdocs\u002Freference\u002Fgo-module-email","docs\u002F4.reference\u002F05.go-module-email","i-lucide-mail",{"title":159,"path":160,"stem":161,"order":102,"icon":162},"Go Core & IR","\u002Fdocs\u002Freference\u002Fgo-core","docs\u002F4.reference\u002F06.go-core","i-lucide-cpu",{"title":164,"path":165,"stem":166,"order":108,"icon":167},"Module Definition Files","\u002Fdocs\u002Freference\u002Fgo-module-files","docs\u002F4.reference\u002F07.go-module-files","i-lucide-file-code",{"title":169,"path":170,"stem":171,"order":114,"icon":72},"CLI Reference","\u002Fdocs\u002Freference\u002Fgo-cli","docs\u002F4.reference\u002F08.go-cli",{"title":173,"path":174,"stem":175,"order":120,"icon":176},"Go Formats","\u002Fdocs\u002Freference\u002Fgo-formats","docs\u002F4.reference\u002F09.go-formats","i-lucide-file-json",{"title":178,"path":179,"stem":180,"order":181,"icon":152},"AsyncAPI Module","\u002Fdocs\u002Freference\u002Fgo-asyncapi","docs\u002F4.reference\u002F10.go-asyncapi",10,{"title":183,"path":184,"stem":185,"order":186,"icon":52},"Go FlowDSL","\u002Fdocs\u002Freference\u002Fgo-flowdsl","docs\u002F4.reference\u002F11.go-flowdsl",11,{"title":188,"path":189,"stem":190,"order":191,"icon":192},"FlowDSL Examples","\u002Fdocs\u002Freference\u002Fflowdsl-examples","docs\u002F4.reference\u002F12.flowdsl-examples",12,"i-lucide-file-code-2",{"title":194,"path":195,"stem":196,"order":197,"icon":198},"FlowDSL Sync","\u002Fdocs\u002Freference\u002Fflowdsl-sync","docs\u002F4.reference\u002F13.flowdsl-sync",13,"i-lucide-refresh-cw",{"title":200,"path":201,"stem":202,"order":203,"icon":204},"Node.js Framework","\u002Fdocs\u002Freference\u002Fjs-framework","docs\u002F4.reference\u002F14.js-framework",14,"i-simple-icons-nodedotjs",{"title":206,"path":207,"stem":208,"order":203,"icon":209},"Python Framework","\u002Fdocs\u002Freference\u002Fpy-framework","docs\u002F4.reference\u002F14.py-framework","i-simple-icons-python",{"title":211,"path":212,"stem":213,"order":214,"icon":204},"Node.js Events","\u002Fdocs\u002Freference\u002Fjs-events","docs\u002F4.reference\u002F15.js-events",15,{"title":216,"path":217,"stem":218,"order":214,"icon":209},"Python Events","\u002Fdocs\u002Freference\u002Fpy-events","docs\u002F4.reference\u002F15.py-events",{"title":220,"path":221,"stem":222,"order":223,"icon":224},"go-ai — LLM Providers, Guard, Ledger","\u002Fdocs\u002Freference\u002Fgo-ai","docs\u002F4.reference\u002F16.go-ai",16,"i-lucide-brain-circuit",{"title":226,"path":227,"stem":228,"order":229,"icon":41},"Infrastructure Modules","\u002Fdocs\u002Freference\u002Fgeneric-infra-modules","docs\u002F4.reference\u002F17.generic-infra-modules",17,{"title":231,"path":232,"stem":233,"order":234,"icon":235},"Flow Templates","\u002Fdocs\u002Freference\u002Fflow-templates","docs\u002F4.reference\u002F18.flow-templates",18,"i-lucide-library-big",{"title":237,"path":238,"stem":239,"order":240,"icon":241},"Assistant (chat + handoff)","\u002Fdocs\u002Freference\u002Fassistant","docs\u002F4.reference\u002F19.assistant",19,"i-lucide-messages-square",{"title":243,"path":244,"stem":245,"order":246,"icon":41},"Coordination","\u002Fdocs\u002Freference\u002Fcoordination","docs\u002F4.reference\u002F20.coordination",20,{"title":248,"path":249,"stem":250,"order":251,"icon":252},"Search (vector)","\u002Fdocs\u002Freference\u002Fsearch","docs\u002F4.reference\u002F21.search",21,"i-lucide-search",{"title":254,"path":255,"stem":256,"order":257,"icon":258},"Profiles","\u002Fdocs\u002Freference\u002Fprofiles","docs\u002F4.reference\u002F22.profiles",22,"i-lucide-bookmark",{"title":260,"path":261,"stem":262},"Flow-driven HTTP endpoints","\u002Fdocs\u002Freference\u002Fflow-driven-endpoints","docs\u002F4.reference\u002F23.flow-driven-endpoints",{"title":264,"path":265,"stem":266},"Deployments","\u002Fdocs\u002Freference\u002Fdeployments","docs\u002F4.reference\u002F24.deployments",{"title":268,"path":269,"stem":270,"order":271,"icon":272},"i18n (translations)","\u002Fdocs\u002Freference\u002Fi18n","docs\u002F4.reference\u002F25.i18n",25,"i-lucide-languages",{"title":274,"path":275,"stem":276,"order":277,"icon":152},"WebSockets","\u002Fdocs\u002Freference\u002Fwebsockets","docs\u002F4.reference\u002F26.websockets",26,{"title":279,"path":280,"stem":281,"order":282,"icon":283},"Localized content","\u002Fdocs\u002Freference\u002Flocalized-content","docs\u002F4.reference\u002F27.localized-content",27,"i-lucide-file-text",{"title":130,"path":285,"stem":286,"order":51},"\u002Fdocs\u002Freference\u002F_dir","docs\u002F4.reference\u002F_dir",{"title":288,"path":289,"stem":290,"children":291,"page":62},"Integrations","\u002Fdocs\u002Fintegrations","docs\u002F5.integrations",[292,296,300,304,308],{"title":293,"path":294,"stem":295,"order":10,"icon":52},"FlowDSL","\u002Fdocs\u002Fintegrations\u002Fflowdsl","docs\u002F5.integrations\u002F1.flowdsl",{"title":297,"path":298,"stem":299,"order":16,"icon":283},"OpenAPI","\u002Fdocs\u002Fintegrations\u002Fopenapi","docs\u002F5.integrations\u002F2.openapi",{"title":301,"path":302,"stem":303,"order":22,"icon":152},"AsyncAPI","\u002Fdocs\u002Fintegrations\u002Fasyncapi","docs\u002F5.integrations\u002F3.asyncapi",{"title":305,"path":306,"stem":307},"MCP Integration","\u002Fdocs\u002Fintegrations\u002Fmcp","docs\u002F5.integrations\u002F4.mcp",{"title":288,"path":309,"stem":310,"order":57},"\u002Fdocs\u002Fintegrations\u002F_dir","docs\u002F5.integrations\u002F_dir",{"title":312,"path":313,"stem":314,"children":315},"FlowDSL Node Catalog","\u002Fdocs\u002Fnodes","docs\u002F5.nodes\u002Findex",[316,317,321,325,329,333,337,341,345,349,353,357,361,365,369,373,377,381,385,389,393,397,401,405,409,413,417,421,425,429,433,437,441,445,449,453,457,461,465,469,473,477,481,485,489,493,497,501,505,509,513,517,521,525,529,533,537,541,545,549,553,557,561,565,569,573,577,581,585,589,593,597,601,605,609,613,617,621,625,629,633,637,641,645,649,653,657,661,665,669,673,677,681,685,689,693,697,701,705,709,713,717,721,725,729,733,737,741,745,749,753,757,761,765,769,773,777,781,785,789,793,797,801,805,809,813,817,821,825,829,833,837,841,845,849,853,857,861,865,869,873,877,881,885,889],{"title":312,"path":313,"stem":314},{"title":318,"path":319,"stem":320,"order":57},"Node Catalog","\u002Fdocs\u002Fnodes\u002F_dir","docs\u002F5.nodes\u002F_dir",{"title":322,"path":323,"stem":324},"Record Alert","\u002Fdocs\u002Fnodes\u002Falerts_record","docs\u002F5.nodes\u002Falerts_record",{"title":326,"path":327,"stem":328},"Log to API Log","\u002Fdocs\u002Fnodes\u002Fapilog_record","docs\u002F5.nodes\u002Fapilog_record",{"title":330,"path":331,"stem":332},"ClickHouse Exec","\u002Fdocs\u002Fnodes\u002Fclickhouse_exec","docs\u002F5.nodes\u002Fclickhouse_exec",{"title":334,"path":335,"stem":336},"ClickHouse Insert","\u002Fdocs\u002Fnodes\u002Fclickhouse_insert","docs\u002F5.nodes\u002Fclickhouse_insert",{"title":338,"path":339,"stem":340},"ClickHouse Query","\u002Fdocs\u002Fnodes\u002Fclickhouse_query","docs\u002F5.nodes\u002Fclickhouse_query",{"title":342,"path":343,"stem":344},"Array Op","\u002Fdocs\u002Fnodes\u002Fcore_array-ops","docs\u002F5.nodes\u002Fcore_array-ops",{"title":346,"path":347,"stem":348},"Assert","\u002Fdocs\u002Fnodes\u002Fcore_assert","docs\u002F5.nodes\u002Fcore_assert",{"title":350,"path":351,"stem":352},"Audit Emit","\u002Fdocs\u002Fnodes\u002Fcore_audit-emit","docs\u002F5.nodes\u002Fcore_audit-emit",{"title":354,"path":355,"stem":356},"Catch","\u002Fdocs\u002Fnodes\u002Fcore_catch","docs\u002F5.nodes\u002Fcore_catch",{"title":358,"path":359,"stem":360},"DateTime","\u002Fdocs\u002Fnodes\u002Fcore_datetime","docs\u002F5.nodes\u002Fcore_datetime",{"title":362,"path":363,"stem":364},"Dead Letter","\u002Fdocs\u002Fnodes\u002Fcore_dead-letter","docs\u002F5.nodes\u002Fcore_dead-letter",{"title":366,"path":367,"stem":368},"Delay","\u002Fdocs\u002Fnodes\u002Fcore_delay","docs\u002F5.nodes\u002Fcore_delay",{"title":370,"path":371,"stem":372},"ForEach","\u002Fdocs\u002Fnodes\u002Fcore_foreach","docs\u002F5.nodes\u002Fcore_foreach",{"title":374,"path":375,"stem":376},"Idempotency Key","\u002Fdocs\u002Fnodes\u002Fcore_idempotency-key","docs\u002F5.nodes\u002Fcore_idempotency-key",{"title":378,"path":379,"stem":380},"If","\u002Fdocs\u002Fnodes\u002Fcore_if","docs\u002F5.nodes\u002Fcore_if",{"title":382,"path":383,"stem":384},"Inspect","\u002Fdocs\u002Fnodes\u002Fcore_inspect","docs\u002F5.nodes\u002Fcore_inspect",{"title":386,"path":387,"stem":388},"JSON Merge","\u002Fdocs\u002Fnodes\u002Fcore_json-merge","docs\u002F5.nodes\u002Fcore_json-merge",{"title":390,"path":391,"stem":392},"JSON Schema Validate","\u002Fdocs\u002Fnodes\u002Fcore_json-schema-validate","docs\u002F5.nodes\u002Fcore_json-schema-validate",{"title":394,"path":395,"stem":396},"JSONPath Extract","\u002Fdocs\u002Fnodes\u002Fcore_jsonpath-extract","docs\u002F5.nodes\u002Fcore_jsonpath-extract",{"title":398,"path":399,"stem":400},"Log","\u002Fdocs\u002Fnodes\u002Fcore_log","docs\u002F5.nodes\u002Fcore_log",{"title":402,"path":403,"stem":404},"Math","\u002Fdocs\u002Fnodes\u002Fcore_math","docs\u002F5.nodes\u002Fcore_math",{"title":406,"path":407,"stem":408},"Merge","\u002Fdocs\u002Fnodes\u002Fcore_merge","docs\u002F5.nodes\u002Fcore_merge",{"title":410,"path":411,"stem":412},"Metric Counter","\u002Fdocs\u002Fnodes\u002Fcore_metric-counter","docs\u002F5.nodes\u002Fcore_metric-counter",{"title":414,"path":415,"stem":416},"Metric Gauge","\u002Fdocs\u002Fnodes\u002Fcore_metric-gauge","docs\u002F5.nodes\u002Fcore_metric-gauge",{"title":418,"path":419,"stem":420},"Mock","\u002Fdocs\u002Fnodes\u002Fcore_mock","docs\u002F5.nodes\u002Fcore_mock",{"title":422,"path":423,"stem":424},"No-op","\u002Fdocs\u002Fnodes\u002Fcore_noop","docs\u002F5.nodes\u002Fcore_noop",{"title":426,"path":427,"stem":428},"Object Omit","\u002Fdocs\u002Fnodes\u002Fcore_object-omit","docs\u002F5.nodes\u002Fcore_object-omit",{"title":430,"path":431,"stem":432},"Object Pick","\u002Fdocs\u002Fnodes\u002Fcore_object-pick","docs\u002F5.nodes\u002Fcore_object-pick",{"title":434,"path":435,"stem":436},"Parallel Fan-Out","\u002Fdocs\u002Fnodes\u002Fcore_parallel","docs\u002F5.nodes\u002Fcore_parallel",{"title":438,"path":439,"stem":440},"Raise","\u002Fdocs\u002Fnodes\u002Fcore_raise","docs\u002F5.nodes\u002Fcore_raise",{"title":442,"path":443,"stem":444},"Rate Limit Check","\u002Fdocs\u002Fnodes\u002Fcore_rate-limit-check","docs\u002F5.nodes\u002Fcore_rate-limit-check",{"title":446,"path":447,"stem":448},"Regex Extract","\u002Fdocs\u002Fnodes\u002Fcore_regex-extract","docs\u002F5.nodes\u002Fcore_regex-extract",{"title":450,"path":451,"stem":452},"Require Fields","\u002Fdocs\u002Fnodes\u002Fcore_require-fields","docs\u002F5.nodes\u002Fcore_require-fields",{"title":454,"path":455,"stem":456},"Rethrow","\u002Fdocs\u002Fnodes\u002Fcore_rethrow","docs\u002F5.nodes\u002Fcore_rethrow",{"title":458,"path":459,"stem":460},"Return","\u002Fdocs\u002Fnodes\u002Fcore_return","docs\u002F5.nodes\u002Fcore_return",{"title":462,"path":463,"stem":464},"HMAC Signature Verify","\u002Fdocs\u002Fnodes\u002Fcore_signature-verify","docs\u002F5.nodes\u002Fcore_signature-verify",{"title":466,"path":467,"stem":468},"String Op","\u002Fdocs\u002Fnodes\u002Fcore_string-ops","docs\u002F5.nodes\u002Fcore_string-ops",{"title":470,"path":471,"stem":472},"Subflow Invoke","\u002Fdocs\u002Fnodes\u002Fcore_subflow-invoke","docs\u002F5.nodes\u002Fcore_subflow-invoke",{"title":474,"path":475,"stem":476},"Switch","\u002Fdocs\u002Fnodes\u002Fcore_switch","docs\u002F5.nodes\u002Fcore_switch",{"title":478,"path":479,"stem":480},"Template Render","\u002Fdocs\u002Fnodes\u002Fcore_template-render","docs\u002F5.nodes\u002Fcore_template-render",{"title":482,"path":483,"stem":484},"Throttle","\u002Fdocs\u002Fnodes\u002Fcore_throttle","docs\u002F5.nodes\u002Fcore_throttle",{"title":486,"path":487,"stem":488},"Timeout","\u002Fdocs\u002Fnodes\u002Fcore_timeout","docs\u002F5.nodes\u002Fcore_timeout",{"title":490,"path":491,"stem":492},"Type Cast","\u002Fdocs\u002Fnodes\u002Fcore_type-cast","docs\u002F5.nodes\u002Fcore_type-cast",{"title":494,"path":495,"stem":496},"Webhook Respond","\u002Fdocs\u002Fnodes\u002Fcore_webhook-respond","docs\u002F5.nodes\u002Fcore_webhook-respond",{"title":498,"path":499,"stem":500},"File Delete","\u002Fdocs\u002Fnodes\u002Ffilesys_delete","docs\u002F5.nodes\u002Ffilesys_delete",{"title":502,"path":503,"stem":504},"Directory List","\u002Fdocs\u002Fnodes\u002Ffilesys_list","docs\u002F5.nodes\u002Ffilesys_list",{"title":506,"path":507,"stem":508},"File Read","\u002Fdocs\u002Fnodes\u002Ffilesys_read","docs\u002F5.nodes\u002Ffilesys_read",{"title":510,"path":511,"stem":512},"File Stat","\u002Fdocs\u002Fnodes\u002Ffilesys_stat","docs\u002F5.nodes\u002Ffilesys_stat",{"title":514,"path":515,"stem":516},"File Write","\u002Fdocs\u002Fnodes\u002Ffilesys_write","docs\u002F5.nodes\u002Ffilesys_write",{"title":518,"path":519,"stem":520},"FTP Delete","\u002Fdocs\u002Fnodes\u002Fftp_delete","docs\u002F5.nodes\u002Fftp_delete",{"title":522,"path":523,"stem":524},"FTP Download","\u002Fdocs\u002Fnodes\u002Fftp_download","docs\u002F5.nodes\u002Fftp_download",{"title":526,"path":527,"stem":528},"FTP List","\u002Fdocs\u002Fnodes\u002Fftp_list","docs\u002F5.nodes\u002Fftp_list",{"title":530,"path":531,"stem":532},"FTP Upload","\u002Fdocs\u002Fnodes\u002Fftp_upload","docs\u002F5.nodes\u002Fftp_upload",{"title":534,"path":535,"stem":536},"HTTP DELETE","\u002Fdocs\u002Fnodes\u002Fhttp_delete","docs\u002F5.nodes\u002Fhttp_delete",{"title":538,"path":539,"stem":540},"HTTP GET","\u002Fdocs\u002Fnodes\u002Fhttp_get","docs\u002F5.nodes\u002Fhttp_get",{"title":542,"path":543,"stem":544},"HTTP POST","\u002Fdocs\u002Fnodes\u002Fhttp_post","docs\u002F5.nodes\u002Fhttp_post",{"title":546,"path":547,"stem":548},"HTTP PUT","\u002Fdocs\u002Fnodes\u002Fhttp_put","docs\u002F5.nodes\u002Fhttp_put",{"title":550,"path":551,"stem":552},"HTTP Request","\u002Fdocs\u002Fnodes\u002Fhttp_request","docs\u002F5.nodes\u002Fhttp_request",{"title":554,"path":555,"stem":556},"Fill Translations","\u002Fdocs\u002Fnodes\u002Fi18n_fill-translations","docs\u002F5.nodes\u002Fi18n_fill-translations",{"title":558,"path":559,"stem":560},"Resolve Locale","\u002Fdocs\u002Fnodes\u002Fi18n_resolve-locale","docs\u002F5.nodes\u002Fi18n_resolve-locale",{"title":562,"path":563,"stem":564},"Translate","\u002Fdocs\u002Fnodes\u002Fi18n_translate","docs\u002F5.nodes\u002Fi18n_translate",{"title":566,"path":567,"stem":568},"Mongo AGGREGATE","\u002Fdocs\u002Fnodes\u002Fmongoops_aggregate","docs\u002F5.nodes\u002Fmongoops_aggregate",{"title":570,"path":571,"stem":572},"Mongo DELETE","\u002Fdocs\u002Fnodes\u002Fmongoops_delete","docs\u002F5.nodes\u002Fmongoops_delete",{"title":574,"path":575,"stem":576},"Mongo FIND","\u002Fdocs\u002Fnodes\u002Fmongoops_find","docs\u002F5.nodes\u002Fmongoops_find",{"title":578,"path":579,"stem":580},"Mongo FIND ONE","\u002Fdocs\u002Fnodes\u002Fmongoops_find-one","docs\u002F5.nodes\u002Fmongoops_find-one",{"title":582,"path":583,"stem":584},"Mongo INSERT","\u002Fdocs\u002Fnodes\u002Fmongoops_insert","docs\u002F5.nodes\u002Fmongoops_insert",{"title":586,"path":587,"stem":588},"Mongo UPDATE","\u002Fdocs\u002Fnodes\u002Fmongoops_update","docs\u002F5.nodes\u002Fmongoops_update",{"title":590,"path":591,"stem":592},"Postgres COPY FROM","\u002Fdocs\u002Fnodes\u002Fpostgres_copy-from","docs\u002F5.nodes\u002Fpostgres_copy-from",{"title":594,"path":595,"stem":596},"Postgres Exec","\u002Fdocs\u002Fnodes\u002Fpostgres_exec","docs\u002F5.nodes\u002Fpostgres_exec",{"title":598,"path":599,"stem":600},"Postgres Query","\u002Fdocs\u002Fnodes\u002Fpostgres_query","docs\u002F5.nodes\u002Fpostgres_query",{"title":602,"path":603,"stem":604},"Postgres Transaction","\u002Fdocs\u002Fnodes\u002Fpostgres_transaction","docs\u002F5.nodes\u002Fpostgres_transaction",{"title":606,"path":607,"stem":608},"RabbitMQ Consume","\u002Fdocs\u002Fnodes\u002Frabbitmq_consume","docs\u002F5.nodes\u002Frabbitmq_consume",{"title":610,"path":611,"stem":612},"RabbitMQ Declare","\u002Fdocs\u002Fnodes\u002Frabbitmq_declare","docs\u002F5.nodes\u002Frabbitmq_declare",{"title":614,"path":615,"stem":616},"RabbitMQ Publish","\u002Fdocs\u002Fnodes\u002Frabbitmq_publish","docs\u002F5.nodes\u002Frabbitmq_publish",{"title":618,"path":619,"stem":620},"Auth Login","\u002Fdocs\u002Fnodes\u002Fredelay_auth-login","docs\u002F5.nodes\u002Fredelay_auth-login",{"title":622,"path":623,"stem":624},"Require Permission","\u002Fdocs\u002Fnodes\u002Fredelay_auth-require-permission","docs\u002F5.nodes\u002Fredelay_auth-require-permission",{"title":626,"path":627,"stem":628},"Validate Token","\u002Fdocs\u002Fnodes\u002Fredelay_auth-validate-token","docs\u002F5.nodes\u002Fredelay_auth-validate-token",{"title":630,"path":631,"stem":632},"Render Email Template","\u002Fdocs\u002Fnodes\u002Fredelay_email-render-template","docs\u002F5.nodes\u002Fredelay_email-render-template",{"title":634,"path":635,"stem":636},"Send Email","\u002Fdocs\u002Fnodes\u002Fredelay_email-send","docs\u002F5.nodes\u002Fredelay_email-send",{"title":638,"path":639,"stem":640},"Send Templated Email","\u002Fdocs\u002Fnodes\u002Fredelay_email-send-templated","docs\u002F5.nodes\u002Fredelay_email-send-templated",{"title":642,"path":643,"stem":644},"Event Source","\u002Fdocs\u002Fnodes\u002Fredelay_event-source","docs\u002F5.nodes\u002Fredelay_event-source",{"title":646,"path":647,"stem":648},"Create Group","\u002Fdocs\u002Fnodes\u002Fredelay_groups-create-group","docs\u002F5.nodes\u002Fredelay_groups-create-group",{"title":650,"path":651,"stem":652},"Delete Group","\u002Fdocs\u002Fnodes\u002Fredelay_groups-delete-group","docs\u002F5.nodes\u002Fredelay_groups-delete-group",{"title":654,"path":655,"stem":656},"Resolve Permissions","\u002Fdocs\u002Fnodes\u002Fredelay_groups-resolve-permissions","docs\u002F5.nodes\u002Fredelay_groups-resolve-permissions",{"title":658,"path":659,"stem":660},"Update Group","\u002Fdocs\u002Fnodes\u002Fredelay_groups-update-group","docs\u002F5.nodes\u002Fredelay_groups-update-group",{"title":662,"path":663,"stem":664},"HTTP Endpoint","\u002Fdocs\u002Fnodes\u002Fredelay_http-endpoint","docs\u002F5.nodes\u002Fredelay_http-endpoint",{"title":666,"path":667,"stem":668},"JSON Stream Source","\u002Fdocs\u002Fnodes\u002Fredelay_json-stream-source","docs\u002F5.nodes\u002Fredelay_json-stream-source",{"title":670,"path":671,"stem":672},"JSON → Event","\u002Fdocs\u002Fnodes\u002Fredelay_json-to-event","docs\u002F5.nodes\u002Fredelay_json-to-event",{"title":674,"path":675,"stem":676},"Kafka Produce","\u002Fdocs\u002Fnodes\u002Fredelay_kafka-produce","docs\u002F5.nodes\u002Fredelay_kafka-produce",{"title":678,"path":679,"stem":680},"Create Short Link","\u002Fdocs\u002Fnodes\u002Fredelay_links-create","docs\u002F5.nodes\u002Fredelay_links-create",{"title":682,"path":683,"stem":684},"Delete Short Link","\u002Fdocs\u002Fnodes\u002Fredelay_links-delete","docs\u002F5.nodes\u002Fredelay_links-delete",{"title":686,"path":687,"stem":688},"Resolve Short Link","\u002Fdocs\u002Fnodes\u002Fredelay_links-resolve","docs\u002F5.nodes\u002Fredelay_links-resolve",{"title":690,"path":691,"stem":692},"LLM Chat","\u002Fdocs\u002Fnodes\u002Fredelay_llm-chat","docs\u002F5.nodes\u002Fredelay_llm-chat",{"title":694,"path":695,"stem":696},"LLM Embed","\u002Fdocs\u002Fnodes\u002Fredelay_llm-embed","docs\u002F5.nodes\u002Fredelay_llm-embed",{"title":698,"path":699,"stem":700},"LLM Guard","\u002Fdocs\u002Fnodes\u002Fredelay_llm-guard","docs\u002F5.nodes\u002Fredelay_llm-guard",{"title":702,"path":703,"stem":704},"LLM Tool Router","\u002Fdocs\u002Fnodes\u002Fredelay_llm-tool-router","docs\u002F5.nodes\u002Fredelay_llm-tool-router",{"title":706,"path":707,"stem":708},"NATS Publish","\u002Fdocs\u002Fnodes\u002Fredelay_nats-publish","docs\u002F5.nodes\u002Fredelay_nats-publish",{"title":710,"path":711,"stem":712},"Mark Notification Read","\u002Fdocs\u002Fnodes\u002Fredelay_notifications-mark-read","docs\u002F5.nodes\u002Fredelay_notifications-mark-read",{"title":714,"path":715,"stem":716},"Send Notification","\u002Fdocs\u002Fnodes\u002Fredelay_notifications-send","docs\u002F5.nodes\u002Fredelay_notifications-send",{"title":718,"path":719,"stem":720},"Redis Stream XADD","\u002Fdocs\u002Fnodes\u002Fredelay_redis-stream-publish","docs\u002F5.nodes\u002Fredelay_redis-stream-publish",{"title":722,"path":723,"stem":724},"S3 Copy Object","\u002Fdocs\u002Fnodes\u002Fredelay_s3-copy-object","docs\u002F5.nodes\u002Fredelay_s3-copy-object",{"title":726,"path":727,"stem":728},"S3 Delete Many","\u002Fdocs\u002Fnodes\u002Fredelay_s3-delete-many","docs\u002F5.nodes\u002Fredelay_s3-delete-many",{"title":730,"path":731,"stem":732},"S3 Head Object","\u002Fdocs\u002Fnodes\u002Fredelay_s3-head-object","docs\u002F5.nodes\u002Fredelay_s3-head-object",{"title":734,"path":735,"stem":736},"S3 List Objects","\u002Fdocs\u002Fnodes\u002Fredelay_s3-list-objects","docs\u002F5.nodes\u002Fredelay_s3-list-objects",{"title":738,"path":739,"stem":740},"Create Schedule","\u002Fdocs\u002Fnodes\u002Fredelay_scheduler-create-schedule","docs\u002F5.nodes\u002Fredelay_scheduler-create-schedule",{"title":742,"path":743,"stem":744},"Cron Trigger","\u002Fdocs\u002Fnodes\u002Fredelay_scheduler-cron-trigger","docs\u002F5.nodes\u002Fredelay_scheduler-cron-trigger",{"title":746,"path":747,"stem":748},"Delete Schedule","\u002Fdocs\u002Fnodes\u002Fredelay_scheduler-delete-schedule","docs\u002F5.nodes\u002Fredelay_scheduler-delete-schedule",{"title":750,"path":751,"stem":752},"Interval Trigger","\u002Fdocs\u002Fnodes\u002Fredelay_scheduler-interval-trigger","docs\u002F5.nodes\u002Fredelay_scheduler-interval-trigger",{"title":754,"path":755,"stem":756},"Search Query","\u002Fdocs\u002Fnodes\u002Fredelay_search-query","docs\u002F5.nodes\u002Fredelay_search-query",{"title":758,"path":759,"stem":760},"Search Upsert","\u002Fdocs\u002Fnodes\u002Fredelay_search-upsert","docs\u002F5.nodes\u002Fredelay_search-upsert",{"title":762,"path":763,"stem":764},"Delete Setting","\u002Fdocs\u002Fnodes\u002Fredelay_settings-delete","docs\u002F5.nodes\u002Fredelay_settings-delete",{"title":766,"path":767,"stem":768},"Get Setting","\u002Fdocs\u002Fnodes\u002Fredelay_settings-get","docs\u002F5.nodes\u002Fredelay_settings-get",{"title":770,"path":771,"stem":772},"Set Setting","\u002Fdocs\u002Fnodes\u002Fredelay_settings-set","docs\u002F5.nodes\u002Fredelay_settings-set",{"title":774,"path":775,"stem":776},"Delete File","\u002Fdocs\u002Fnodes\u002Fredelay_storage-delete","docs\u002F5.nodes\u002Fredelay_storage-delete",{"title":778,"path":779,"stem":780},"Download File","\u002Fdocs\u002Fnodes\u002Fredelay_storage-download","docs\u002F5.nodes\u002Fredelay_storage-download",{"title":782,"path":783,"stem":784},"Generate Presigned URL","\u002Fdocs\u002Fnodes\u002Fredelay_storage-presign-url","docs\u002F5.nodes\u002Fredelay_storage-presign-url",{"title":786,"path":787,"stem":788},"Upload File","\u002Fdocs\u002Fnodes\u002Fredelay_storage-upload","docs\u002F5.nodes\u002Fredelay_storage-upload",{"title":790,"path":791,"stem":792},"Subworkflow","\u002Fdocs\u002Fnodes\u002Fredelay_subworkflow","docs\u002F5.nodes\u002Fredelay_subworkflow",{"title":794,"path":795,"stem":796},"Activate User","\u002Fdocs\u002Fnodes\u002Fredelay_users-activate","docs\u002F5.nodes\u002Fredelay_users-activate",{"title":798,"path":799,"stem":800},"Create Pending User","\u002Fdocs\u002Fnodes\u002Fredelay_users-create-pending","docs\u002F5.nodes\u002Fredelay_users-create-pending",{"title":802,"path":803,"stem":804},"Create User","\u002Fdocs\u002Fnodes\u002Fredelay_users-create-user","docs\u002F5.nodes\u002Fredelay_users-create-user",{"title":806,"path":807,"stem":808},"Delete User","\u002Fdocs\u002Fnodes\u002Fredelay_users-delete-user","docs\u002F5.nodes\u002Fredelay_users-delete-user",{"title":810,"path":811,"stem":812},"Find User By Email","\u002Fdocs\u002Fnodes\u002Fredelay_users-find-by-email","docs\u002F5.nodes\u002Fredelay_users-find-by-email",{"title":814,"path":815,"stem":816},"Get User","\u002Fdocs\u002Fnodes\u002Fredelay_users-get-user","docs\u002F5.nodes\u002Fredelay_users-get-user",{"title":818,"path":819,"stem":820},"List Users","\u002Fdocs\u002Fnodes\u002Fredelay_users-list-users","docs\u002F5.nodes\u002Fredelay_users-list-users",{"title":822,"path":823,"stem":824},"Update User","\u002Fdocs\u002Fnodes\u002Fredelay_users-update-user","docs\u002F5.nodes\u002Fredelay_users-update-user",{"title":826,"path":827,"stem":828},"Request Email Verification (legacy)","\u002Fdocs\u002Fnodes\u002Fredelay_verification-request","docs\u002F5.nodes\u002Fredelay_verification-request",{"title":830,"path":831,"stem":832},"Request Email Verification","\u002Fdocs\u002Fnodes\u002Fredelay_verification-request-email","docs\u002F5.nodes\u002Fredelay_verification-request-email",{"title":834,"path":835,"stem":836},"Request SMS Verification","\u002Fdocs\u002Fnodes\u002Fredelay_verification-request-sms","docs\u002F5.nodes\u002Fredelay_verification-request-sms",{"title":838,"path":839,"stem":840},"Verify Token","\u002Fdocs\u002Fnodes\u002Fredelay_verification-verify","docs\u002F5.nodes\u002Fredelay_verification-verify",{"title":842,"path":843,"stem":844},"Redis DEL","\u002Fdocs\u002Fnodes\u002Fredisops_del","docs\u002F5.nodes\u002Fredisops_del",{"title":846,"path":847,"stem":848},"Redis EXPIRE","\u002Fdocs\u002Fnodes\u002Fredisops_expire","docs\u002F5.nodes\u002Fredisops_expire",{"title":850,"path":851,"stem":852},"Redis GET","\u002Fdocs\u002Fnodes\u002Fredisops_get","docs\u002F5.nodes\u002Fredisops_get",{"title":854,"path":855,"stem":856},"Redis HGET","\u002Fdocs\u002Fnodes\u002Fredisops_hget","docs\u002F5.nodes\u002Fredisops_hget",{"title":858,"path":859,"stem":860},"Redis HSET","\u002Fdocs\u002Fnodes\u002Fredisops_hset","docs\u002F5.nodes\u002Fredisops_hset",{"title":862,"path":863,"stem":864},"Redis INCR","\u002Fdocs\u002Fnodes\u002Fredisops_incr","docs\u002F5.nodes\u002Fredisops_incr",{"title":866,"path":867,"stem":868},"Redis LPOP","\u002Fdocs\u002Fnodes\u002Fredisops_lpop","docs\u002F5.nodes\u002Fredisops_lpop",{"title":870,"path":871,"stem":872},"Redis LPUSH","\u002Fdocs\u002Fnodes\u002Fredisops_lpush","docs\u002F5.nodes\u002Fredisops_lpush",{"title":874,"path":875,"stem":876},"Redis PUBLISH","\u002Fdocs\u002Fnodes\u002Fredisops_publish","docs\u002F5.nodes\u002Fredisops_publish",{"title":878,"path":879,"stem":880},"Redis SET","\u002Fdocs\u002Fnodes\u002Fredisops_set","docs\u002F5.nodes\u002Fredisops_set",{"title":882,"path":883,"stem":884},"SFTP Download","\u002Fdocs\u002Fnodes\u002Fsftp_download","docs\u002F5.nodes\u002Fsftp_download",{"title":886,"path":887,"stem":888},"SFTP Upload","\u002Fdocs\u002Fnodes\u002Fsftp_upload","docs\u002F5.nodes\u002Fsftp_upload",{"title":890,"path":891,"stem":892},"Send SMS","\u002Fdocs\u002Fnodes\u002Fsms_send","docs\u002F5.nodes\u002Fsms_send",{"title":894,"path":895,"stem":896,"children":897,"page":62},"Rfcs","\u002Fdocs\u002Frfcs","docs\u002F6.rfcs",[898],{"title":899,"path":900,"stem":901},"RFC 0001 — Worker Assignment for Flow Deployments","\u002Fdocs\u002Frfcs\u002F0001-worker-assignment","docs\u002F6.rfcs\u002F0001-worker-assignment",{"title":903,"path":904,"stem":905,"children":906,"page":62},"Admin","\u002Fdocs\u002Fadmin","docs\u002F7.admin",[907,912,917,922,927,932,937,941,946],{"title":5,"path":908,"stem":909,"order":910,"icon":911},"\u002Fdocs\u002Fadmin\u002Foverview","docs\u002F7.admin\u002F00.overview",0,"i-lucide-compass",{"title":913,"path":914,"stem":915,"order":10,"icon":916},"Getting started","\u002Fdocs\u002Fadmin\u002Fgetting-started","docs\u002F7.admin\u002F01.getting-started","i-lucide-play",{"title":918,"path":919,"stem":920,"order":16,"icon":921},"Layered architecture","\u002Fdocs\u002Fadmin\u002Flayered-architecture","docs\u002F7.admin\u002F02.layered-architecture","i-lucide-layers",{"title":923,"path":924,"stem":925,"order":22,"icon":926},"Building a custom admin project","\u002Fdocs\u002Fadmin\u002Fbuilding-a-custom-admin-project","docs\u002F7.admin\u002F03.building-a-custom-admin-project","i-lucide-folder-plus",{"title":928,"path":929,"stem":930,"order":51,"icon":931},"Building admin modules","\u002Fdocs\u002Fadmin\u002Fbuilding-admin-modules","docs\u002F7.admin\u002F04.building-admin-modules","i-lucide-package-plus",{"title":933,"path":934,"stem":935,"order":57,"icon":936},"Base module reference","\u002Fdocs\u002Fadmin\u002Freference-base-modules","docs\u002F7.admin\u002F05.reference-base-modules","i-lucide-boxes",{"title":938,"path":939,"stem":940,"order":102,"icon":17},"Deployment","\u002Fdocs\u002Fadmin\u002Fdeployment","docs\u002F7.admin\u002F06.deployment",{"title":942,"path":943,"stem":944,"order":108,"icon":945},"Consuming the base layer (versioned)","\u002Fdocs\u002Fadmin\u002Fconsuming-the-base-layer","docs\u002F7.admin\u002F07.consuming-the-base-layer","i-lucide-package",{"title":947,"path":948,"stem":949,"order":108},"Admin UI","\u002Fdocs\u002Fadmin\u002F_dir","docs\u002F7.admin\u002F_dir",{"title":951,"path":952,"stem":953,"children":954,"page":62},"Services","\u002Fdocs\u002Fservices","docs\u002F8.services",[955,960],{"title":956,"path":957,"stem":958,"order":10,"icon":959},"Custom development & support services","\u002Fdocs\u002Fservices\u002Fcustom-development","docs\u002F8.services\u002F1.custom-development","i-lucide-briefcase",{"title":951,"path":961,"stem":962,"icon":959,"order":963},"\u002Fdocs\u002Fservices\u002F_dir","docs\u002F8.services\u002F_dir",80,{"title":965,"path":966,"stem":967,"order":910},"Dir","\u002Fdocs\u002F_dir","docs\u002F_dir",{"id":969,"title":144,"body":970,"description":5802,"extension":5803,"links":5804,"meta":5805,"navigation":5806,"path":145,"seo":5807,"stem":146,"__hash__":5808},"docs\u002Fdocs\u002F4.reference\u002F03.go-modules-addons.md",{"type":971,"value":972,"toc":5733},"minimark",[973,977,990,1005,1010,1034,1065,1069,1517,1537,1541,1548,1570,1721,1728,1731,1733,1738,1741,1764,1769,1882,1886,1896,1914,1927,1937,1941,1955,2097,2107,2117,2128,2132,2145,2168,2171,2208,2216,2241,2256,2271,2392,2429,2490,2494,2497,2579,2592,2594,2596,2601,2608,2612,2647,2657,2661,2719,2737,2741,2748,2799,2804,2869,2875,2879,2898,2902,2933,2938,2967,2978,2993,3073,3083,3095,3098,3242,3246,3255,3301,3309,3319,3405,3409,3424,3469,3484,3488,3519,3522,3585,3589,3617,3623,3681,3683,3685,3690,3696,3700,3725,3728,3816,3818,3820,3825,3840,3844,3900,3903,3930,3934,4043,4045,4047,4052,4063,4066,4108,4112,4122,4196,4199,4256,4258,4260,4265,4275,4278,4346,4349,4405,4407,4409,4414,4428,4431,4459,4463,4499,4503,4515,4522,4591,4594,4596,4598,4603,4614,4618,4715,4719,4733,4736,4868,4870,4872,4877,4886,4889,4987,4994,5007,5010,5099,5101,5103,5108,5120,5143,5149,5201,5204,5224,5228,5239,5242,5247,5376,5383,5399,5404,5457,5483,5488,5517,5530,5568,5588,5592,5608,5616,5631,5635,5639,5709,5715,5719,5729],[974,975,144],"h1",{"id":976},"domain-addon-modules",[978,979,980,984,985,989],"p",{},[981,982,983],"code",{},"github.com\u002Fredelay\u002Fgo-modules"," provides ",[986,987,988],"strong",{},"domain-level feature modules"," that extend the Redelay framework. Each module is added via a blank import and works with zero configuration defaults.",[991,992,993,994,999,1000,1004],"callout",{"icon":921},"Looking for raw infrastructure nodes (Redis\u002FMongo\u002FKafka\u002FHTTP\u002Ffile\u002FSMS\u002FFTP\u002FSFTP\u002FPostgres\u002FClickHouse\u002FRabbitMQ) to compose directly in FlowDSL flows? See the ",[995,996,997],"a",{"href":227},[986,998,226],{}," reference and the ",[995,1001,1002],{"href":313},[986,1003,318],{},".",[1006,1007,1009],"h2",{"id":1008},"quick-start","Quick start",[1011,1012,1017],"pre",{"className":1013,"code":1014,"language":1015,"meta":1016,"style":1016},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","go get github.com\u002Fredelay\u002Fgo-modules\n","bash","",[981,1018,1019],{"__ignoreMap":1016},[1020,1021,1023,1027,1031],"span",{"class":1022,"line":10},"line",[1020,1024,1026],{"class":1025},"sBMFI","go",[1020,1028,1030],{"class":1029},"sfazB"," get",[1020,1032,1033],{"class":1029}," github.com\u002Fredelay\u002Fgo-modules\n",[1011,1035,1038],{"className":1036,"code":1037,"language":1026,"meta":1016,"style":1016},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import (\n    _ \"github.com\u002Fredelay\u002Fgo-modules\u002Fscheduler\"\n    _ \"github.com\u002Fredelay\u002Fgo-modules\u002Fmetrics\"\n    \u002F\u002F add more as needed\n)\n",[981,1039,1040,1045,1050,1055,1060],{"__ignoreMap":1016},[1020,1041,1042],{"class":1022,"line":10},[1020,1043,1044],{},"import (\n",[1020,1046,1047],{"class":1022,"line":16},[1020,1048,1049],{},"    _ \"github.com\u002Fredelay\u002Fgo-modules\u002Fscheduler\"\n",[1020,1051,1052],{"class":1022,"line":22},[1020,1053,1054],{},"    _ \"github.com\u002Fredelay\u002Fgo-modules\u002Fmetrics\"\n",[1020,1056,1057],{"class":1022,"line":51},[1020,1058,1059],{},"    \u002F\u002F add more as needed\n",[1020,1061,1062],{"class":1022,"line":57},[1020,1063,1064],{},")\n",[1006,1066,1068],{"id":1067},"module-overview","Module overview",[1070,1071,1072,1088],"table",{},[1073,1074,1075],"thead",{},[1076,1077,1078,1082,1085],"tr",{},[1079,1080,1081],"th",{},"Module",[1079,1083,1084],{},"Package",[1079,1086,1087],{},"Purpose",[1089,1090,1091,1108,1124,1140,1156,1172,1188,1204,1220,1235,1292,1310,1325,1340,1360,1373,1386,1407,1469,1504],"tbody",{},[1076,1092,1093,1100,1105],{},[1094,1095,1096],"td",{},[995,1097,1099],{"href":1098},"#scheduler","scheduler",[1094,1101,1102],{},[981,1103,1104],{},"go-modules\u002Fscheduler",[1094,1106,1107],{},"Distributed cron with leader election",[1076,1109,1110,1116,1121],{},[1094,1111,1112],{},[995,1113,1115],{"href":1114},"#settings","settings",[1094,1117,1118],{},[981,1119,1120],{},"go-framework\u002Fmodules\u002Fsettings",[1094,1122,1123],{},"Key-value settings API",[1076,1125,1126,1132,1137],{},[1094,1127,1128],{},[995,1129,1131],{"href":1130},"#storage","storage",[1094,1133,1134],{},[981,1135,1136],{},"go-modules\u002Fstorage",[1094,1138,1139],{},"Object storage (S3\u002FMinIO) with S3 list \u002F head \u002F copy \u002F delete-many nodes",[1076,1141,1142,1148,1153],{},[1094,1143,1144],{},[995,1145,1147],{"href":1146},"#notifications","notifications",[1094,1149,1150],{},[981,1151,1152],{},"go-modules\u002Fnotifications",[1094,1154,1155],{},"Real-time SSE notifications",[1076,1157,1158,1164,1169],{},[1094,1159,1160],{},[995,1161,1163],{"href":1162},"#verification","verification",[1094,1165,1166],{},[981,1167,1168],{},"go-modules\u002Fverification",[1094,1170,1171],{},"Email address verification",[1076,1173,1174,1180,1185],{},[1094,1175,1176],{},[995,1177,1179],{"href":1178},"#links","links",[1094,1181,1182],{},[981,1183,1184],{},"go-modules\u002Flinks",[1094,1186,1187],{},"URL shortener",[1076,1189,1190,1196,1201],{},[1094,1191,1192],{},[995,1193,1195],{"href":1194},"#metrics","metrics",[1094,1197,1198],{},[981,1199,1200],{},"go-modules\u002Fmetrics",[1094,1202,1203],{},"Prometheus metrics",[1076,1205,1206,1212,1217],{},[1094,1207,1208],{},[995,1209,1211],{"href":1210},"#flowexec","flowexec",[1094,1213,1214],{},[981,1215,1216],{},"go-flowdsl\u002Fflowexec\u002Fmodule",[1094,1218,1219],{},"Flow CRUD, versioning, run launch, live SSE events",[1076,1221,1222,1227,1232],{},[1094,1223,1224],{},[995,1225,1226],{"href":249},"search",[1094,1228,1229],{},[981,1230,1231],{},"go-modules\u002Fsearch",[1094,1233,1234],{},"Pluggable vector search (Qdrant today, OpenSearch planned) with index CRUD + FlowDSL upsert\u002Fquery nodes",[1076,1236,1237,1242,1247],{},[1094,1238,1239],{},[995,1240,1241],{"href":269},"i18n",[1094,1243,1244],{},[981,1245,1246],{},"go-modules\u002Fi18n",[1094,1248,1249,1250,1253,1254,1257,1258,1261,1262,1265,1266,1269,1270,1273,1274,1276,1277,1280,1281,1284,1285,1288,1289,1004],{},"Locale-resolution middleware, Mongo message catalog with fallback chain, admin CRUD, translate\u002Fresolve-locale nodes. Also drives customer-app UI-label i18n: write-once ",[981,1251,1252],{},"POST \u002Fi18n\u002Freport-keys"," (frontend auto-registers the ",[981,1255,1256],{},"$t"," keys it uses; ",[981,1259,1260],{},"I18N_AUTOREGISTER","), admin ",[981,1263,1264],{},"POST \u002Fadmin\u002Fi18n\u002Ftranslations\u002Ftranslate-missing"," (bulk AI-translate every active locale via the ",[981,1267,1268],{},"ai"," module), and a per-key ",[981,1271,1272],{},"Translation.Context"," hint. Reusable frontend ",[981,1275,1256],{}," plumbing — catalog + ICU plurals via ",[981,1278,1279],{},"Intl.PluralRules"," + interpolation + build-time extractor — ships in ",[981,1282,1283],{},"redelay-starter-kit\u002Ftemplates\u002Fnuxt-i18n",". The admin Translations catalog adds a Default-text column, per-row Re-translate, and per-key context; localized admin fields (",[981,1286,1287],{},"LocalizedField",") take a per-field ",[981,1290,1291],{},"context",[1076,1293,1294,1299,1304],{},[1094,1295,1296],{},[995,1297,1298],{"href":232},"flowtemplates",[1094,1300,1301],{},[981,1302,1303],{},"go-modules\u002Fflowtemplates",[1094,1305,1306,1307],{},"Curated starter flows surfaced via ",[981,1308,1309],{},"flowexec.TemplateProvider",[1076,1311,1312,1317,1322],{},[1094,1313,1314],{},[995,1315,1316],{"href":244},"coordination",[1094,1318,1319],{},[981,1320,1321],{},"go-modules\u002Fcoordination",[1094,1323,1324],{},"Cross-container Coordinator — pub\u002Fsub, streams, KV (NATS or Redis backend)",[1076,1326,1327,1332,1337],{},[1094,1328,1329],{},[995,1330,1331],{"href":275},"websockets",[1094,1333,1334],{},[981,1335,1336],{},"go-modules\u002Fws",[1094,1338,1339],{},"WebSocket hub — rooms + cross-replica fan-out, health\u002Finfo\u002Fbroadcast control plane",[1076,1341,1342,1348,1353],{},[1094,1343,1344],{},[995,1345,1347],{"href":1346},"#security","security",[1094,1349,1350],{},[981,1351,1352],{},"go-modules\u002Fsecurity",[1094,1354,1355,1356,1359],{},"Per-user security — activity log, trusted devices, rate limits, auto-restriction; ",[981,1357,1358],{},"security\u002Fadmin"," for IP blocks + user restriction",[1076,1361,1362,1365,1370],{},[1094,1363,1364],{},"eventadmin",[1094,1366,1367],{},[981,1368,1369],{},"go-modules\u002Feventadmin",[1094,1371,1372],{},"Event-bus admin (admin-api only) — event definitions, manual publish, event log, webhook subscriptions",[1076,1374,1375,1378,1383],{},[1094,1376,1377],{},"metrics\u002Fadmin",[1094,1379,1380],{},[981,1381,1382],{},"go-modules\u002Fmetrics\u002Fadmin",[1094,1384,1385],{},"Database observability (admin-api only) — live ClickHouse\u002FMongo\u002FRedis stats",[1076,1387,1388,1391,1396],{},[1094,1389,1390],{},"apilog",[1094,1392,1393],{},[981,1394,1395],{},"go-modules\u002Fapilog",[1094,1397,1398,1399,1402,1403,1406],{},"Time-series log of outbound external API calls, queryable in admin; ",[981,1400,1401],{},"Mask()"," redaction + ",[981,1404,1405],{},"apilog\u002Frecord"," debug node",[1076,1408,1409,1411,1416],{},[1094,1410,1268],{},[1094,1412,1413],{},[981,1414,1415],{},"go-modules\u002Fai",[1094,1417,1418,1419,1422,1423,1426,1427,1430,1431,1434,1435,1438,1439,1442,1443,1446,1447,1426,1450,1453,1454,1457,1458,1461,1462,1465,1466,1468],{},"Provider-agnostic, LLM-assisted content authoring on go-ai (stateless — no DB). ",[981,1420,1421],{},"ai\u002Fadmin"," (admin-api only): ",[981,1424,1425],{},"POST \u002Fadmin\u002Fai\u002Ftranslate"," (",[981,1428,1429],{},"{text,from,to,context?}",") + ",[981,1432,1433],{},"POST \u002Fadmin\u002Fai\u002Fgenerate",". Model selection via the ",[981,1436,1437],{},"ai.models"," settings group — ",[981,1440,1441],{},"profile"," (a named ",[981,1444,1445],{},"llm-chat"," profile: provider+model+creds+tuning, overrides the flat fields) \u002F ",[981,1448,1449],{},"provider",[981,1451,1452],{},"options_ref llm.providers",") \u002F ",[981,1455,1456],{},"model"," \u002F ",[981,1459,1460],{},"temperature"," — admin-editable, no restart; per-consumer profiles let each feature run its own model. ",[981,1463,1464],{},"translate"," validates format (placeholders \u002F ICU-plural structure \u002F HTML tags preserved — corrupt locales re-requested then omitted) and translates ICU-plural sources one locale per call; ",[981,1467,1291],{}," disambiguates ambiguous terms.",[1076,1470,1471,1474,1479],{},[1094,1472,1473],{},"content",[1094,1475,1476],{},[981,1477,1478],{},"go-modules\u002Fcontent",[1094,1480,1481,1482,1485,1486,1489,1490,1493,1494,1497,1498,1501,1502,1004],{},"CMS-lite scope-scoped localized pages (",[981,1483,1484],{},"\u002Fpages\u002F{slug}",") + reusable fragments (",[981,1487,1488],{},"\u002Ffragments\u002F{key}","). Prose may embed ",[981,1491,1492],{},"[[ module.key ]]"," settings tokens, resolved per request against the PUBLIC settings gate. Fragment leaves are localized with an explicit ",[981,1495,1496],{},"_i18n"," marker; both pages and fragments carry ",[981,1499,1500],{},"crud.TranslationState"," (ready \u002F stale \u002F retranslate). See ",[995,1503,279],{"href":280},[1076,1505,1506,1509,1514],{},[1094,1507,1508],{},"workers",[1094,1510,1511],{},[981,1512,1513],{},"go-modules\u002Fworkers",[1094,1515,1516],{},"Cross-instance worker registry with heartbeat tracking",[978,1518,1519,1426,1522,1525,1526,1529,1530,1533,1534,1004],{},[981,1520,1521],{},"audit",[981,1523,1524],{},"go-modules\u002Faudit",") is a ",[986,1527,1528],{},"library package, not a module"," — it has no factory and\nis not blank-imported. Entities embed ",[981,1531,1532],{},"History []audit.Event"," and append via ",[981,1535,1536],{},"audit.Push",[1006,1538,1540],{"id":1539},"flowdsl-node-subpackages","FlowDSL node subpackages",[978,1542,1543,1544,1547],{},"Each module (except metrics and flowexec) ships a ",[981,1545,1546],{},"flowdsl\u002F"," subpackage that registers FlowDSL\nnodes as a companion module. Enable them with a blank import:",[1011,1549,1551],{"className":1036,"code":1550,"language":1026,"meta":1016,"style":1016},"import (\n    _ \"github.com\u002Fredelay\u002Fgo-modules\u002Fscheduler\"\n    _ \"github.com\u002Fredelay\u002Fgo-modules\u002Fscheduler\u002Fflowdsl\"   \u002F\u002F 4 FlowDSL nodes\n)\n",[981,1552,1553,1557,1561,1566],{"__ignoreMap":1016},[1020,1554,1555],{"class":1022,"line":10},[1020,1556,1044],{},[1020,1558,1559],{"class":1022,"line":16},[1020,1560,1049],{},[1020,1562,1563],{"class":1022,"line":22},[1020,1564,1565],{},"    _ \"github.com\u002Fredelay\u002Fgo-modules\u002Fscheduler\u002Fflowdsl\"   \u002F\u002F 4 FlowDSL nodes\n",[1020,1567,1568],{"class":1022,"line":51},[1020,1569,1064],{},[1070,1571,1572,1588],{},[1073,1573,1574],{},[1076,1575,1576,1579,1582,1585],{},[1079,1577,1578],{},"Subpackage",[1079,1580,1581],{},"Factory",[1079,1583,1584],{},"Nodes",[1079,1586,1587],{},"Kinds",[1089,1589,1590,1608,1626,1644,1661,1679,1696],{},[1076,1591,1592,1597,1602,1605],{},[1094,1593,1594],{},[981,1595,1596],{},"scheduler\u002Fflowdsl",[1094,1598,1599],{},[981,1600,1601],{},"scheduler-flowdsl",[1094,1603,1604],{},"4",[1094,1606,1607],{},"2 source (with settings_schema), 2 action",[1076,1609,1610,1615,1620,1623],{},[1094,1611,1612],{},[981,1613,1614],{},"settings\u002Fflowdsl",[1094,1616,1617],{},[981,1618,1619],{},"settings-flowdsl",[1094,1621,1622],{},"3",[1094,1624,1625],{},"1 transform (with NotFound), 2 action",[1076,1627,1628,1633,1638,1641],{},[1094,1629,1630],{},[981,1631,1632],{},"storage\u002Fflowdsl",[1094,1634,1635],{},[981,1636,1637],{},"storage-flowdsl",[1094,1639,1640],{},"8",[1094,1642,1643],{},"4 upload\u002Fdownload\u002Fdelete\u002Fpresign + 4 S3 list \u002F head \u002F copy \u002F delete-many",[1076,1645,1646,1651,1656,1658],{},[1094,1647,1648],{},[981,1649,1650],{},"notifications\u002Fflowdsl",[1094,1652,1653],{},[981,1654,1655],{},"notifications-flowdsl",[1094,1657,1622],{},[1094,1659,1660],{},"2 action, 1 source",[1076,1662,1663,1668,1673,1676],{},[1094,1664,1665],{},[981,1666,1667],{},"verification\u002Fflowdsl",[1094,1669,1670],{},[981,1671,1672],{},"verification-flowdsl",[1094,1674,1675],{},"2",[1094,1677,1678],{},"1 action, 1 router (Valid\u002FInvalid)",[1076,1680,1681,1686,1691,1693],{},[1094,1682,1683],{},[981,1684,1685],{},"links\u002Fflowdsl",[1094,1687,1688],{},[981,1689,1690],{},"links-flowdsl",[1094,1692,1622],{},[1094,1694,1695],{},"2 action, 1 transform (with NotFound)",[1076,1697,1698,1703,1708,1710],{},[1094,1699,1700],{},[981,1701,1702],{},"search\u002Fflowdsl",[1094,1704,1705],{},[981,1706,1707],{},"search-flowdsl",[1094,1709,1675],{},[1094,1711,1712,1713,1716,1717,1720],{},"2 action (",[981,1714,1715],{},"search-upsert",", ",[981,1718,1719],{},"search-query",")",[978,1722,1723,1724,1004],{},"For the full node catalog — including core, events, redisops, mongoops, and every infrastructure module — browse the ",[995,1725,1726],{"href":313},[986,1727,318],{},[1729,1730],"hr",{},[1006,1732,1099],{"id":1099},[978,1734,1735],{},[986,1736,1737],{},"Distributed cron job scheduler with MongoDB persistence and Redis-based leader election.",[978,1739,1740],{},"Only the elected leader runs jobs at any given time — all replicas coordinate automatically.",[978,1742,1743,1744,1747,1748,1751,1752,1755,1756,1760,1761,1004],{},"A schedule fires an ",[986,1745,1746],{},"event"," — ",[981,1749,1750],{},"event_type"," + ",[981,1753,1754],{},"event_action"," on a cron\nexpression or once at a fixed time. The event goes onto the bus, where any\nconsumer or FlowDSL flow can react to it. The scheduler is a timer, not an\nexecutor: it decides ",[1757,1758,1759],"em",{},"when",", the event bus decides ",[1757,1762,1763],{},"what happens next",[1765,1766,1768],"h3",{"id":1767},"environment-variables","Environment variables",[1070,1770,1771,1784],{},[1073,1772,1773],{},[1076,1774,1775,1778,1781],{},[1079,1776,1777],{},"Variable",[1079,1779,1780],{},"Default",[1079,1782,1783],{},"Description",[1089,1785,1786,1801,1816,1831,1850,1864],{},[1076,1787,1788,1793,1798],{},[1094,1789,1790],{},[981,1791,1792],{},"SCHEDULER_COLLECTION",[1094,1794,1795],{},[981,1796,1797],{},"scheduler_schedules",[1094,1799,1800],{},"MongoDB collection for schedule definitions",[1076,1802,1803,1808,1813],{},[1094,1804,1805],{},[981,1806,1807],{},"SCHEDULER_LOG_COLLECTION",[1094,1809,1810],{},[981,1811,1812],{},"scheduler_logs",[1094,1814,1815],{},"MongoDB collection for execution logs",[1076,1817,1818,1823,1828],{},[1094,1819,1820],{},[981,1821,1822],{},"SCHEDULER_POLL_INTERVAL_SECONDS",[1094,1824,1825],{},[981,1826,1827],{},"10",[1094,1829,1830],{},"How often to check for due schedules",[1076,1832,1833,1838,1843],{},[1094,1834,1835],{},[981,1836,1837],{},"SCHEDULER_LOG_TTL_DAYS",[1094,1839,1840],{},[981,1841,1842],{},"30",[1094,1844,1845,1846,1849],{},"How long execution history is kept. ",[981,1847,1848],{},"0"," keeps it forever",[1076,1851,1852,1857,1861],{},[1094,1853,1854],{},[981,1855,1856],{},"SCHEDULER_LOCK_TTL_SECONDS",[1094,1858,1859],{},[981,1860,1842],{},[1094,1862,1863],{},"Redis leader-election lock TTL",[1076,1865,1866,1871,1876],{},[1094,1867,1868],{},[981,1869,1870],{},"SCHEDULER_LOCK_KEY",[1094,1872,1873],{},[981,1874,1875],{},"redelay:\u003Capp-name>:scheduler:leader",[1094,1877,1878,1879],{},"Redis key for the leader lock. Namespaced by ",[981,1880,1881],{},"APP_NAME",[1765,1883,1885],{"id":1884},"leader-election-read-this-before-sharing-a-redis","Leader election — read this before sharing a Redis",[978,1887,1888,1889],{},"Every replica polls; the Redis lock decides which one dispatches. Three things\nabout that lock exist because each was got wrong once, and the failure they\nproduce is the same every time: ",[986,1890,1891,1892,1895],{},"schedules fire on time, every execution logs\n",[981,1893,1894],{},"success",", and nothing is delivered.",[978,1897,1898,1901,1902,1905,1906,1909,1910,1913],{},[986,1899,1900],{},"The lock key is namespaced per app."," It used to be the constant\n",[981,1903,1904],{},"redelay:scheduler:leader"," in every deployment, so any process reaching the same\nRedis competed for one lock — a second app, a staging environment pointed at the\nsame instance, or a developer's ",[981,1907,1908],{},"go run"," left over from yesterday. Whichever won\ndispatched ",[1757,1911,1912],{},"everyone's"," schedules, into whatever transport it happened to have.\nA 27-hour-old local build holding no Kafka connection at all once owned a\ndeployment's cron for hours this way.",[978,1915,1916,1426,1919,1922,1923,1926],{},[986,1917,1918],{},"The lock records its holder",[981,1920,1921],{},"host\u002Fpid-N","), not ",[981,1924,1925],{},"1",". A lock that says\nnothing about its owner cannot answer \"which process is running my cron\", and\nanswering it otherwise means stopping containers one at a time.",[978,1928,1929,1932,1933,1936],{},[986,1930,1931],{},"The lock is only renewed while still owned."," A blind ",[981,1934,1935],{},"EXPIRE"," extends\nwhatever is there, so a replica that lost the lock would keep refreshing the new\nleader's claim — two dispatchers, and a lock that never changes hands again.",[1765,1938,1940],{"id":1939},"freezing-schedules-before-a-migration-during-an-incident","Freezing schedules (before a migration, during an incident)",[978,1942,1943,1946,1947,1950,1951,1954],{},[981,1944,1945],{},"POST \u002Fschedules\u002F{id}\u002Fpause"," and ",[981,1948,1949],{},"\u002Fresume"," set the state ",[986,1952,1953],{},"explicitly"," and are\nidempotent — 200 when it is already there. Use these to script a freeze:",[1011,1956,1958],{"className":1013,"code":1957,"language":1015,"meta":1016,"style":1016},"# Pause everything. Safe to re-run.\nfor id in $(curl -s -H \"Authorization: Bearer $TOKEN\" \\\n      \"$API\u002Fapi\u002Fv1\u002Fschedules\u002F?limit=200\" | jq -r '.items[].id'); do\n  curl -s -X POST -H \"Authorization: Bearer $TOKEN\" \\\n      \"$API\u002Fapi\u002Fv1\u002Fschedules\u002F$id\u002Fpause\" > \u002Fdev\u002Fnull\ndone\n",[981,1959,1960,1966,2007,2044,2069,2092],{"__ignoreMap":1016},[1020,1961,1962],{"class":1022,"line":10},[1020,1963,1965],{"class":1964},"sHwdD","# Pause everything. Safe to re-run.\n",[1020,1967,1968,1972,1976,1979,1983,1986,1989,1992,1995,1998,2001,2004],{"class":1022,"line":16},[1020,1969,1971],{"class":1970},"s7zQu","for",[1020,1973,1975],{"class":1974},"sTEyZ"," id ",[1020,1977,1978],{"class":1970},"in",[1020,1980,1982],{"class":1981},"sMK4o"," $(",[1020,1984,1985],{"class":1025},"curl",[1020,1987,1988],{"class":1029}," -s",[1020,1990,1991],{"class":1029}," -H",[1020,1993,1994],{"class":1981}," \"",[1020,1996,1997],{"class":1029},"Authorization: Bearer ",[1020,1999,2000],{"class":1974},"$TOKEN",[1020,2002,2003],{"class":1981},"\"",[1020,2005,2006],{"class":1974}," \\\n",[1020,2008,2009,2012,2015,2018,2020,2023,2026,2029,2032,2035,2038,2041],{"class":1022,"line":22},[1020,2010,2011],{"class":1981},"      \"",[1020,2013,2014],{"class":1974},"$API",[1020,2016,2017],{"class":1029},"\u002Fapi\u002Fv1\u002Fschedules\u002F?limit=200",[1020,2019,2003],{"class":1981},[1020,2021,2022],{"class":1981}," |",[1020,2024,2025],{"class":1025}," jq",[1020,2027,2028],{"class":1029}," -r",[1020,2030,2031],{"class":1981}," '",[1020,2033,2034],{"class":1029},".items[].id",[1020,2036,2037],{"class":1981},"'",[1020,2039,2040],{"class":1981},");",[1020,2042,2043],{"class":1970}," do\n",[1020,2045,2046,2049,2051,2054,2057,2059,2061,2063,2065,2067],{"class":1022,"line":51},[1020,2047,2048],{"class":1025},"  curl",[1020,2050,1988],{"class":1029},[1020,2052,2053],{"class":1029}," -X",[1020,2055,2056],{"class":1029}," POST",[1020,2058,1991],{"class":1029},[1020,2060,1994],{"class":1981},[1020,2062,1997],{"class":1029},[1020,2064,2000],{"class":1974},[1020,2066,2003],{"class":1981},[1020,2068,2006],{"class":1974},[1020,2070,2071,2073,2075,2078,2081,2084,2086,2089],{"class":1022,"line":57},[1020,2072,2011],{"class":1981},[1020,2074,2014],{"class":1974},[1020,2076,2077],{"class":1029},"\u002Fapi\u002Fv1\u002Fschedules\u002F",[1020,2079,2080],{"class":1974},"$id",[1020,2082,2083],{"class":1029},"\u002Fpause",[1020,2085,2003],{"class":1981},[1020,2087,2088],{"class":1981}," >",[1020,2090,2091],{"class":1029}," \u002Fdev\u002Fnull\n",[1020,2093,2094],{"class":1022,"line":102},[1020,2095,2096],{"class":1970},"done\n",[978,2098,2099,2102,2103,2106],{},[981,2100,2101],{},"\u002Ftoggle"," exists too but ",[986,2104,2105],{},"flips",", which is right for a switch in a UI and\nwrong for a script: re-running a toggle-based freeze turns everything back on,\nand two operators running it at once can leave the fleet in either state.",[978,2108,2109,2112,2113,2116],{},[981,2110,2111],{},"resume"," deliberately leaves a ",[1757,2114,2115],{},"completed"," one-time schedule completed —\nre-arming it would fire it a second time for reasons nobody chose.",[978,2118,2119,2120,2123,2124,2127],{},"An update leaves ",[981,2121,2122],{},"status"," alone unless ",[981,2125,2126],{},"enabled"," is sent, so editing a cron\nexpression or a description during a freeze does not lift it.",[1765,2129,2131],{"id":2130},"observability","Observability",[978,2133,2134,2137,2138,2140,2141,2144],{},[981,2135,2136],{},"GET \u002Fhealth"," includes a ",[981,2139,1099],{}," check. It is deliberately ",[986,2142,2143],{},"not"," unhealthy\nfor a follower — that is the normal state for every replica but one — but it\ndoes fail when the lock is held by an owner that does not look like a peer,\nwhich is the stale-build case above and is invisible everywhere else.",[978,2146,2147,2148,1946,2151,2154,2155,2157,2158,2160,2161,2163,2164,2167],{},"Each execution log row records ",[981,2149,2150],{},"host",[981,2152,2153],{},"topic",". ",[981,2156,2153],{}," matters because a\nschedule whose ",[981,2159,1750],{}," resolves to nothing still logs ",[981,2162,1894],{},"; without it\nthere is no way to tell a real publish from a no-op. Every dispatch is also\nlogged at INFO ",[986,2165,2166],{},"on success as well as failure"," — a scheduler whose whole job\nis to publish used to be silent when it worked, so a deployment where every run\npublished into a void looked exactly like a healthy one.",[978,2169,2170],{},"If scheduled events stop arriving, check in this order:",[2172,2173,2174,2183,2189,2198],"ol",{},[2175,2176,2177,2179,2180,2182],"li",{},[981,2178,2136],{}," → the ",[981,2181,1099],{}," check names a foreign lock holder.",[2175,2184,2185,2188],{},[981,2186,2187],{},"redis-cli get redelay:\u003Capp>:scheduler:leader"," → who thinks it is leader.",[2175,2190,2191,2192,2194,2195,2197],{},"The ",[981,2193,2150],{}," field on recent ",[981,2196,1812],{}," rows → who actually dispatched.",[2175,2199,2200,2201,2204,2205,2207],{},"A ",[981,2202,2203],{},"duration_ms"," of ",[981,2206,1848],{}," on every row is a strong hint that publishing is a\nno-op: a real broker round-trip is not free.",[1765,2209,2211,2212,2215],{"id":2210},"http-surface-scheduleradmin-admin-api-only","HTTP surface — ",[981,2213,2214],{},"scheduler\u002Fadmin"," (admin-api only)",[978,2217,2218,2219,1716,2222,2225,2226,2229,2230,2232,2233,2236,2237,2240],{},"The management API is a ",[986,2220,2221],{},"separate submodule",[981,2223,2224],{},"go-modules\u002Fscheduler\u002Fadmin",",\nblank-imported from the ",[986,2227,2228],{},"admin-api binary only",". The core ",[981,2231,1099],{}," module\nruns the engine and mounts nothing; importing it on the public api gives you\nreliable schedule ",[1757,2234,2235],{},"firing"," without exposing schedule ",[1757,2238,2239],{},"management"," there.",[1011,2242,2244],{"className":1036,"code":2243,"language":1026,"meta":1016,"style":1016},"\u002F\u002F cmd\u002Fadmin-api only\nimport _ \"github.com\u002Fredelay\u002Fgo-modules\u002Fscheduler\u002Fadmin\"\n",[981,2245,2246,2251],{"__ignoreMap":1016},[1020,2247,2248],{"class":1022,"line":10},[1020,2249,2250],{},"\u002F\u002F cmd\u002Fadmin-api only\n",[1020,2252,2253],{"class":1022,"line":16},[1020,2254,2255],{},"import _ \"github.com\u002Fredelay\u002Fgo-modules\u002Fscheduler\u002Fadmin\"\n",[978,2257,2258,2259,2262,2263,2266,2267,2270],{},"The routes sit at ",[981,2260,2261],{},"\u002Fschedules\u002F"," (matching the API contract, not under the admin\nprefix) and are gated on ",[981,2264,2265],{},"RequirePermission(\"admin:access\")",". A schedule\npublishes an arbitrary event as an arbitrary actor on a timer, so managing them\nis an admin capability — the permission check ",[1757,2268,2269],{},"and"," the admin-api-only import\nkeep the surface off the public api.",[1070,2272,2273,2285],{},[1073,2274,2275],{},[1076,2276,2277,2280,2283],{},[1079,2278,2279],{},"Method",[1079,2281,2282],{},"Path",[1079,2284,1087],{},[1089,2286,2287,2308,2320,2332,2344,2356,2368,2380],{},[1076,2288,2289,2292,2296],{},[1094,2290,2291],{},"GET",[1094,2293,2294],{},[981,2295,2261],{},[1094,2297,2298,2299,1716,2301,1716,2304,1716,2306,1720],{},"List schedules (filter by ",[981,2300,2126],{},[981,2302,2303],{},"tag",[981,2305,1750],{},[981,2307,1754],{},[1076,2309,2310,2313,2317],{},[1094,2311,2312],{},"POST",[1094,2314,2315],{},[981,2316,2261],{},[1094,2318,2319],{},"Create a schedule",[1076,2321,2322,2324,2329],{},[1094,2323,2291],{},[1094,2325,2326],{},[981,2327,2328],{},"\u002Fschedules\u002F{schedule_id}",[1094,2330,2331],{},"Get a schedule",[1076,2333,2334,2337,2341],{},[1094,2335,2336],{},"PUT",[1094,2338,2339],{},[981,2340,2328],{},[1094,2342,2343],{},"Update (partial; changing the timing re-arms the next run)",[1076,2345,2346,2349,2353],{},[1094,2347,2348],{},"DELETE",[1094,2350,2351],{},[981,2352,2328],{},[1094,2354,2355],{},"Delete the schedule and its execution history",[1076,2357,2358,2360,2365],{},[1094,2359,2312],{},[1094,2361,2362],{},[981,2363,2364],{},"\u002Fschedules\u002F{schedule_id}\u002Fexecute",[1094,2366,2367],{},"Fire now, without shifting the regular timing",[1076,2369,2370,2372,2377],{},[1094,2371,2291],{},[1094,2373,2374],{},[981,2375,2376],{},"\u002Fschedules\u002F{schedule_id}\u002Fexecutions",[1094,2378,2379],{},"List execution log entries (newest first)",[1076,2381,2382,2384,2389],{},[1094,2383,2312],{},[1094,2385,2386],{},[981,2387,2388],{},"\u002Fschedules\u002F{schedule_id}\u002Ftoggle",[1094,2390,2391],{},"Enable \u002F pause",[978,2393,2394,2395,2398,2399,2402,2403,2406,2407,1426,2410,2413,2414,2417,2418,2420,2421,2424,2425,2428],{},"A schedule is either ",[986,2396,2397],{},"recurring"," (a 5-field ",[981,2400,2401],{},"cron_expression",", read in its own\n",[981,2404,2405],{},"timezone",") or ",[986,2408,2409],{},"one-time",[981,2411,2412],{},"one_time: true"," + an ",[981,2415,2416],{},"execution_time","); a one-time\nschedule moves to a terminal ",[981,2419,2115],{}," state after it fires. A failed publish\nretries up to ",[981,2422,2423],{},"max_retries"," with ",[981,2426,2427],{},"retry_delay"," seconds between attempts before\nwaiting for the next occurrence. Six-field cron expressions are rejected — the\nparser does not enable seconds, so a sixth field would silently shift every\nposition.",[1011,2430,2432],{"className":1013,"code":2431,"language":1015,"meta":1016,"style":1016},"curl -X POST \u002Fapi\u002Fv1\u002Fschedules\u002F -H 'Authorization: Bearer \u003Cadmin>' -d '{\n  \"name\": \"nightly-report\",\n  \"event_type\": \"report\", \"event_action\": \"generate\",\n  \"cron_expression\": \"0 3 * * *\", \"timezone\": \"Europe\u002FWarsaw\",\n  \"event_payload\": {\"kind\": \"daily\"}\n}'\n",[981,2433,2434,2462,2467,2472,2477,2482],{"__ignoreMap":1016},[1020,2435,2436,2438,2440,2442,2445,2447,2449,2452,2454,2457,2459],{"class":1022,"line":10},[1020,2437,1985],{"class":1025},[1020,2439,2053],{"class":1029},[1020,2441,2056],{"class":1029},[1020,2443,2444],{"class":1029}," \u002Fapi\u002Fv1\u002Fschedules\u002F",[1020,2446,1991],{"class":1029},[1020,2448,2031],{"class":1981},[1020,2450,2451],{"class":1029},"Authorization: Bearer \u003Cadmin>",[1020,2453,2037],{"class":1981},[1020,2455,2456],{"class":1029}," -d",[1020,2458,2031],{"class":1981},[1020,2460,2461],{"class":1029},"{\n",[1020,2463,2464],{"class":1022,"line":16},[1020,2465,2466],{"class":1029},"  \"name\": \"nightly-report\",\n",[1020,2468,2469],{"class":1022,"line":22},[1020,2470,2471],{"class":1029},"  \"event_type\": \"report\", \"event_action\": \"generate\",\n",[1020,2473,2474],{"class":1022,"line":51},[1020,2475,2476],{"class":1029},"  \"cron_expression\": \"0 3 * * *\", \"timezone\": \"Europe\u002FWarsaw\",\n",[1020,2478,2479],{"class":1022,"line":57},[1020,2480,2481],{"class":1029},"  \"event_payload\": {\"kind\": \"daily\"}\n",[1020,2483,2484,2487],{"class":1022,"line":102},[1020,2485,2486],{"class":1029},"}",[1020,2488,2489],{"class":1981},"'\n",[1765,2491,2493],{"id":2492},"flowdsl-alternative","FlowDSL alternative",[978,2495,2496],{},"The same effect is available declaratively — a flow with a cron or interval\nsource node, resolved natively by the flow engine:",[1011,2498,2502],{"className":2499,"code":2500,"language":2501,"meta":1016,"style":1016},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","nodes:\n  - id: nightly\n    nodeType: redelay\u002Fscheduler-cron-trigger\n    settings:\n      cron: \"0 2 * * *\"\n  - id: cleanup\n    nodeType: mongoops\u002Fdelete\n","yaml",[981,2503,2504,2513,2527,2537,2544,2559,2570],{"__ignoreMap":1016},[1020,2505,2506,2510],{"class":1022,"line":10},[1020,2507,2509],{"class":2508},"swJcz","nodes",[1020,2511,2512],{"class":1981},":\n",[1020,2514,2515,2518,2521,2524],{"class":1022,"line":16},[1020,2516,2517],{"class":1981},"  -",[1020,2519,2520],{"class":2508}," id",[1020,2522,2523],{"class":1981},":",[1020,2525,2526],{"class":1029}," nightly\n",[1020,2528,2529,2532,2534],{"class":1022,"line":22},[1020,2530,2531],{"class":2508},"    nodeType",[1020,2533,2523],{"class":1981},[1020,2535,2536],{"class":1029}," redelay\u002Fscheduler-cron-trigger\n",[1020,2538,2539,2542],{"class":1022,"line":51},[1020,2540,2541],{"class":2508},"    settings",[1020,2543,2512],{"class":1981},[1020,2545,2546,2549,2551,2553,2556],{"class":1022,"line":57},[1020,2547,2548],{"class":2508},"      cron",[1020,2550,2523],{"class":1981},[1020,2552,1994],{"class":1981},[1020,2554,2555],{"class":1029},"0 2 * * *",[1020,2557,2558],{"class":1981},"\"\n",[1020,2560,2561,2563,2565,2567],{"class":1022,"line":102},[1020,2562,2517],{"class":1981},[1020,2564,2520],{"class":2508},[1020,2566,2523],{"class":1981},[1020,2568,2569],{"class":1029}," cleanup\n",[1020,2571,2572,2574,2576],{"class":1022,"line":108},[1020,2573,2531],{"class":2508},[1020,2575,2523],{"class":1981},[1020,2577,2578],{"class":1029}," mongoops\u002Fdelete\n",[978,2580,2581,1426,2584,2587,2588,2591],{},[981,2582,2583],{},"SchedulesProvider",[981,2585,2586],{},"Schedules() []*ir.Schedule",") is ",[986,2589,2590],{},"metadata only"," — it\npopulates the module browser's IR and is not wired to the scheduler service.",[1729,2593],{},[1006,2595,1115],{"id":1115},[978,2597,2598],{},[986,2599,2600],{},"Key-value settings store backed by MongoDB with in-memory caching and cluster-wide invalidation.",[978,2602,2603,2604,2607],{},"Implements ",[981,2605,2606],{},"modules.SettingsReader"," — other modules resolve settings via dependency injection with automatic 3-layer precedence: DB override → environment variable → YAML default. Updates propagate to all workers instantly via the event bus without a restart.",[1765,2609,2611],{"id":2610},"data-model","Data model",[1011,2613,2615],{"className":1036,"code":2614,"language":1026,"meta":1016,"style":1016},"type Setting struct {\n    ModuleID  string    \u002F\u002F e.g. \"ai-llm\"\n    Key       string    \u002F\u002F e.g. \"openai_api_key\"\n    Value     any       \u002F\u002F JSON-serializable\n    UpdatedAt time.Time\n}\n",[981,2616,2617,2622,2627,2632,2637,2642],{"__ignoreMap":1016},[1020,2618,2619],{"class":1022,"line":10},[1020,2620,2621],{},"type Setting struct {\n",[1020,2623,2624],{"class":1022,"line":16},[1020,2625,2626],{},"    ModuleID  string    \u002F\u002F e.g. \"ai-llm\"\n",[1020,2628,2629],{"class":1022,"line":22},[1020,2630,2631],{},"    Key       string    \u002F\u002F e.g. \"openai_api_key\"\n",[1020,2633,2634],{"class":1022,"line":51},[1020,2635,2636],{},"    Value     any       \u002F\u002F JSON-serializable\n",[1020,2638,2639],{"class":1022,"line":57},[1020,2640,2641],{},"    UpdatedAt time.Time\n",[1020,2643,2644],{"class":1022,"line":102},[1020,2645,2646],{},"}\n",[978,2648,2649,2650,2653,2654,1004],{},"Unique index on ",[981,2651,2652],{},"(module_id, key)",". Default collection: ",[981,2655,2656],{},"_settings",[1765,2658,2660],{"id":2659},"_3-layer-resolution-precedence","3-layer resolution precedence",[1070,2662,2663,2676],{},[1073,2664,2665],{},[1076,2666,2667,2670,2673],{},[1079,2668,2669],{},"Priority",[1079,2671,2672],{},"Source",[1079,2674,2675],{},"Notes",[1089,2677,2678,2689,2706],{},[1076,2679,2680,2683,2686],{},[1094,2681,2682],{},"1 (highest)",[1094,2684,2685],{},"MongoDB (admin-saved)",[1094,2687,2688],{},"Written via admin API",[1076,2690,2691,2693,2696],{},[1094,2692,1675],{},[1094,2694,2695],{},"Environment variable",[1094,2697,2698,2699,2702,2703],{},"Explicit ",[981,2700,2701],{},"EnvVar"," field or implicit ",[981,2704,2705],{},"{MODULE}_{KEY}",[1076,2707,2708,2710,2713],{},[1094,2709,1622],{},[1094,2711,2712],{},"YAML default",[1094,2714,2715,2716],{},"Declared in module's ",[981,2717,2718],{},"SettingsDefinition",[978,2720,2721,2724,2725,2728,2729,2732,2733,2736],{},[986,2722,2723],{},"Implicit env var naming:"," module ",[981,2726,2727],{},"ai-llm"," + key ",[981,2730,2731],{},"openai_api_key"," → ",[981,2734,2735],{},"AI_LLM_OPENAI_API_KEY"," (hyphens → underscores, uppercased).",[1765,2738,2740],{"id":2739},"caching-and-propagation","Caching and propagation",[978,2742,2743,2744,2747],{},"Settings are cached in memory per worker behind a ",[981,2745,2746],{},"sync.RWMutex",". The cache is designed for correctness across three deployment shapes:",[2172,2749,2750,2760,2778],{},[2175,2751,2752,2755,2756,2759],{},[986,2753,2754],{},"Single binary"," (one cmd\u002Fapi with admin imports) — local ",[981,2757,2758],{},"Service.Set"," invalidates the local cache; events are unnecessary.",[2175,2761,2762,2765,2766,2769,2770,2773,2774,2777],{},[986,2763,2764],{},"Multi-binary local dev"," (cmd\u002Fapi + cmd\u002Fadmin-api with ",[981,2767,2768],{},"TRANSPORT=memory",") — each binary runs an isolated in-process event bus, so a ",[981,2771,2772],{},"settings.updated"," event published by admin-api ",[986,2775,2776],{},"never reaches"," cmd\u002Fapi. The TTL (below) is the only invalidation mechanism in this mode.",[2175,2779,2780,2783,2784,2787,2788,2787,2791,2794,2795,2798],{},[986,2781,2782],{},"Production cluster"," (N replicas with ",[981,2785,2786],{},"TRANSPORT=kafka","\u002F",[981,2789,2790],{},"nats",[981,2792,2793],{},"redis",") — every replica subscribes with a unique ",[981,2796,2797],{},"settings-invalidator-{hostname}-{8-char-uuid}"," GroupID, so events fan out to all replicas in milliseconds. The TTL acts as a safety net for missed events (consumer restart mid-event, network blip, hostname collision).",[2800,2801,2803],"h4",{"id":2802},"cache-rules","Cache rules",[1070,2805,2806,2819],{},[1073,2807,2808],{},[1076,2809,2810,2813,2816],{},[1079,2811,2812],{},"Resolution source",[1079,2814,2815],{},"Cached?",[1079,2817,2818],{},"Invalidated by",[1089,2820,2821,2840,2853],{},[1076,2822,2823,2829,2832],{},[1094,2824,2825,2828],{},[981,2826,2827],{},"db"," — admin-edited row in MongoDB",[1094,2830,2831],{},"Yes, with TTL",[1094,2833,2834,2835,1716,2837,2839],{},"local ",[981,2836,2758],{},[981,2838,2772],{}," event, TTL expiry",[1076,2841,2842,2848,2850],{},[1094,2843,2844,2847],{},[981,2845,2846],{},"env"," — environment variable",[1094,2849,2831],{},[1094,2851,2852],{},"TTL expiry (env doesn't change at runtime)",[1076,2854,2855,2861,2866],{},[1094,2856,2857,2860],{},[981,2858,2859],{},"default"," — YAML-declared default",[1094,2862,2863],{},[986,2864,2865],{},"Never cached",[1094,2867,2868],{},"n\u002Fa — re-resolved on every miss",[978,2870,2871,2874],{},[986,2872,2873],{},"Why defaults are not cached:"," a default returned before any DB row exists would shadow a future admin write whose invalidation event a peer binary failed to receive. Skipping the cache for defaults guarantees the next read after a peer save sees the new DB value immediately.",[2800,2876,2878],{"id":2877},"save-flow","Save flow",[2172,2880,2881,2884,2887,2892,2895],{},[2175,2882,2883],{},"The value is written to MongoDB.",[2175,2885,2886],{},"The local cache entry is invalidated on the writing worker.",[2175,2888,2200,2889,2891],{},[981,2890,2772],{}," event is published to the event bus.",[2175,2893,2894],{},"Every worker subscribed with a unique GroupID receives the event (fan-out, not round-robin) and invalidates its local cache entry.",[2175,2896,2897],{},"On next read, the cache miss triggers a MongoDB re-query.",[2800,2899,2901],{"id":2900},"cache-ttl","Cache TTL",[1070,2903,2904,2914],{},[1073,2905,2906],{},[1076,2907,2908,2910,2912],{},[1079,2909,1777],{},[1079,2911,1780],{},[1079,2913,2675],{},[1089,2915,2916],{},[1076,2917,2918,2923,2927],{},[1094,2919,2920],{},[981,2921,2922],{},"SETTINGS_CACHE_TTL_SECONDS",[1094,2924,2925],{},[981,2926,1842],{},[1094,2928,2929,2930,2932],{},"Maximum staleness for a DB-sourced cache entry. Set to ",[981,2931,1848],{}," to disable expiry — only safe in single-binary deployments OR a real-transport cluster where every replica has a unique hostname.",[978,2934,2935],{},[986,2936,2937],{},"Tuning guidance:",[2939,2940,2941,2948,2957],"ul",{},[2175,2942,2943,2944,2947],{},"Single-binary dev: ",[981,2945,2946],{},"SETTINGS_CACHE_TTL_SECONDS=0"," is fine — local invalidation is authoritative.",[2175,2949,2950,2951,2953,2954,2956],{},"Multi-binary dev (",[981,2952,2768],{},", separate cmd\u002Fapi + cmd\u002Fadmin-api): leave at default ",[981,2955,1842],{},". Admin saves become visible to the public binary within 30 seconds even though no event crosses binaries.",[2175,2958,2959,2960,2962,2963,2966],{},"Production with kafka\u002Fnats\u002Fredis: leave at default ",[981,2961,1842],{}," (or raise to ",[981,2964,2965],{},"300"," for less DB load). Events handle ~ms invalidation; the TTL is just a backstop for missed events.",[1765,2968,2970,2971,1946,2974,2977],{"id":2969},"access-control-public-and-sensitive-flags","Access control: ",[981,2972,2973],{},"public",[981,2975,2976],{},"sensitive"," flags",[978,2979,2980,2981,2984,2985,2988,2989,2992],{},"Settings default to ",[986,2982,2983],{},"admin-only",". The public API exposes a setting only when its declared schema field opts in with ",[981,2986,2987],{},"public: true",". Sensitive secrets opt in with ",[981,2990,2991],{},"sensitive: true"," and are masked on admin reads.",[1070,2994,2995,3014],{},[1073,2996,2997],{},[1076,2998,2999,3002,3008],{},[1079,3000,3001],{},"Field flag",[1079,3003,3004,3005,1720],{},"Public API (",[981,3006,3007],{},"\u002Fsettings\u002F...",[1079,3009,3010,3011,1720],{},"Admin API (",[981,3012,3013],{},"\u002Fadmin\u002Fsettings\u002F...",[1089,3015,3016,3027,3038,3052],{},[1076,3017,3018,3021,3024],{},[1094,3019,3020],{},"(none)",[1094,3022,3023],{},"404",[1094,3025,3026],{},"raw value",[1076,3028,3029,3033,3036],{},[1094,3030,3031],{},[981,3032,2987],{},[1094,3034,3035],{},"resolved value (DB > ENV > default)",[1094,3037,3026],{},[1076,3039,3040,3044,3046],{},[1094,3041,3042],{},[981,3043,2991],{},[1094,3045,3023],{},[1094,3047,3048,3049],{},"masked sentinel ",[981,3050,3051],{},"••••••••",[1076,3053,3054,3061,3070],{},[1094,3055,3056,3058,3059],{},[981,3057,2987],{}," AND ",[981,3060,2991],{},[1094,3062,3063,3066,3067,1720],{},[986,3064,3065],{},"rejected at startup"," by modval (",[981,3068,3069],{},"MV054",[1094,3071,3072],{},"—",[978,3074,3075,3076,3079,3080,3082],{},"Orphan DB rows (rows whose ",[981,3077,3078],{},"(module, key)"," is not declared in any module's ",[981,3081,2718],{},") are invisible on the public API and visible verbatim on the admin API.",[978,3084,3085,3088,3089,3091,3092,3094],{},[986,3086,3087],{},"Mask passthrough:"," when an admin write submits the ",[981,3090,3051],{}," sentinel as the value for a ",[981,3093,2991],{}," field, the existing stored value is preserved — admins can re-save a form without retyping every secret. Submitting any other string overwrites normally. Non-sensitive fields treat the sentinel as a literal string.",[978,3096,3097],{},"Example schema:",[1011,3099,3101],{"className":2499,"code":3100,"language":2501,"meta":1016,"style":1016},"settings:\n  groups:\n    - id: ai-llm.openai\n      label: OpenAI\n      settings:\n        - key: openai_api_key\n          label: API key\n          type: string\n          env_var: OPENAI_API_KEY\n          sensitive: true     # masked on admin reads, never readable on public API\n        - key: openai_default_model\n          label: Default model\n          type: string\n          public: true        # readable by \u002Fsettings\u002Fai-llm\u002Fopenai_default_model\n",[981,3102,3103,3109,3116,3128,3138,3145,3158,3168,3178,3188,3202,3213,3222,3230],{"__ignoreMap":1016},[1020,3104,3105,3107],{"class":1022,"line":10},[1020,3106,1115],{"class":2508},[1020,3108,2512],{"class":1981},[1020,3110,3111,3114],{"class":1022,"line":16},[1020,3112,3113],{"class":2508},"  groups",[1020,3115,2512],{"class":1981},[1020,3117,3118,3121,3123,3125],{"class":1022,"line":22},[1020,3119,3120],{"class":1981},"    -",[1020,3122,2520],{"class":2508},[1020,3124,2523],{"class":1981},[1020,3126,3127],{"class":1029}," ai-llm.openai\n",[1020,3129,3130,3133,3135],{"class":1022,"line":51},[1020,3131,3132],{"class":2508},"      label",[1020,3134,2523],{"class":1981},[1020,3136,3137],{"class":1029}," OpenAI\n",[1020,3139,3140,3143],{"class":1022,"line":57},[1020,3141,3142],{"class":2508},"      settings",[1020,3144,2512],{"class":1981},[1020,3146,3147,3150,3153,3155],{"class":1022,"line":102},[1020,3148,3149],{"class":1981},"        -",[1020,3151,3152],{"class":2508}," key",[1020,3154,2523],{"class":1981},[1020,3156,3157],{"class":1029}," openai_api_key\n",[1020,3159,3160,3163,3165],{"class":1022,"line":108},[1020,3161,3162],{"class":2508},"          label",[1020,3164,2523],{"class":1981},[1020,3166,3167],{"class":1029}," API key\n",[1020,3169,3170,3173,3175],{"class":1022,"line":114},[1020,3171,3172],{"class":2508},"          type",[1020,3174,2523],{"class":1981},[1020,3176,3177],{"class":1029}," string\n",[1020,3179,3180,3183,3185],{"class":1022,"line":120},[1020,3181,3182],{"class":2508},"          env_var",[1020,3184,2523],{"class":1981},[1020,3186,3187],{"class":1029}," OPENAI_API_KEY\n",[1020,3189,3190,3193,3195,3199],{"class":1022,"line":181},[1020,3191,3192],{"class":2508},"          sensitive",[1020,3194,2523],{"class":1981},[1020,3196,3198],{"class":3197},"sfNiH"," true",[1020,3200,3201],{"class":1964},"     # masked on admin reads, never readable on public API\n",[1020,3203,3204,3206,3208,3210],{"class":1022,"line":186},[1020,3205,3149],{"class":1981},[1020,3207,3152],{"class":2508},[1020,3209,2523],{"class":1981},[1020,3211,3212],{"class":1029}," openai_default_model\n",[1020,3214,3215,3217,3219],{"class":1022,"line":191},[1020,3216,3162],{"class":2508},[1020,3218,2523],{"class":1981},[1020,3220,3221],{"class":1029}," Default model\n",[1020,3223,3224,3226,3228],{"class":1022,"line":197},[1020,3225,3172],{"class":2508},[1020,3227,2523],{"class":1981},[1020,3229,3177],{"class":1029},[1020,3231,3232,3235,3237,3239],{"class":1022,"line":203},[1020,3233,3234],{"class":2508},"          public",[1020,3236,2523],{"class":1981},[1020,3238,3198],{"class":3197},[1020,3240,3241],{"class":1964},"        # readable by \u002Fsettings\u002Fai-llm\u002Fopenai_default_model\n",[1765,3243,3245],{"id":3244},"read-only-public-routes-core-module","Read-only public routes (core module)",[978,3247,3248,3249,3058,3251,3254],{},"Unauthenticated. Only fields declared with ",[981,3250,2987],{},[981,3252,3253],{},"sensitive: false"," are returned.",[1070,3256,3257,3267],{},[1073,3258,3259],{},[1076,3260,3261,3263,3265],{},[1079,3262,2279],{},[1079,3264,2282],{},[1079,3266,1783],{},[1089,3268,3269,3285],{},[1076,3270,3271,3275,3280],{},[1094,3272,3273],{},[981,3274,2291],{},[1094,3276,3277],{},[981,3278,3279],{},"\u002Fsettings\u002F{module}\u002F{key}",[1094,3281,3282,3283,1720],{},"Get a public setting value (404 if not declared ",[981,3284,2987],{},[1076,3286,3287,3291,3296],{},[1094,3288,3289],{},[981,3290,2291],{},[1094,3292,3293],{},[981,3294,3295],{},"\u002Fsettings\u002F{module}",[1094,3297,3298,3299,1720],{},"List all public settings for a module (filtered to ",[981,3300,2987],{},[1765,3302,3304,3305,3308],{"id":3303},"admin-routes-settingsadmin-submodule","Admin routes (",[981,3306,3307],{},"settings\u002Fadmin"," submodule)",[978,3310,3311,3312,3315,3316,3318],{},"Require ",[981,3313,3314],{},"admin:access"," permission. Sensitive values are masked with ",[981,3317,3051],{}," in responses.",[1070,3320,3321,3331],{},[1073,3322,3323],{},[1076,3324,3325,3327,3329],{},[1079,3326,2279],{},[1079,3328,2282],{},[1079,3330,1783],{},[1089,3332,3333,3347,3364,3378,3392],{},[1076,3334,3335,3339,3344],{},[1094,3336,3337],{},[981,3338,2291],{},[1094,3340,3341],{},[981,3342,3343],{},"\u002Fadmin\u002Fsettings\u002Fschemas",[1094,3345,3346],{},"List settings schemas from all registered modules",[1076,3348,3349,3353,3358],{},[1094,3350,3351],{},[981,3352,2312],{},[1094,3354,3355],{},[981,3356,3357],{},"\u002Fadmin\u002Fsettings\u002Fget",[1094,3359,3360,3361,3363],{},"Bulk-get multiple settings by ",[981,3362,3078],{}," pairs (masks sensitive)",[1076,3365,3366,3370,3375],{},[1094,3367,3368],{},[981,3369,2336],{},[1094,3371,3372],{},[981,3373,3374],{},"\u002Fadmin\u002Fsettings\u002F{module}\u002F{key}",[1094,3376,3377],{},"Set or update a setting (mask passthrough)",[1076,3379,3380,3384,3389],{},[1094,3381,3382],{},[981,3383,2312],{},[1094,3385,3386],{},[981,3387,3388],{},"\u002Fadmin\u002Fsettings\u002Fsave",[1094,3390,3391],{},"Alternative POST endpoint for save (mask passthrough)",[1076,3393,3394,3398,3402],{},[1094,3395,3396],{},[981,3397,2348],{},[1094,3399,3400],{},[981,3401,3374],{},[1094,3403,3404],{},"Delete a setting (scoped to module, 204)",[1765,3406,3408],{"id":3407},"internal-service-to-service-routes","Internal (service-to-service) routes",[978,3410,3411,3412,3415,3416,3423],{},"Secret-gated, not user-authenticated: the callers are other services, which\nhave no user to act as. Gated on the ",[981,3413,3414],{},"x-api-secret"," header (constant-time\ncompare); ",[986,3417,3418,3419,3422],{},"disabled unless ",[981,3420,3421],{},"SETTINGS_INTERNAL_SECRET"," is set"," — an unset\nsecret refuses everything, so the internal API is opt-in.",[1070,3425,3426,3436],{},[1073,3427,3428],{},[1076,3429,3430,3432,3434],{},[1079,3431,2279],{},[1079,3433,2282],{},[1079,3435,1783],{},[1089,3437,3438,3455],{},[1076,3439,3440,3444,3449],{},[1094,3441,3442],{},[981,3443,2291],{},[1094,3445,3446],{},[981,3447,3448],{},"\u002Finternal\u002Fsettings\u002Fschemas",[1094,3450,3451,3452],{},"Every module's settings schema, as ",[981,3453,3454],{},"{settings, groups, subgroups}",[1076,3456,3457,3461,3466],{},[1094,3458,3459],{},[981,3460,2312],{},[1094,3462,3463],{},[981,3464,3465],{},"\u002Finternal\u002Fsettings\u002Frefresh-cache",[1094,3467,3468],{},"Drop this instance's settings cache",[978,3470,3471,3472,3475,3476,3479,3480,3483],{},"These are the service-to-service counterparts of the admin ",[981,3473,3474],{},"schemas"," \u002F\n",[981,3477,3478],{},"refresh-cache"," endpoints — same effect, different caller. ",[981,3481,3482],{},"subgroups"," is always\nempty: Redelay's settings IR has one level of grouping, and the key is present\nonly for wire compatibility with the legacy shape.",[1765,3485,3487],{"id":3486},"events-published","Events published",[1070,3489,3490,3503],{},[1073,3491,3492],{},[1076,3493,3494,3497,3500],{},[1079,3495,3496],{},"Topic",[1079,3498,3499],{},"Trigger",[1079,3501,3502],{},"Payload",[1089,3504,3505],{},[1076,3506,3507,3511,3514],{},[1094,3508,3509],{},[981,3510,2772],{},[1094,3512,3513],{},"Any save or delete",[1094,3515,3516],{},[981,3517,3518],{},"{ moduleId, key, value, deleted }",[1765,3520,1768],{"id":3521},"environment-variables-1",[1070,3523,3524,3534],{},[1073,3525,3526],{},[1076,3527,3528,3530,3532],{},[1079,3529,1777],{},[1079,3531,1780],{},[1079,3533,1783],{},[1089,3535,3536,3550,3569],{},[1076,3537,3538,3543,3547],{},[1094,3539,3540],{},[981,3541,3542],{},"SETTINGS_COLLECTION",[1094,3544,3545],{},[981,3546,2656],{},[1094,3548,3549],{},"MongoDB collection name",[1076,3551,3552,3556,3560],{},[1094,3553,3554],{},[981,3555,2922],{},[1094,3557,3558],{},[981,3559,1842],{},[1094,3561,3562,3563,3565,3566,1004],{},"Resolution-cache staleness bound for DB-sourced values; ",[981,3564,1848],{}," disables expiry. See ",[995,3567,2740],{"href":3568},"#caching-and-propagation",[1076,3570,3571,3575,3578],{},[1094,3572,3573],{},[981,3574,3421],{},[1094,3576,3577],{},"(unset)",[1094,3579,3580,3581,3584],{},"Shared secret for the ",[981,3582,3583],{},"\u002Finternal\u002Fsettings\u002F*"," service-to-service routes. Unset disables them.",[1765,3586,3588],{"id":3587},"blank-import","Blank-import",[1011,3590,3592],{"className":1036,"code":3591,"language":1026,"meta":1016,"style":1016},"import (\n    _ \"github.com\u002Fredelay\u002Fgo-framework\u002Fmodules\u002Fsettings\"        \u002F\u002F core read-only routes\n    _ \"github.com\u002Fredelay\u002Fgo-framework\u002Fmodules\u002Fsettings\u002Fadmin\"  \u002F\u002F admin CRUD routes\n    _ \"github.com\u002Fredelay\u002Fgo-framework\u002Fmodules\u002Fsettings\u002Fflowdsl\" \u002F\u002F FlowDSL nodes\n)\n",[981,3593,3594,3598,3603,3608,3613],{"__ignoreMap":1016},[1020,3595,3596],{"class":1022,"line":10},[1020,3597,1044],{},[1020,3599,3600],{"class":1022,"line":16},[1020,3601,3602],{},"    _ \"github.com\u002Fredelay\u002Fgo-framework\u002Fmodules\u002Fsettings\"        \u002F\u002F core read-only routes\n",[1020,3604,3605],{"class":1022,"line":22},[1020,3606,3607],{},"    _ \"github.com\u002Fredelay\u002Fgo-framework\u002Fmodules\u002Fsettings\u002Fadmin\"  \u002F\u002F admin CRUD routes\n",[1020,3609,3610],{"class":1022,"line":51},[1020,3611,3612],{},"    _ \"github.com\u002Fredelay\u002Fgo-framework\u002Fmodules\u002Fsettings\u002Fflowdsl\" \u002F\u002F FlowDSL nodes\n",[1020,3614,3615],{"class":1022,"line":57},[1020,3616,1064],{},[1765,3618,3620,3621,1720],{"id":3619},"flowdsl-nodes-settingsflowdsl","FlowDSL nodes (",[981,3622,1614],{},[1070,3624,3625,3637],{},[1073,3626,3627],{},[1076,3628,3629,3632,3635],{},[1079,3630,3631],{},"Node",[1079,3633,3634],{},"Kind",[1079,3636,1783],{},[1089,3638,3639,3656,3669],{},[1076,3640,3641,3646,3649],{},[1094,3642,3643],{},[981,3644,3645],{},"redelay\u002Fsettings-get",[1094,3647,3648],{},"transform",[1094,3650,3651,3652,3655],{},"Read a setting by module + key; has ",[981,3653,3654],{},"NotFound"," output port",[1076,3657,3658,3663,3666],{},[1094,3659,3660],{},[981,3661,3662],{},"redelay\u002Fsettings-set",[1094,3664,3665],{},"action",[1094,3667,3668],{},"Write a setting value",[1076,3670,3671,3676,3678],{},[1094,3672,3673],{},[981,3674,3675],{},"redelay\u002Fsettings-delete",[1094,3677,3665],{},[1094,3679,3680],{},"Remove a setting",[1729,3682],{},[1006,3684,1131],{"id":1131},[978,3686,3687],{},[986,3688,3689],{},"Object storage module backed by MinIO (S3-compatible).",[978,3691,2603,3692,3695],{},[981,3693,3694],{},"modules.ObjectStorage"," — inject into other modules for file uploads and downloads.",[1765,3697,3699],{"id":3698},"methods","Methods",[1011,3701,3703],{"className":1036,"code":3702,"language":1026,"meta":1016,"style":1016},"PutObject(ctx, bucket, key string, r io.Reader, size int64) error\nGetObject(ctx, bucket, key string) (io.ReadCloser, error)\nDeleteObject(ctx, bucket, key string) error\nPresignURL(ctx, bucket, key string, ttl time.Duration) (string, error)\n",[981,3704,3705,3710,3715,3720],{"__ignoreMap":1016},[1020,3706,3707],{"class":1022,"line":10},[1020,3708,3709],{},"PutObject(ctx, bucket, key string, r io.Reader, size int64) error\n",[1020,3711,3712],{"class":1022,"line":16},[1020,3713,3714],{},"GetObject(ctx, bucket, key string) (io.ReadCloser, error)\n",[1020,3716,3717],{"class":1022,"line":22},[1020,3718,3719],{},"DeleteObject(ctx, bucket, key string) error\n",[1020,3721,3722],{"class":1022,"line":51},[1020,3723,3724],{},"PresignURL(ctx, bucket, key string, ttl time.Duration) (string, error)\n",[1765,3726,1768],{"id":3727},"environment-variables-2",[1070,3729,3730,3740],{},[1073,3731,3732],{},[1076,3733,3734,3736,3738],{},[1079,3735,1777],{},[1079,3737,1780],{},[1079,3739,1783],{},[1089,3741,3742,3757,3772,3786,3801],{},[1076,3743,3744,3749,3754],{},[1094,3745,3746],{},[981,3747,3748],{},"MINIO_ENDPOINT",[1094,3750,3751],{},[981,3752,3753],{},"localhost:9000",[1094,3755,3756],{},"MinIO server endpoint",[1076,3758,3759,3764,3769],{},[1094,3760,3761],{},[981,3762,3763],{},"MINIO_ACCESS_KEY",[1094,3765,3766],{},[981,3767,3768],{},"minioadmin",[1094,3770,3771],{},"Access key ID",[1076,3773,3774,3779,3783],{},[1094,3775,3776],{},[981,3777,3778],{},"MINIO_SECRET_KEY",[1094,3780,3781],{},[981,3782,3768],{},[1094,3784,3785],{},"Secret access key",[1076,3787,3788,3793,3798],{},[1094,3789,3790],{},[981,3791,3792],{},"MINIO_BUCKET",[1094,3794,3795],{},[981,3796,3797],{},"redelay",[1094,3799,3800],{},"Default bucket name",[1076,3802,3803,3808,3813],{},[1094,3804,3805],{},[981,3806,3807],{},"MINIO_USE_SSL",[1094,3809,3810],{},[981,3811,3812],{},"false",[1094,3814,3815],{},"Use TLS",[1729,3817],{},[1006,3819,1147],{"id":1147},[978,3821,3822],{},[986,3823,3824],{},"Real-time notifications via Server-Sent Events with MongoDB persistence.",[978,3826,3827,3828,3831,3832,3835,3836,3839],{},"Clients subscribe to ",[981,3829,3830],{},"GET \u002Fnotifications\u002Fstream"," (under ROUTE_PREFIX, so\n",[981,3833,3834],{},"\u002Fapi\u002Fv1\u002Fnotifications\u002Fstream"," by default) and receive events in real time.\nThe module consumes ",[981,3837,3838],{},"notification.created"," events from the event bus and fans them out to\nall connected clients for that user.",[1765,3841,3843],{"id":3842},"routes","Routes",[1070,3845,3846,3856],{},[1073,3847,3848],{},[1076,3849,3850,3852,3854],{},[1079,3851,2279],{},[1079,3853,2282],{},[1079,3855,1783],{},[1089,3857,3858,3872,3886],{},[1076,3859,3860,3864,3869],{},[1094,3861,3862],{},[981,3863,2291],{},[1094,3865,3866],{},[981,3867,3868],{},"\u002Fnotifications\u002Fstream",[1094,3870,3871],{},"SSE stream for authenticated user",[1076,3873,3874,3878,3883],{},[1094,3875,3876],{},[981,3877,2291],{},[1094,3879,3880],{},[981,3881,3882],{},"\u002Fnotifications\u002F",[1094,3884,3885],{},"List notifications (paginated)",[1076,3887,3888,3892,3897],{},[1094,3889,3890],{},[981,3891,2312],{},[1094,3893,3894],{},[981,3895,3896],{},"\u002Fnotifications\u002F{id}\u002Fread",[1094,3898,3899],{},"Mark notification as read",[1765,3901,1768],{"id":3902},"environment-variables-3",[1070,3904,3905,3915],{},[1073,3906,3907],{},[1076,3908,3909,3911,3913],{},[1079,3910,1777],{},[1079,3912,1780],{},[1079,3914,1783],{},[1089,3916,3917],{},[1076,3918,3919,3924,3928],{},[1094,3920,3921],{},[981,3922,3923],{},"NOTIFICATIONS_COLLECTION",[1094,3925,3926],{},[981,3927,1147],{},[1094,3929,3549],{},[1765,3931,3933],{"id":3932},"event-schema-notificationcreated","Event schema (notification.created)",[1011,3935,3939],{"className":3936,"code":3937,"language":3938,"meta":1016,"style":1016},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"user_id\": \"string\",\n  \"type\": \"string\",\n  \"title\": \"string\",\n  \"body\": \"string\",\n  \"data\": {}\n}\n","json",[981,3940,3941,3945,3968,3987,4006,4025,4039],{"__ignoreMap":1016},[1020,3942,3943],{"class":1022,"line":10},[1020,3944,2461],{"class":1981},[1020,3946,3947,3950,3954,3956,3958,3960,3963,3965],{"class":1022,"line":16},[1020,3948,3949],{"class":1981},"  \"",[1020,3951,3953],{"class":3952},"spNyl","user_id",[1020,3955,2003],{"class":1981},[1020,3957,2523],{"class":1981},[1020,3959,1994],{"class":1981},[1020,3961,3962],{"class":1029},"string",[1020,3964,2003],{"class":1981},[1020,3966,3967],{"class":1981},",\n",[1020,3969,3970,3972,3975,3977,3979,3981,3983,3985],{"class":1022,"line":22},[1020,3971,3949],{"class":1981},[1020,3973,3974],{"class":3952},"type",[1020,3976,2003],{"class":1981},[1020,3978,2523],{"class":1981},[1020,3980,1994],{"class":1981},[1020,3982,3962],{"class":1029},[1020,3984,2003],{"class":1981},[1020,3986,3967],{"class":1981},[1020,3988,3989,3991,3994,3996,3998,4000,4002,4004],{"class":1022,"line":51},[1020,3990,3949],{"class":1981},[1020,3992,3993],{"class":3952},"title",[1020,3995,2003],{"class":1981},[1020,3997,2523],{"class":1981},[1020,3999,1994],{"class":1981},[1020,4001,3962],{"class":1029},[1020,4003,2003],{"class":1981},[1020,4005,3967],{"class":1981},[1020,4007,4008,4010,4013,4015,4017,4019,4021,4023],{"class":1022,"line":57},[1020,4009,3949],{"class":1981},[1020,4011,4012],{"class":3952},"body",[1020,4014,2003],{"class":1981},[1020,4016,2523],{"class":1981},[1020,4018,1994],{"class":1981},[1020,4020,3962],{"class":1029},[1020,4022,2003],{"class":1981},[1020,4024,3967],{"class":1981},[1020,4026,4027,4029,4032,4034,4036],{"class":1022,"line":102},[1020,4028,3949],{"class":1981},[1020,4030,4031],{"class":3952},"data",[1020,4033,2003],{"class":1981},[1020,4035,2523],{"class":1981},[1020,4037,4038],{"class":1981}," {}\n",[1020,4040,4041],{"class":1022,"line":108},[1020,4042,2646],{"class":1981},[1729,4044],{},[1006,4046,1163],{"id":1163},[978,4048,4049],{},[986,4050,4051],{},"Single-use token-based email verification.",[978,4053,4054,4055,4058,4059,4062],{},"Issues verification tokens, stores them in MongoDB, and optionally emits ",[981,4056,4057],{},"email.send"," events\n(consumed by ",[981,4060,4061],{},"go-module-email",") when a verification request is made via the HTTP API.",[1765,4064,3843],{"id":4065},"routes-1",[1070,4067,4068,4078],{},[1073,4069,4070],{},[1076,4071,4072,4074,4076],{},[1079,4073,2279],{},[1079,4075,2282],{},[1079,4077,1783],{},[1089,4079,4080,4094],{},[1076,4081,4082,4086,4091],{},[1094,4083,4084],{},[981,4085,2312],{},[1094,4087,4088],{},[981,4089,4090],{},"\u002Fverification\u002Frequest",[1094,4092,4093],{},"Create token and emit verification email",[1076,4095,4096,4100,4105],{},[1094,4097,4098],{},[981,4099,2312],{},[1094,4101,4102],{},[981,4103,4104],{},"\u002Fverification\u002Fverify",[1094,4106,4107],{},"Consume token and return verification result",[1765,4109,4111],{"id":4110},"store-api-for-other-modules","Store API (for other modules)",[978,4113,4114,4115,4118,4119,2523],{},"The verification module exposes its ",[981,4116,4117],{},"Store"," directly so other modules can manage the token\nlifecycle themselves without going through the HTTP routes. Discover it via ",[981,4120,4121],{},"Configure()",[1011,4123,4125],{"className":1036,"code":4124,"language":1026,"meta":1016,"style":1016},"func (m *MyModule) Configure(registry *modules.Registry) error {\n    for _, mod := range registry.All() {\n        if vm, ok := mod.(*verification.Module); ok {\n            m.verifyStore = vm.Store\n        }\n    }\n    return nil\n}\n\n\u002F\u002F Create a token (returns *verification.VerificationToken):\nvt, err := m.verifyStore.Create(ctx, email, verification.KindEmail, 32)\n\n\u002F\u002F Consume a token (returns nil if invalid\u002Fexpired):\nvt, err := m.verifyStore.Consume(ctx, token)\n",[981,4126,4127,4132,4137,4142,4147,4152,4157,4162,4166,4172,4177,4182,4186,4191],{"__ignoreMap":1016},[1020,4128,4129],{"class":1022,"line":10},[1020,4130,4131],{},"func (m *MyModule) Configure(registry *modules.Registry) error {\n",[1020,4133,4134],{"class":1022,"line":16},[1020,4135,4136],{},"    for _, mod := range registry.All() {\n",[1020,4138,4139],{"class":1022,"line":22},[1020,4140,4141],{},"        if vm, ok := mod.(*verification.Module); ok {\n",[1020,4143,4144],{"class":1022,"line":51},[1020,4145,4146],{},"            m.verifyStore = vm.Store\n",[1020,4148,4149],{"class":1022,"line":57},[1020,4150,4151],{},"        }\n",[1020,4153,4154],{"class":1022,"line":102},[1020,4155,4156],{},"    }\n",[1020,4158,4159],{"class":1022,"line":108},[1020,4160,4161],{},"    return nil\n",[1020,4163,4164],{"class":1022,"line":114},[1020,4165,2646],{},[1020,4167,4168],{"class":1022,"line":120},[1020,4169,4171],{"emptyLinePlaceholder":4170},true,"\n",[1020,4173,4174],{"class":1022,"line":181},[1020,4175,4176],{},"\u002F\u002F Create a token (returns *verification.VerificationToken):\n",[1020,4178,4179],{"class":1022,"line":186},[1020,4180,4181],{},"vt, err := m.verifyStore.Create(ctx, email, verification.KindEmail, 32)\n",[1020,4183,4184],{"class":1022,"line":191},[1020,4185,4171],{"emptyLinePlaceholder":4170},[1020,4187,4188],{"class":1022,"line":197},[1020,4189,4190],{},"\u002F\u002F Consume a token (returns nil if invalid\u002Fexpired):\n",[1020,4192,4193],{"class":1022,"line":203},[1020,4194,4195],{},"vt, err := m.verifyStore.Consume(ctx, token)\n",[1765,4197,1768],{"id":4198},"environment-variables-4",[1070,4200,4201,4211],{},[1073,4202,4203],{},[1076,4204,4205,4207,4209],{},[1079,4206,1777],{},[1079,4208,1780],{},[1079,4210,1783],{},[1089,4212,4213,4227,4241],{},[1076,4214,4215,4220,4225],{},[1094,4216,4217],{},[981,4218,4219],{},"VERIFICATION_COLLECTION",[1094,4221,4222],{},[981,4223,4224],{},"verification_tokens",[1094,4226,3549],{},[1076,4228,4229,4234,4238],{},[1094,4230,4231],{},[981,4232,4233],{},"VERIFICATION_TOKEN_TTL_MINUTES",[1094,4235,4236],{},[981,4237,1842],{},[1094,4239,4240],{},"Token expiry in minutes",[1076,4242,4243,4248,4253],{},[1094,4244,4245],{},[981,4246,4247],{},"VERIFICATION_TOKEN_BYTES",[1094,4249,4250],{},[981,4251,4252],{},"32",[1094,4254,4255],{},"Random bytes for token generation",[1729,4257],{},[1006,4259,1179],{"id":1179},[978,4261,4262],{},[986,4263,4264],{},"URL shortener with click tracking.",[978,4266,4267,4268,4271,4272,1004],{},"Short links are stored in MongoDB. The redirect handler is mounted at ",[981,4269,4270],{},"\u002F{code}"," (outside the API prefix) via ",[981,4273,4274],{},"MountProvider",[1765,4276,3843],{"id":4277},"routes-2",[1070,4279,4280,4290],{},[1073,4281,4282],{},[1076,4283,4284,4286,4288],{},[1079,4285,2279],{},[1079,4287,2282],{},[1079,4289,1783],{},[1089,4291,4292,4306,4319,4333],{},[1076,4293,4294,4298,4303],{},[1094,4295,4296],{},[981,4297,2312],{},[1094,4299,4300],{},[981,4301,4302],{},"\u002Flinks\u002F",[1094,4304,4305],{},"Create a short link",[1076,4307,4308,4312,4316],{},[1094,4309,4310],{},[981,4311,2291],{},[1094,4313,4314],{},[981,4315,4302],{},[1094,4317,4318],{},"List short links (last 100)",[1076,4320,4321,4325,4330],{},[1094,4322,4323],{},[981,4324,2348],{},[1094,4326,4327],{},[981,4328,4329],{},"\u002Flinks\u002F{code}",[1094,4331,4332],{},"Delete a short link",[1076,4334,4335,4339,4343],{},[1094,4336,4337],{},[981,4338,2291],{},[1094,4340,4341],{},[981,4342,4270],{},[1094,4344,4345],{},"Redirect to target URL",[1765,4347,1768],{"id":4348},"environment-variables-5",[1070,4350,4351,4361],{},[1073,4352,4353],{},[1076,4354,4355,4357,4359],{},[1079,4356,1777],{},[1079,4358,1780],{},[1079,4360,1783],{},[1089,4362,4363,4377,4392],{},[1076,4364,4365,4370,4375],{},[1094,4366,4367],{},[981,4368,4369],{},"LINKS_COLLECTION",[1094,4371,4372],{},[981,4373,4374],{},"short_links",[1094,4376,3549],{},[1076,4378,4379,4384,4389],{},[1094,4380,4381],{},[981,4382,4383],{},"LINKS_CODE_LENGTH",[1094,4385,4386],{},[981,4387,4388],{},"6",[1094,4390,4391],{},"Generated code length in bytes",[1076,4393,4394,4399,4402],{},[1094,4395,4396],{},[981,4397,4398],{},"LINKS_BASE_URL",[1094,4400,4401],{},"``",[1094,4403,4404],{},"Base URL prepended to short codes",[1729,4406],{},[1006,4408,1195],{"id":1195},[978,4410,4411],{},[986,4412,4413],{},"Prometheus-compatible metrics endpoint and HTTP request duration middleware.",[978,4415,4416,4417,4420,4421,4423,4424,4427],{},"Mounts ",[981,4418,4419],{},"\u002Fmetrics"," (configurable) via ",[981,4422,4274],{}," and wraps all routes with a\n",[981,4425,4426],{},"http_request_duration_seconds"," histogram labeled by method, path, and status code.",[1765,4429,1768],{"id":4430},"environment-variables-6",[1070,4432,4433,4443],{},[1073,4434,4435],{},[1076,4436,4437,4439,4441],{},[1079,4438,1777],{},[1079,4440,1780],{},[1079,4442,1783],{},[1089,4444,4445],{},[1076,4446,4447,4452,4456],{},[1094,4448,4449],{},[981,4450,4451],{},"METRICS_PATH",[1094,4453,4454],{},[981,4455,4419],{},[1094,4457,4458],{},"HTTP path for the metrics endpoint",[1765,4460,4462],{"id":4461},"exposed-metrics","Exposed metrics",[1070,4464,4465,4478],{},[1073,4466,4467],{},[1076,4468,4469,4472,4475],{},[1079,4470,4471],{},"Metric",[1079,4473,4474],{},"Type",[1079,4476,4477],{},"Labels",[1089,4479,4480],{},[1076,4481,4482,4486,4489],{},[1094,4483,4484],{},[981,4485,4426],{},[1094,4487,4488],{},"Histogram",[1094,4490,4491,1716,4494,1716,4497],{},[981,4492,4493],{},"method",[981,4495,4496],{},"path",[981,4498,2122],{},[1765,4500,4502],{"id":4501},"metricsadmin-database-observability-admin-api-only","metrics\u002Fadmin — database observability (admin-api only)",[978,4504,2191,4505,4507,4508,4511,4512,4514],{},[981,4506,1377],{}," submodule adds ",[981,4509,4510],{},"GET \u002Fadmin\u002Fmetrics\u002Fdatabase"," (under the\nadmin prefix, ",[981,4513,3314],{},"), returning a live summary of ClickHouse, MongoDB,\nand Redis activity. Import it from the admin-api binary only.",[978,4516,4517,4518,4521],{},"Every figure is read from the database's ",[986,4519,4520],{},"own"," statistics — Redelay does not\ninstrument queries app-side — so a field is populated only where the backend\nnatively reports it:",[1070,4523,4524,4539],{},[1073,4525,4526],{},[1076,4527,4528,4531,4533,4536],{},[1079,4529,4530],{},"Backend",[1079,4532,2672],{},[1079,4534,4535],{},"Real",[1079,4537,4538],{},"Not available",[1089,4540,4541,4556,4575],{},[1076,4542,4543,4546,4551,4554],{},[1094,4544,4545],{},"ClickHouse",[1094,4547,4548],{},[981,4549,4550],{},"system.query_log",[1094,4552,4553],{},"total, avg\u002Fmax ms, error rate, slow %, top query kinds",[1094,4555,3072],{},[1076,4557,4558,4561,4569,4572],{},[1094,4559,4560],{},"Redis",[1094,4562,4563,1457,4566],{},[981,4564,4565],{},"INFO commandstats",[981,4567,4568],{},"stats",[1094,4570,4571],{},"total ops, avg ms, top commands",[1094,4573,4574],{},"max, error rate, slow %",[1076,4576,4577,4580,4585,4588],{},[1094,4578,4579],{},"MongoDB",[1094,4581,4582],{},[981,4583,4584],{},"serverStatus",[1094,4586,4587],{},"total ops, ops\u002Fmin",[1094,4589,4590],{},"avg\u002Fmax ms, error rate, slow % (need the profiler)",[978,4592,4593],{},"A nil backend yields a zero-valued section rather than an error, so the endpoint\nworks on a deployment running only some of the three.",[1729,4595],{},[1006,4597,1347],{"id":1347},[978,4599,4600],{},[986,4601,4602],{},"Per-user security: an activity log, trusted devices, rate limiting, and\nautomatic restriction of suspicious accounts.",[978,4604,4605,4606,4609,4610,4613],{},"The core module mounts under ",[981,4607,4608],{},"\u002Fuser"," (relative to ",[981,4611,4612],{},"ROUTE_PREFIX",") and records\nrequest activity through a middleware, restricting a user once their suspicious\n-activity count crosses a threshold.",[1765,4615,4617],{"id":4616},"routes-core-authenticated","Routes (core, authenticated)",[1070,4619,4620,4630],{},[1073,4621,4622],{},[1076,4623,4624,4626,4628],{},[1079,4625,2279],{},[1079,4627,2282],{},[1079,4629,1783],{},[1089,4631,4632,4644,4656,4668,4680,4692,4703],{},[1076,4633,4634,4636,4641],{},[1094,4635,2291],{},[1094,4637,4638],{},[981,4639,4640],{},"\u002Fuser\u002Factivities",[1094,4642,4643],{},"The caller's recent activity",[1076,4645,4646,4648,4653],{},[1094,4647,2291],{},[1094,4649,4650],{},[981,4651,4652],{},"\u002Fuser\u002Frate-limits",[1094,4654,4655],{},"The caller's current rate-limit status",[1076,4657,4658,4660,4665],{},[1094,4659,2291],{},[1094,4661,4662],{},[981,4663,4664],{},"\u002Fuser\u002Fsecurity\u002Fprofile",[1094,4666,4667],{},"Suspicious count, restriction state, known devices",[1076,4669,4670,4672,4677],{},[1094,4671,2291],{},[1094,4673,4674],{},[981,4675,4676],{},"\u002Fuser\u002Fsecurity\u002Fsuspicious-activities",[1094,4678,4679],{},"The caller's flagged activity",[1076,4681,4682,4684,4689],{},[1094,4683,2291],{},[1094,4685,4686],{},[981,4687,4688],{},"\u002Fuser\u002Fsecurity\u002Ftrusted-devices",[1094,4690,4691],{},"List trusted devices",[1076,4693,4694,4696,4700],{},[1094,4695,2312],{},[1094,4697,4698],{},[981,4699,4688],{},[1094,4701,4702],{},"Trust the current device",[1076,4704,4705,4707,4712],{},[1094,4706,2348],{},[1094,4708,4709],{},[981,4710,4711],{},"\u002Fuser\u002Fsecurity\u002Ftrusted-devices\u002F{device_id}",[1094,4713,4714],{},"Untrust a device",[1765,4716,4718],{"id":4717},"securityadmin-admin-api-only","security\u002Fadmin (admin-api only)",[978,4720,4721,4722,4725,4726,4729,4730,1004],{},"Superuser operations under the admin prefix: per-user activity reports\n(",[981,4723,4724],{},"\u002Fadmin\u002Fsecurity\u002Factivities\u002F{user_id}"," + summary), error\u002Fpath reports, security\nanalytics, and enforcement — ",[981,4727,4728],{},"POST \u002Fadmin\u002Fsecurity\u002Fblock-ip\u002F{ip}"," and\n",[981,4731,4732],{},"POST \u002Fadmin\u002Fsecurity\u002Frestrict-user\u002F{user_id}",[1765,4734,1768],{"id":4735},"environment-variables-7",[1070,4737,4738,4748],{},[1073,4739,4740],{},[1076,4741,4742,4744,4746],{},[1079,4743,1777],{},[1079,4745,1780],{},[1079,4747,1783],{},[1089,4749,4750,4765,4780,4795,4810,4824,4838,4853],{},[1076,4751,4752,4757,4762],{},[1094,4753,4754],{},[981,4755,4756],{},"SECURITY_ACTIVITY_COLLECTION",[1094,4758,4759],{},[981,4760,4761],{},"user_activities",[1094,4763,4764],{},"Activity log collection",[1076,4766,4767,4772,4777],{},[1094,4768,4769],{},[981,4770,4771],{},"SECURITY_DEVICE_COLLECTION",[1094,4773,4774],{},[981,4775,4776],{},"trusted_devices",[1094,4778,4779],{},"Trusted-device collection",[1076,4781,4782,4787,4792],{},[1094,4783,4784],{},[981,4785,4786],{},"SECURITY_SUSPICIOUS_COLLECTION",[1094,4788,4789],{},[981,4790,4791],{},"suspicious_activities",[1094,4793,4794],{},"Flagged-activity collection",[1076,4796,4797,4802,4807],{},[1094,4798,4799],{},[981,4800,4801],{},"SECURITY_RESTRICTION_COLLECTION",[1094,4803,4804],{},[981,4805,4806],{},"security_restrictions",[1094,4808,4809],{},"Active restrictions",[1076,4811,4812,4817,4821],{},[1094,4813,4814],{},[981,4815,4816],{},"SECURITY_ACTIVITY_RETENTION_DAYS",[1094,4818,4819],{},[981,4820,1842],{},[1094,4822,4823],{},"Activity-log TTL",[1076,4825,4826,4831,4835],{},[1094,4827,4828],{},[981,4829,4830],{},"SECURITY_RESTRICT_THRESHOLD",[1094,4832,4833],{},[981,4834,1827],{},[1094,4836,4837],{},"Suspicious events before auto-restriction",[1076,4839,4840,4845,4850],{},[1094,4841,4842],{},[981,4843,4844],{},"SECURITY_USER_RATE_LIMIT",[1094,4846,4847],{},[981,4848,4849],{},"1000",[1094,4851,4852],{},"Per-user request budget",[1076,4854,4855,4860,4865],{},[1094,4856,4857],{},[981,4858,4859],{},"SECURITY_IP_RATE_LIMIT",[1094,4861,4862],{},[981,4863,4864],{},"200",[1094,4866,4867],{},"Per-IP request budget",[1729,4869],{},[1006,4871,1364],{"id":1364},[978,4873,4874],{},[986,4875,4876],{},"Event-bus admin (admin-api only): browse event definitions, publish events by\nhand, browse the event log, and manage webhook subscriptions.",[978,4878,4879,4880,1426,4883,4885],{},"Mounts under ",[981,4881,4882],{},"\u002Fadmin\u002Fevents",[981,4884,3314],{},"). Import from the admin-api binary\nonly.",[1765,4887,3843],{"id":4888},"routes-3",[1070,4890,4891,4901],{},[1073,4892,4893],{},[1076,4894,4895,4897,4899],{},[1079,4896,2279],{},[1079,4898,2282],{},[1079,4900,1783],{},[1089,4902,4903,4915,4930,4942,4963,4975],{},[1076,4904,4905,4907,4912],{},[1094,4906,2291],{},[1094,4908,4909],{},[981,4910,4911],{},"\u002Fadmin\u002Fevents\u002Fdefinitions",[1094,4913,4914],{},"Known event types — live registry + runtime-registered",[1076,4916,4917,4919,4924],{},[1094,4918,2312],{},[1094,4920,4921],{},[981,4922,4923],{},"\u002Fadmin\u002Fevents\u002Fdefinition",[1094,4925,4926,4927,1720],{},"Register a runtime event definition (",[981,4928,4929],{},"?definition=\u003Cjson>",[1076,4931,4932,4934,4939],{},[1094,4933,2312],{},[1094,4935,4936],{},[981,4937,4938],{},"\u002Fadmin\u002Fevents\u002Fpublish",[1094,4940,4941],{},"Publish an event → bus + log + webhook dispatch",[1076,4943,4944,4946,4951],{},[1094,4945,2291],{},[1094,4947,4948],{},[981,4949,4950],{},"\u002Fadmin\u002Fevents\u002Flogs",[1094,4952,4953,4954,2787,4957,2787,4959,4962],{},"Browse the event log (",[981,4955,4956],{},"entity_type",[981,4958,3665],{},[981,4960,4961],{},"limit"," filters)",[1076,4964,4965,4967,4972],{},[1094,4966,2291],{},[1094,4968,4969],{},[981,4970,4971],{},"\u002Fadmin\u002Fevents\u002Fsubscriptions",[1094,4973,4974],{},"List webhook subscriptions",[1076,4976,4977,4979,4984],{},[1094,4978,2312],{},[1094,4980,4981],{},[981,4982,4983],{},"\u002Fadmin\u002Fevents\u002Fsubscription",[1094,4985,4986],{},"Register a webhook (entity_type\u002Faction match; nil = any)",[978,4988,4989,4990,4993],{},"Definitions are read from the live module registry ",[986,4991,4992],{},"at request time"," — after\nevery module has registered — so the list is current without depending on module\nstartup ordering.",[991,4995,4996,4997,5000,5001,5003,5004,5006],{"icon":11},"The event log captures events published ",[986,4998,4999],{},"through this module"," (and any module\nthat calls its service). It does ",[986,5002,2143],{}," passively sniff every event on the bus:\nRedelay consumers are per-topic and a catch-all sink would depend on fragile\nConfigure ordering. For a complete trail, add per-topic consumers or use the\n",[981,5005,1521],{}," module.",[1765,5008,1768],{"id":5009},"environment-variables-8",[1070,5011,5012,5022],{},[1073,5013,5014],{},[1076,5015,5016,5018,5020],{},[1079,5017,1777],{},[1079,5019,1780],{},[1079,5021,1783],{},[1089,5023,5024,5039,5054,5069,5084],{},[1076,5025,5026,5031,5036],{},[1094,5027,5028],{},[981,5029,5030],{},"EVENTADMIN_DEFINITION_COLLECTION",[1094,5032,5033],{},[981,5034,5035],{},"event_definitions",[1094,5037,5038],{},"Runtime definitions",[1076,5040,5041,5046,5051],{},[1094,5042,5043],{},[981,5044,5045],{},"EVENTADMIN_SUBSCRIPTION_COLLECTION",[1094,5047,5048],{},[981,5049,5050],{},"event_subscriptions",[1094,5052,5053],{},"Webhook subscriptions",[1076,5055,5056,5061,5066],{},[1094,5057,5058],{},[981,5059,5060],{},"EVENTADMIN_LOG_COLLECTION",[1094,5062,5063],{},[981,5064,5065],{},"event_logs",[1094,5067,5068],{},"Event log",[1076,5070,5071,5076,5081],{},[1094,5072,5073],{},[981,5074,5075],{},"EVENTADMIN_LOG_TTL_HOURS",[1094,5077,5078],{},[981,5079,5080],{},"168",[1094,5082,5083],{},"Event-log retention (7 days)",[1076,5085,5086,5091,5096],{},[1094,5087,5088],{},[981,5089,5090],{},"EVENTADMIN_WEBHOOK_TIMEOUT_SECONDS",[1094,5092,5093],{},[981,5094,5095],{},"5",[1094,5097,5098],{},"Per-callback timeout on dispatch",[1729,5100],{},[1006,5102,1211],{"id":1211},[978,5104,5105],{},[986,5106,5107],{},"Flow CRUD, immutable versioning, run launch, and live SSE event streaming for FlowDSL flows.",[978,5109,5110,5112,5113,5119],{},[981,5111,1216],{}," is the framework-side HTTP surface over\n",[995,5114,5116],{"href":5115},"\u002Fdocs\u002Freference\u002Fgo-flowdsl#flowexec",[981,5117,5118],{},"go-flowdsl\u002Fflowexec",". It wires the executor, store, and\nsink into your app and exposes them as REST + Server-Sent Events. Register it with a blank\nimport:",[1011,5121,5123],{"className":1036,"code":5122,"language":1026,"meta":1016,"style":1016},"import (\n    _ \"github.com\u002Fredelay\u002Fgo-flowdsl\u002Fruntime\"       \u002F\u002F your handlers register here\n    _ \"github.com\u002Fredelay\u002Fgo-flowdsl\u002Fflowexec\u002Fmodule\"\n)\n",[981,5124,5125,5129,5134,5139],{"__ignoreMap":1016},[1020,5126,5127],{"class":1022,"line":10},[1020,5128,1044],{},[1020,5130,5131],{"class":1022,"line":16},[1020,5132,5133],{},"    _ \"github.com\u002Fredelay\u002Fgo-flowdsl\u002Fruntime\"       \u002F\u002F your handlers register here\n",[1020,5135,5136],{"class":1022,"line":22},[1020,5137,5138],{},"    _ \"github.com\u002Fredelay\u002Fgo-flowdsl\u002Fflowexec\u002Fmodule\"\n",[1020,5140,5141],{"class":1022,"line":51},[1020,5142,1064],{},[978,5144,5145,5146,2523],{},"At bootstrap it inspects ",[981,5147,5148],{},"deps.DB",[1070,5150,5151,5164],{},[1073,5152,5153],{},[1076,5154,5155,5159,5161],{},[1079,5156,5157],{},[981,5158,5148],{},[1079,5160,4117],{},[1079,5162,5163],{},"Sink",[1089,5165,5166,5187],{},[1076,5167,5168,5171,5177],{},[1094,5169,5170],{},"non-nil",[1094,5172,5173,5176],{},[981,5174,5175],{},"mongostore"," (indexes created automatically)",[1094,5178,5179,5182,5183,5186],{},[981,5180,5181],{},"mongots"," time-series sink (falls back to ",[981,5184,5185],{},"noop"," on init error)",[1076,5188,5189,5192,5197],{},[1094,5190,5191],{},"nil",[1094,5193,5194],{},[981,5195,5196],{},"memstore",[1094,5198,5199],{},[981,5200,5185],{},[978,5202,5203],{},"App code registers node handlers on the engine exposed by the module:",[1011,5205,5207],{"className":1036,"code":5206,"language":1026,"meta":1016,"style":1016},"m := modules.Registry().MustGet(\"flowexec\").(*flowexec.Module)\nm.Engine().RegisterHandler(\"charge_card\", chargeCard)\nm.Engine().RegisterKindHandler(ir.NodeKindAction, defaultAction)\n",[981,5208,5209,5214,5219],{"__ignoreMap":1016},[1020,5210,5211],{"class":1022,"line":10},[1020,5212,5213],{},"m := modules.Registry().MustGet(\"flowexec\").(*flowexec.Module)\n",[1020,5215,5216],{"class":1022,"line":16},[1020,5217,5218],{},"m.Engine().RegisterHandler(\"charge_card\", chargeCard)\n",[1020,5220,5221],{"class":1022,"line":22},[1020,5222,5223],{},"m.Engine().RegisterKindHandler(ir.NodeKindAction, defaultAction)\n",[1765,5225,5227],{"id":5226},"live-sse-broadcaster","Live SSE broadcaster",[978,5229,5230,5231,5234,5235,5238],{},"Between the executor and the downstream sink sits a broadcaster that tees every ",[981,5232,5233],{},"FlowEvent"," to\nper-",[981,5236,5237],{},"runID"," subscriber channels. The downstream sink still receives the canonical record.\nSlow subscribers are dropped (non-blocking send) rather than backpressuring the run — the\ndurable event stream in the sink remains complete, subscribers see a live best-effort feed.",[1765,5240,3843],{"id":5241},"routes-4",[978,5243,5244,5245,1004],{},"All routes are mounted relative to ",[981,5246,4612],{},[1070,5248,5249,5259],{},[1073,5250,5251],{},[1076,5252,5253,5255,5257],{},[1079,5254,2279],{},[1079,5256,2282],{},[1079,5258,1783],{},[1089,5260,5261,5275,5291,5305,5319,5332,5349,5362],{},[1076,5262,5263,5267,5272],{},[1094,5264,5265],{},[981,5266,2291],{},[1094,5268,5269],{},[981,5270,5271],{},"\u002Fflows",[1094,5273,5274],{},"List flows (cursor-paginated)",[1076,5276,5277,5281,5285],{},[1094,5278,5279],{},[981,5280,2312],{},[1094,5282,5283],{},[981,5284,5271],{},[1094,5286,5287,5288],{},"Create a flow — ",[981,5289,5290],{},"{name, description, labels}",[1076,5292,5293,5297,5302],{},[1094,5294,5295],{},[981,5296,2291],{},[1094,5298,5299],{},[981,5300,5301],{},"\u002Fflows\u002F{id}",[1094,5303,5304],{},"Read a flow (head and published pointers)",[1076,5306,5307,5312,5316],{},[1094,5308,5309],{},[981,5310,5311],{},"PATCH",[1094,5313,5314],{},[981,5315,5301],{},[1094,5317,5318],{},"Update flow metadata",[1076,5320,5321,5325,5329],{},[1094,5322,5323],{},[981,5324,2348],{},[1094,5326,5327],{},[981,5328,5301],{},[1094,5330,5331],{},"Delete flow and all versions",[1076,5333,5334,5338,5343],{},[1094,5335,5336],{},[981,5337,2312],{},[1094,5339,5340],{},[981,5341,5342],{},"\u002Fflows\u002F{id}\u002Fversions",[1094,5344,5345,5346],{},"Save a new immutable version — ",[981,5347,5348],{},"{document, note, labels}",[1076,5350,5351,5355,5359],{},[1094,5352,5353],{},[981,5354,2291],{},[1094,5356,5357],{},[981,5358,5342],{},[1094,5360,5361],{},"List versions (newest first, documents omitted)",[1076,5363,5364,5368,5373],{},[1094,5365,5366],{},[981,5367,2291],{},[1094,5369,5370],{},[981,5371,5372],{},"\u002Fflows\u002F{id}\u002Fversions\u002F{vid}",[1094,5374,5375],{},"Read a version, full document included",[2800,5377,5379,5382],{"id":5378},"formatspec-query-parameter",[981,5380,5381],{},"?format=spec"," query parameter",[978,5384,5385,5386,5388,5389,5392,5393,1004],{},"The version endpoints accept an optional ",[981,5387,5381],{}," query parameter. When present, the\nAPI transparently converts between the Studio spec document format and the internal\n",[981,5390,5391],{},"ir.Workflow"," using ",[995,5394,5396],{"href":5395},"\u002Fdocs\u002Freference\u002Fgo-flowdsl#spec-studio-spec-document-converters",[981,5397,5398],{},"go-flowdsl\u002Fspec",[978,5400,5401],{},[986,5402,5403],{},"Save a version in spec format:",[1011,5405,5407],{"className":1013,"code":5406,"language":1015,"meta":1016,"style":1016},"curl -sX POST \"$API\u002Fflows\u002F$FLOW\u002Fversions?format=spec\" \\\n  -H 'Content-Type: application\u002Fjson' \\\n  -d @my-flow.spec.json\n",[981,5408,5409,5435,5449],{"__ignoreMap":1016},[1020,5410,5411,5413,5416,5418,5420,5422,5425,5428,5431,5433],{"class":1022,"line":10},[1020,5412,1985],{"class":1025},[1020,5414,5415],{"class":1029}," -sX",[1020,5417,2056],{"class":1029},[1020,5419,1994],{"class":1981},[1020,5421,2014],{"class":1974},[1020,5423,5424],{"class":1029},"\u002Fflows\u002F",[1020,5426,5427],{"class":1974},"$FLOW",[1020,5429,5430],{"class":1029},"\u002Fversions?format=spec",[1020,5432,2003],{"class":1981},[1020,5434,2006],{"class":1974},[1020,5436,5437,5440,5442,5445,5447],{"class":1022,"line":16},[1020,5438,5439],{"class":1029},"  -H",[1020,5441,2031],{"class":1981},[1020,5443,5444],{"class":1029},"Content-Type: application\u002Fjson",[1020,5446,2037],{"class":1981},[1020,5448,2006],{"class":1974},[1020,5450,5451,5454],{"class":1022,"line":22},[1020,5452,5453],{"class":1029},"  -d",[1020,5455,5456],{"class":1029}," @my-flow.spec.json\n",[978,5458,5459,5460,5463,5464,1716,5467,1716,5470,1716,5473,5476,5477,5480,5481,1004],{},"The request body is a ",[981,5461,5462],{},"spec.Document"," (with ",[981,5465,5466],{},"flowdsl",[981,5468,5469],{},"info",[981,5471,5472],{},"flows",[981,5474,5475],{},"components",").\nThe server calls ",[981,5478,5479],{},"spec.ToWorkflow()"," and stores the resulting ",[981,5482,5391],{},[978,5484,5485],{},[986,5486,5487],{},"Read a version in spec format:",[1011,5489,5491],{"className":1013,"code":5490,"language":1015,"meta":1016,"style":1016},"curl -s \"$API\u002Fflows\u002F$FLOW\u002Fversions\u002F$VID?format=spec\"\n",[981,5492,5493],{"__ignoreMap":1016},[1020,5494,5495,5497,5499,5501,5503,5505,5507,5510,5513,5515],{"class":1022,"line":10},[1020,5496,1985],{"class":1025},[1020,5498,1988],{"class":1029},[1020,5500,1994],{"class":1981},[1020,5502,2014],{"class":1974},[1020,5504,5424],{"class":1029},[1020,5506,5427],{"class":1974},[1020,5508,5509],{"class":1029},"\u002Fversions\u002F",[1020,5511,5512],{"class":1974},"$VID",[1020,5514,5381],{"class":1029},[1020,5516,2558],{"class":1981},[978,5518,5519,5520,5523,5524,5526,5527,5529],{},"The server calls ",[981,5521,5522],{},"spec.FromWorkflow()"," on the stored ",[981,5525,5391],{}," and returns a\n",[981,5528,5462],{}," in the response. This is the format the FlowDSL Studio editor expects.",[978,5531,5532,5533,5535,5536,5538,5539,5541,5542,5545,5546,5549,5550,5541,5552,5555,5556,5549,5559,5541,5561,5564,5565,5567],{},"Without ",[981,5534,5381],{},", both endpoints use the raw ",[981,5537,5391],{}," format.\n| ",[981,5540,2312],{}," | ",[981,5543,5544],{},"\u002Fflows\u002F{id}\u002Fpublish"," | Flip published pointer — ",[981,5547,5548],{},"{versionID}"," |\n| ",[981,5551,2312],{},[981,5553,5554],{},"\u002Fflows\u002F{id}\u002Fruns"," | Launch run on the currently published version — ",[981,5557,5558],{},"{input, labels}",[981,5560,2291],{},[981,5562,5563],{},"\u002Fruns\u002F{runID}\u002Fevents"," | SSE live stream of ",[981,5566,5233],{}," payloads for a run |",[978,5569,5570,5573,5574,5577,5578,2424,5581,5584,5585,1004],{},[981,5571,5572],{},"POST \u002Fflows\u002F{id}\u002Fruns"," resolves the published version, calls ",[981,5575,5576],{},"Executor.RunAsync",", and returns\n",[981,5579,5580],{},"202 Accepted",[981,5582,5583],{},"{runID, versionID, versionHash}",". If the flow has no published version\nthe response is ",[981,5586,5587],{},"409 Conflict",[1765,5589,5591],{"id":5590},"sse-stream","SSE stream",[978,5593,5594,5597,5598,5601,5602,5605,5606,2523],{},[981,5595,5596],{},"GET \u002Fruns\u002F{runID}\u002Fevents"," returns a ",[981,5599,5600],{},"text\u002Fevent-stream"," that writes a ",[981,5603,5604],{},": connected"," prelude,\nthen one SSE frame per ",[981,5607,5233],{},[1011,5609,5614],{"className":5610,"code":5612,"language":5613},[5611],"language-text","event: node.started\ndata: {\"runID\":\"run.abc\",\"flowID\":\"flow.xyz\",\"nodeID\":\"n1\",\"timestamp\":\"2026-04-14T10:00:00Z\",...}\n","text",[981,5615,5612],{"__ignoreMap":1016},[978,5617,5618,5619,5622,5623,5626,5627,5630],{},"Heartbeat ",[981,5620,5621],{},": keep-alive"," lines are written every 15 seconds so intermediaries do not drop the\nconnection. The stream closes automatically when a ",[981,5624,5625],{},"run.completed"," or ",[981,5628,5629],{},"run.failed"," event\narrives.",[1765,5632,5634],{"id":5633},"response-shapes","Response shapes",[978,5636,5637,2523],{},[981,5638,5572],{},[1011,5640,5642],{"className":3936,"code":5641,"language":3938,"meta":1016,"style":1016},"{\n  \"runID\": \"run.018f...\",\n  \"versionID\": \"v.018f...\",\n  \"versionHash\": \"f3e1b...\"\n}\n",[981,5643,5644,5648,5667,5687,5705],{"__ignoreMap":1016},[1020,5645,5646],{"class":1022,"line":10},[1020,5647,2461],{"class":1981},[1020,5649,5650,5652,5654,5656,5658,5660,5663,5665],{"class":1022,"line":16},[1020,5651,3949],{"class":1981},[1020,5653,5237],{"class":3952},[1020,5655,2003],{"class":1981},[1020,5657,2523],{"class":1981},[1020,5659,1994],{"class":1981},[1020,5661,5662],{"class":1029},"run.018f...",[1020,5664,2003],{"class":1981},[1020,5666,3967],{"class":1981},[1020,5668,5669,5671,5674,5676,5678,5680,5683,5685],{"class":1022,"line":22},[1020,5670,3949],{"class":1981},[1020,5672,5673],{"class":3952},"versionID",[1020,5675,2003],{"class":1981},[1020,5677,2523],{"class":1981},[1020,5679,1994],{"class":1981},[1020,5681,5682],{"class":1029},"v.018f...",[1020,5684,2003],{"class":1981},[1020,5686,3967],{"class":1981},[1020,5688,5689,5691,5694,5696,5698,5700,5703],{"class":1022,"line":51},[1020,5690,3949],{"class":1981},[1020,5692,5693],{"class":3952},"versionHash",[1020,5695,2003],{"class":1981},[1020,5697,2523],{"class":1981},[1020,5699,1994],{"class":1981},[1020,5701,5702],{"class":1029},"f3e1b...",[1020,5704,2558],{"class":1981},[1020,5706,5707],{"class":1022,"line":57},[1020,5708,2646],{"class":1981},[978,5710,5711,5712,5714],{},"Every event emitted on the SSE stream carries the same ",[981,5713,5693],{},", so clients can tell at a\nglance whether they are watching the same version they launched.",[1765,5716,5718],{"id":5717},"usage-with-historical-replay","Usage with historical replay",[978,5720,5721,5722,5725,5726,5728],{},"The module does not serve paginated historical events — use the sink's ",[981,5723,5724],{},"Reader"," interface\n(implemented by ",[981,5727,5181],{},") to back a replay endpoint in your own module when needed. The SSE\nstream is strictly live.",[5730,5731,5732],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 .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 .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 .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":1016,"searchDepth":16,"depth":16,"links":5734},[5735,5736,5737,5738,5747,5763,5767,5772,5777,5781,5786,5791,5795],{"id":1008,"depth":16,"text":1009},{"id":1067,"depth":16,"text":1068},{"id":1539,"depth":16,"text":1540},{"id":1099,"depth":16,"text":1099,"children":5739},[5740,5741,5742,5743,5744,5746],{"id":1767,"depth":22,"text":1768},{"id":1884,"depth":22,"text":1885},{"id":1939,"depth":22,"text":1940},{"id":2130,"depth":22,"text":2131},{"id":2210,"depth":22,"text":5745},"HTTP surface — scheduler\u002Fadmin (admin-api only)",{"id":2492,"depth":22,"text":2493},{"id":1115,"depth":16,"text":1115,"children":5748},[5749,5750,5751,5752,5754,5755,5757,5758,5759,5760,5761],{"id":2610,"depth":22,"text":2611},{"id":2659,"depth":22,"text":2660},{"id":2739,"depth":22,"text":2740},{"id":2969,"depth":22,"text":5753},"Access control: public and sensitive flags",{"id":3244,"depth":22,"text":3245},{"id":3303,"depth":22,"text":5756},"Admin routes (settings\u002Fadmin submodule)",{"id":3407,"depth":22,"text":3408},{"id":3486,"depth":22,"text":3487},{"id":3521,"depth":22,"text":1768},{"id":3587,"depth":22,"text":3588},{"id":3619,"depth":22,"text":5762},"FlowDSL nodes (settings\u002Fflowdsl)",{"id":1131,"depth":16,"text":1131,"children":5764},[5765,5766],{"id":3698,"depth":22,"text":3699},{"id":3727,"depth":22,"text":1768},{"id":1147,"depth":16,"text":1147,"children":5768},[5769,5770,5771],{"id":3842,"depth":22,"text":3843},{"id":3902,"depth":22,"text":1768},{"id":3932,"depth":22,"text":3933},{"id":1163,"depth":16,"text":1163,"children":5773},[5774,5775,5776],{"id":4065,"depth":22,"text":3843},{"id":4110,"depth":22,"text":4111},{"id":4198,"depth":22,"text":1768},{"id":1179,"depth":16,"text":1179,"children":5778},[5779,5780],{"id":4277,"depth":22,"text":3843},{"id":4348,"depth":22,"text":1768},{"id":1195,"depth":16,"text":1195,"children":5782},[5783,5784,5785],{"id":4430,"depth":22,"text":1768},{"id":4461,"depth":22,"text":4462},{"id":4501,"depth":22,"text":4502},{"id":1347,"depth":16,"text":1347,"children":5787},[5788,5789,5790],{"id":4616,"depth":22,"text":4617},{"id":4717,"depth":22,"text":4718},{"id":4735,"depth":22,"text":1768},{"id":1364,"depth":16,"text":1364,"children":5792},[5793,5794],{"id":4888,"depth":22,"text":3843},{"id":5009,"depth":22,"text":1768},{"id":1211,"depth":16,"text":1211,"children":5796},[5797,5798,5799,5800,5801],{"id":5226,"depth":22,"text":5227},{"id":5241,"depth":22,"text":3843},{"id":5590,"depth":22,"text":5591},{"id":5633,"depth":22,"text":5634},{"id":5717,"depth":22,"text":5718},"Domain addon modules: scheduler, settings, storage, notifications, verification, links, metrics, search, i18n, apilog, content, workers, coordination, websockets, and flowexec.","md",null,{},{"order":22,"icon":147},{"title":144,"description":5802},"2DYMX5w4V1ihZCvtTLasDBpBDRyjtDBvHZW9_F2-F0Y",[5810,5812],{"title":140,"path":141,"stem":142,"description":5811,"order":16,"icon":46,"children":-1},"Redelay ships with 8 production-ready modules: auth, users, groups, health, OpenAPI, AsyncAPI, MCP, and module spec browser — all wired up automatically.",{"title":149,"path":150,"stem":151,"description":5813,"order":51,"icon":152,"children":-1},"Full API reference for the go-events library — transports, EventBus, filters, typed messages.",1790332223783]