<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Documentation on gobrave - Bioinformatics Analysis Platform</title><link>https://gobravedev.github.io/gobrave-doc/docs/</link><description>Recent content in Documentation on gobrave - Bioinformatics Analysis Platform</description><generator>Hugo</generator><language>en</language><lastBuildDate>Mon, 17 Aug 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://gobravedev.github.io/gobrave-doc/docs/index.xml" rel="self" type="application/rss+xml"/><item><title>Quick Start</title><link>https://gobravedev.github.io/gobrave-doc/docs/quick-start/</link><pubDate>Wed, 12 Aug 2026 00:00:00 +0800</pubDate><guid>https://gobravedev.github.io/gobrave-doc/docs/quick-start/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;This guide helps you boot gobrave locally in minutes, using the default Go server entrypoint.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Go 1.25 or newer&lt;/li&gt;
&lt;li&gt;A reachable database: SQLite (default), MySQL, or PostgreSQL&lt;/li&gt;
&lt;li&gt;Docker, k8s, or k3s if you want containerized analysis runtime&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="1-clone-and-enter-project"&gt;1. Clone And Enter Project&lt;/h2&gt;
&lt;div class="code-block"&gt;
 &lt;button class="code-copy" type="button" hidden aria-label="Copy code to clipboard"&gt;
 &lt;span class="code-copy-label" aria-hidden="true"&gt;Copy&lt;/span&gt;
 &lt;/button&gt;
 &lt;div class="highlight"&gt;&lt;div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/gobravedev/gobrave.git
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd gobrave&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
 &lt;/div&gt;&lt;h2 id="2-create-runtime-config"&gt;2. Create Runtime Config&lt;/h2&gt;
&lt;div class="code-block"&gt;
 &lt;button class="code-copy" type="button" hidden aria-label="Copy code to clipboard"&gt;
 &lt;span class="code-copy-label" aria-hidden="true"&gt;Copy&lt;/span&gt;
 &lt;/button&gt;
 &lt;div class="highlight"&gt;&lt;div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cp config.example.yml config.yml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
 &lt;/div&gt;&lt;p&gt;Edit at least:&lt;/p&gt;</description></item><item><title>Configuration</title><link>https://gobravedev.github.io/gobrave-doc/docs/configuration/</link><pubDate>Wed, 12 Aug 2026 00:00:00 +0800</pubDate><guid>https://gobravedev.github.io/gobrave-doc/docs/configuration/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;gobrave loads configuration from defaults, then merges values from &lt;code&gt;config.yml&lt;/code&gt;, and finally applies CLI overrides.&lt;/p&gt;
&lt;h2 id="resolution-order"&gt;Resolution Order&lt;/h2&gt;
&lt;p&gt;Configuration priority is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Built-in defaults&lt;/li&gt;
&lt;li&gt;&lt;code&gt;config.yml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;CLI flags (&lt;code&gt;--port&lt;/code&gt;, &lt;code&gt;--db-driver&lt;/code&gt;, &lt;code&gt;--runtime&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="config-file-location"&gt;Config File Location&lt;/h2&gt;
&lt;p&gt;At startup, config path is resolved in this order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;--config&lt;/code&gt; CLI flag&lt;/li&gt;
&lt;li&gt;external path resolution for &lt;code&gt;config.yml&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="core-sections"&gt;Core Sections&lt;/h2&gt;
&lt;h3 id="server"&gt;&lt;code&gt;server&lt;/code&gt;&lt;/h3&gt;
&lt;div class="code-block"&gt;
 &lt;button class="code-copy" type="button" hidden aria-label="Copy code to clipboard"&gt;
 &lt;span class="code-copy-label" aria-hidden="true"&gt;Copy&lt;/span&gt;
 &lt;/button&gt;
 &lt;div class="highlight"&gt;&lt;div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7ee787"&gt;server&lt;/span&gt;:&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;host&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;0.0.0.0&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;port&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;8082&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;log_path&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;logs/server.log&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
 &lt;/div&gt;&lt;h3 id="database"&gt;&lt;code&gt;database&lt;/code&gt;&lt;/h3&gt;
&lt;div class="code-block"&gt;
 &lt;button class="code-copy" type="button" hidden aria-label="Copy code to clipboard"&gt;
 &lt;span class="code-copy-label" aria-hidden="true"&gt;Copy&lt;/span&gt;
 &lt;/button&gt;
 &lt;div class="highlight"&gt;&lt;div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;5
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;6
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;7
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;8
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7ee787"&gt;database&lt;/span&gt;:&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;driver&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;sqlite&lt;/span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# sqlite | mysql | postgres&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;host&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;127.0.0.1&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;port&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;&amp;#34;5432&amp;#34;&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;user&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;postgres&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;password&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;name&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;postgres&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;ssl_mode&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;disable&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;path&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# used by sqlite&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
 &lt;/div&gt;&lt;h3 id="container"&gt;&lt;code&gt;container&lt;/code&gt;&lt;/h3&gt;
&lt;div class="code-block"&gt;
 &lt;button class="code-copy" type="button" hidden aria-label="Copy code to clipboard"&gt;
 &lt;span class="code-copy-label" aria-hidden="true"&gt;Copy&lt;/span&gt;
 &lt;/button&gt;
 &lt;div class="highlight"&gt;&lt;div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt; 1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt; 2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt; 3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt; 4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt; 5
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt; 6
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt; 7
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt; 8
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt; 9
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;10
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;11
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;12
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;13
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7ee787"&gt;container&lt;/span&gt;:&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;runtime&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;docker&lt;/span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# docker | k8s | k3s&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;kubernetes&lt;/span&gt;:&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;namespace&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;default&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;kubeconfig&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;in_cluster&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#79c0ff"&gt;false&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;refresh_image_status_on_start&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#79c0ff"&gt;true&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;recover_running_dag_on_start&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#79c0ff"&gt;true&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;cleanup_dag_node_containers_before_start&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#79c0ff"&gt;true&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;delete_container_on_node_success&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#79c0ff"&gt;true&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;dag_node_cleanup_on_failed&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;stop&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;dag_node_cleanup_on_dag_finished&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;delete&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;create_queue_max_concurrency&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;3&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;create_queue_max_pending&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;50&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
 &lt;/div&gt;&lt;h3 id="route"&gt;&lt;code&gt;route&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;route.registry&lt;/code&gt; controls route registration strategy:&lt;/p&gt;</description></item><item><title>Architecture</title><link>https://gobravedev.github.io/gobrave-doc/docs/architecture/</link><pubDate>Wed, 12 Aug 2026 00:00:00 +0800</pubDate><guid>https://gobravedev.github.io/gobrave-doc/docs/architecture/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;gobrave is a modular Go backend centered around project-scoped bioinformatics workflows, data assets, and containerized execution.&lt;/p&gt;
&lt;h2 id="high-level-components"&gt;High-Level Components&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TD
 UI[Web / API Clients] --&amp;gt; API[GIN Router &amp;#43; Handlers]
 API --&amp;gt; APP[Application Services]
 APP --&amp;gt; DOM[Domain Managers]
 DOM --&amp;gt; RT[Container Runtime Registry]
 DOM --&amp;gt; REPO[Repository Layer]
 REPO --&amp;gt; DB[(MySQL/Postgres/SQLite)]

 APP --&amp;gt; BUS[In-Memory Event Bus]
 BUS --&amp;gt; WK[Outbox Dispatcher &amp;#43; Workers]
 WK --&amp;gt; RT&lt;/pre&gt;
&lt;h2 id="runtime-composition"&gt;Runtime Composition&lt;/h2&gt;
&lt;p&gt;At startup, gobrave builds a dependency container and wires:&lt;/p&gt;</description></item><item><title>Container Management</title><link>https://gobravedev.github.io/gobrave-doc/docs/containers/</link><pubDate>Wed, 12 Aug 2026 00:00:00 +0800</pubDate><guid>https://gobravedev.github.io/gobrave-doc/docs/containers/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;gobrave uses a unified container management model for interactive apps and workflow runtime tasks.&lt;/p&gt;
&lt;h2 id="runtime-backends"&gt;Runtime Backends&lt;/h2&gt;
&lt;p&gt;Configured by &lt;code&gt;container.runtime&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;k8s&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;k3s&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Runtime resolution is centralized in the container runtime registry.&lt;/p&gt;
&lt;h2 id="main-entities"&gt;Main Entities&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Container image: image metadata and pull policy&lt;/li&gt;
&lt;li&gt;Container template: reusable launch definition&lt;/li&gt;
&lt;li&gt;App session: user-facing running environment based on template&lt;/li&gt;
&lt;li&gt;Container instance: runtime lifecycle state record&lt;/li&gt;
&lt;li&gt;Outbox event: durable async lifecycle request&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="core-api-groups"&gt;Core API Groups&lt;/h2&gt;
&lt;h3 id="image-and-template"&gt;Image And Template&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/container/image/*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/container/template/*&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="app-session-lifecycle"&gt;App Session Lifecycle&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/container/app-session/create&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/container/app-session/start&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/container/app-session/stop&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/container/app-session/delete&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="runtime-monitoring"&gt;Runtime Monitoring&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/container/runtime/monitoring/list&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/container/queue/status&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/container/outbox/list-by-page&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="lifecycle-model"&gt;Lifecycle Model&lt;/h2&gt;
&lt;p&gt;Typical flow:&lt;/p&gt;</description></item><item><title>Data Management</title><link>https://gobravedev.github.io/gobrave-doc/docs/data/</link><pubDate>Wed, 12 Aug 2026 00:00:00 +0800</pubDate><guid>https://gobravedev.github.io/gobrave-doc/docs/data/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;The gobrave data model is project-centric and designed for reproducible workflow input assembly.&lt;/p&gt;
&lt;h2 id="core-data-objects"&gt;Core Data Objects&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Dataset: logical collection of biological assets&lt;/li&gt;
&lt;li&gt;Sample: biological sample metadata record&lt;/li&gt;
&lt;li&gt;File: physical or logical file metadata&lt;/li&gt;
&lt;li&gt;Relations:&lt;/li&gt;
&lt;li&gt;project &amp;lt;-&amp;gt; dataset&lt;/li&gt;
&lt;li&gt;dataset &amp;lt;-&amp;gt; sample&lt;/li&gt;
&lt;li&gt;dataset &amp;lt;-&amp;gt; file&lt;/li&gt;
&lt;li&gt;sample &amp;lt;-&amp;gt; file&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="api-surface"&gt;API Surface&lt;/h2&gt;
&lt;p&gt;Data endpoints are exposed under &lt;code&gt;/api/v1&lt;/code&gt; and grouped as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/data/dataset/*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/data/project-dataset/*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/data/file/*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/data/sample/*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/data/dataset-file/*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/data/sample-file/*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/data/dataset-sample/*&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="typical-data-workflow"&gt;Typical Data Workflow&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Create project.&lt;/li&gt;
&lt;li&gt;Create datasets.&lt;/li&gt;
&lt;li&gt;Register samples and files.&lt;/li&gt;
&lt;li&gt;Bind sample/file roles (for example FASTQ_R1, FASTQ_R2).&lt;/li&gt;
&lt;li&gt;Link assets into dataset relationships.&lt;/li&gt;
&lt;li&gt;Build workflow input selectors from these relations.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="workflow-integration"&gt;Workflow Integration&lt;/h2&gt;
&lt;p&gt;The workflow engine can resolve structured inputs from managed data:&lt;/p&gt;</description></item><item><title>Container Queue Monitoring</title><link>https://gobravedev.github.io/gobrave-doc/docs/container-monitoring/</link><pubDate>Tue, 11 Aug 2026 00:00:00 +0800</pubDate><guid>https://gobravedev.github.io/gobrave-doc/docs/container-monitoring/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;This document explains how gobrave exposes container create-queue health, how to interpret each metric, and how the queue status is computed internally.&lt;/p&gt;
&lt;p&gt;The monitoring endpoint is designed for operators and UI polling clients that need to answer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is queue mode enabled?&lt;/li&gt;
&lt;li&gt;How many create slots are currently occupied?&lt;/li&gt;
&lt;li&gt;How many create requests are waiting?&lt;/li&gt;
&lt;li&gt;What are the configured hard limits?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="architecture"&gt;Architecture&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 subgraph Client[Client Layer]
 UI[Web UI / Ops Script];
 end;

 subgraph API[API Layer]
 H[ContainerHandler.GetQueueStatus];
 end;

 subgraph Worker[Queue Layer]
 W[ContainerCreateWorker];
 QS[QueueStatus];
 end;

 subgraph Data[Data Layer]
 DB[(ContainerInstance &amp;#43; OutboxEvent)];
 end;

 UI --&amp;gt;|GET /container/queue/status| H;
 H --&amp;gt;|QueueStatus call| W;
 W --&amp;gt; QS;
 QS --&amp;gt;|CountContainerInstanceByStatuses| DB;
 QS --&amp;gt;|CountPendingOutboxEventsByType ContainerCreateRequest| DB;
 H --&amp;gt;|JSON response| UI;&lt;/pre&gt;
&lt;h3 id="boot-time-wiring-for-fault-tolerance-and-accuracy"&gt;Boot-Time Wiring for Fault Tolerance and Accuracy&lt;/h3&gt;
&lt;p&gt;The queue-monitoring path relies on explicit startup wiring in the dependency container.
This wiring is what makes queue status resilient and restart-safe, not just observable.&lt;/p&gt;</description></item><item><title>Container Worker Queue System</title><link>https://gobravedev.github.io/gobrave-doc/docs/container-worker/</link><pubDate>Tue, 11 Aug 2026 00:00:00 +0800</pubDate><guid>https://gobravedev.github.io/gobrave-doc/docs/container-worker/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;gobrave uses an outbox-based worker queue to manage all container lifecycle operations asynchronously. Instead of directly calling the container runtime (Docker/K8s), every operation — &lt;strong&gt;create&lt;/strong&gt;, &lt;strong&gt;start&lt;/strong&gt;, &lt;strong&gt;stop&lt;/strong&gt;, and &lt;strong&gt;delete&lt;/strong&gt; — is enqueued through the &lt;code&gt;ContainerCreateWorker&lt;/code&gt; and processed asynchronously via the event bus.&lt;/p&gt;
&lt;p&gt;This design provides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Concurrency control&lt;/strong&gt; — limits the number of simultaneous container creations via a semaphore.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fault tolerance&lt;/strong&gt; — failed operations are retried automatically via the outbox pattern.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consistent state machine&lt;/strong&gt; — all operations follow the same FSM-driven lifecycle.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Decoupling&lt;/strong&gt; — the HTTP handler returns immediately, and the container operation happens in the background.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="architecture"&gt;Architecture&lt;/h2&gt;
&lt;h3 id="core-component-architecture"&gt;Core Component Architecture&lt;/h3&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 subgraph API[API Layer]
 H[HTTP Handlers]
 end

 subgraph Core[Control Plane]
 M[ContainerManager\nCreateByTemplate / Start / Stop / Delete / OnEvent]
 D[OutboxDispatcher\nPoll pending outbox]
 W[ContainerCreateWorker\nHandle create/start/stop/delete requests]
 R[RunRuntimeReconciler\nPeriodic monitor recovery]
 end

 subgraph Data[Data Layer]
 DB[(ContainerInstance &amp;#43; OutboxEvent &amp;#43; ContainerEvent)]
 end

 subgraph Runtime[Runtime Layer]
 RT[Docker / Kubernetes Runtime]
 end

 H --&amp;gt;|User request| M
 M --&amp;gt;|Tx: write instance &amp;#43; outbox request| DB

 D --&amp;gt;|Fetch pending requests| DB
 D --&amp;gt;|Publish Outbox*RequestEvent| W

 W --&amp;gt;|Execute Create/Start/Stop/Delete| RT
 RT --&amp;gt;|ContainerStarted/Exited/Failed/...| M
 M --&amp;gt;|FSM transition &amp;#43; event persistence| DB

 R --&amp;gt;|RecoverRuntimeMonitoring| RT
 R --&amp;gt;|Scan active instances| DB&lt;/pre&gt;
&lt;p&gt;This diagram shows three key loops:&lt;/p&gt;</description></item><item><title>Runtime Monitor Recovery After Restart</title><link>https://gobravedev.github.io/gobrave-doc/docs/runtime-monitor-recovery/</link><pubDate>Tue, 11 Aug 2026 00:00:00 +0800</pubDate><guid>https://gobravedev.github.io/gobrave-doc/docs/runtime-monitor-recovery/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;This document explains how gobrave restores runtime lifecycle monitoring after a process restart.&lt;/p&gt;
&lt;p&gt;The current recovery path is based on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ContainerManager.RunRuntimeReconciler(...)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ContainerManager.RecoverRuntimeMonitoring(...)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;runtime &lt;code&gt;Monitor(ctx, runtimeID)&lt;/code&gt; implementations&lt;/li&gt;
&lt;li&gt;process-global &lt;code&gt;MonitoringRegistry&lt;/code&gt; idempotency guard&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The goal is to reattach monitoring for recoverable container instances and continue emitting runtime events into the normal state transition pipeline.&lt;/p&gt;
&lt;h2 id="why-recovery-is-needed"&gt;Why Recovery Is Needed&lt;/h2&gt;
&lt;p&gt;After service restart, in-memory monitor goroutines are lost.
Without recovery, runtime state can change while persisted &lt;code&gt;ContainerInstance&lt;/code&gt; status stays stale.&lt;/p&gt;</description></item><item><title>Kubernetes Runtime Architecture</title><link>https://gobravedev.github.io/gobrave-doc/docs/k8s-runtime-architecture/</link><pubDate>Wed, 12 Aug 2026 00:00:00 +0800</pubDate><guid>https://gobravedev.github.io/gobrave-doc/docs/k8s-runtime-architecture/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;This document explains the current Kubernetes runtime architecture used by gobrave.&lt;/p&gt;
&lt;p&gt;It is based on the runtime implementation in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;internal/container_runtime/kubernetes/runtime.go&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;internal/container_runtime/kubernetes/monitor_v2.go&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The runtime supports two workload kinds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;deployment&lt;/code&gt; (long-running service)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;job&lt;/code&gt; (run-to-completion task)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="architecture-goals"&gt;Architecture Goals&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Keep runtime monitoring efficient at scale.&lt;/li&gt;
&lt;li&gt;Avoid duplicate monitor loops for the same runtime ID.&lt;/li&gt;
&lt;li&gt;Convert Kubernetes workload state into stable gobrave runtime events.&lt;/li&gt;
&lt;li&gt;Keep lifecycle behavior predictable for users (&lt;code&gt;start&lt;/code&gt;, &lt;code&gt;stop&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt;, &lt;code&gt;logs&lt;/code&gt;, &lt;code&gt;inspect&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="high-level-flow"&gt;High-Level Flow&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TD
 A[Create ContainerSpec] --&amp;gt; B[KubernetesRuntime.Create]
 B --&amp;gt; C{WorkloadKind}
 C --&amp;gt;|deployment| D[Create Deployment]
 C --&amp;gt;|job| E[Create Job]
 D --&amp;gt; F[Optional Service -svc]
 D --&amp;gt; G[Return runtimeID]
 E --&amp;gt; G

 H[Start or Recovery] --&amp;gt; I[KubernetesRuntime.Monitor]
 I --&amp;gt; J{MarkIfNotMonitoring}
 J --&amp;gt;|already monitoring| K[Return idempotently]
 J --&amp;gt;|new| L[Start shared informers once]
 L --&amp;gt; M[Register subscription kind namespace name]
 M --&amp;gt; N[Deployment or Job events]
 N --&amp;gt; O[Emit RuntimeEvent]
 O --&amp;gt; P[ContainerManager state transition]&lt;/pre&gt;
&lt;h2 id="runtime-id-model"&gt;Runtime ID Model&lt;/h2&gt;
&lt;p&gt;Runtime IDs are encoded as:&lt;/p&gt;</description></item><item><title>Event Bus Subscribers (event_handlers)</title><link>https://gobravedev.github.io/gobrave-doc/docs/event-bus-subscribers/</link><pubDate>Tue, 11 Aug 2026 00:00:00 +0800</pubDate><guid>https://gobravedev.github.io/gobrave-doc/docs/event-bus-subscribers/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;This document explains the user-facing architecture for all handlers subscribed to the shared event bus through the event_handlers DI group.&lt;/p&gt;
&lt;p&gt;Registered subscribers in this group are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NewRouteRegistryHandler&lt;/li&gt;
&lt;li&gt;NewAppSessionEventHandler&lt;/li&gt;
&lt;li&gt;NewDagRuntimeEventNotifier&lt;/li&gt;
&lt;li&gt;ContainerCreateWorker&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These handlers are all subscribed during startup by iterating the event_handlers group and calling bus.Subscribe(handler).&lt;/p&gt;
&lt;h2 id="subscription-architecture"&gt;Subscription Architecture&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 subgraph Startup[Startup Wiring]
 C[BuildContainer]
 G[event_handlers group]
 B[event.Bus]
 end

 subgraph Subscribers[Subscribers]
 R[RouteRegistryHandler\nNewRouteRegistryHandler]
 A[AppSessionEventHandler\nNewAppSessionEventHandler]
 D[DagRuntimeEventNotifier\nNewDagRuntimeEventNotifier]
 W[ContainerCreateWorker]
 end

 subgraph Producers[Main Event Producers]
 O[OutboxDispatcher]
 M[ContainerManager / Runtime Events]
 DG[DAG Runtime]
 end

 C --&amp;gt; G
 C --&amp;gt; B
 G --&amp;gt;|for each handler| B

 O --&amp;gt;|OutboxCreateRequestEvent\nOutboxStartRequestEvent\nOutboxStopRequestEvent\nOutboxDeleteRequestEvent| B
 M --&amp;gt;|ContainerEvent| B
 DG --&amp;gt;|dag.RuntimeEvent| B

 B --&amp;gt; R
 B --&amp;gt; A
 B --&amp;gt; D
 B --&amp;gt; W&lt;/pre&gt;
&lt;h2 id="what-each-subscriber-does"&gt;What Each Subscriber Does&lt;/h2&gt;
&lt;h3 id="1-newrouteregistryhandler"&gt;1) NewRouteRegistryHandler&lt;/h3&gt;
&lt;p&gt;Primary role: keeps external route records in sync with App Session container lifecycle.&lt;/p&gt;</description></item><item><title>Container User Selection</title><link>https://gobravedev.github.io/gobrave-doc/docs/container-user-selection/</link><pubDate>Mon, 17 Aug 2026 00:00:00 +0800</pubDate><guid>https://gobravedev.github.io/gobrave-doc/docs/container-user-selection/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;This document explains when gobrave explicitly sets a container user and how that behavior differs between Docker and Kubernetes runtimes.&lt;/p&gt;
&lt;h2 id="where-the-user-value-comes-from"&gt;Where The User Value Comes From&lt;/h2&gt;
&lt;p&gt;The user value is populated while preparing a DAG node runtime spec.&lt;/p&gt;
&lt;p&gt;Input variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;USERID&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GROUPID&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If &lt;code&gt;USERID&lt;/code&gt; is empty, gobrave does not set a runtime user.&lt;/p&gt;
&lt;h2 id="when-user-is-specified"&gt;When User Is Specified&lt;/h2&gt;
&lt;h3 id="case-1-docker-runtime"&gt;Case 1: Docker Runtime&lt;/h3&gt;
&lt;p&gt;Condition:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;runtime name is &lt;code&gt;docker&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;USERID&lt;/code&gt; is present&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Behavior:&lt;/p&gt;</description></item><item><title>Node Completion Bootstrap</title><link>https://gobravedev.github.io/gobrave-doc/docs/node-completion-bootstrap/</link><pubDate>Tue, 11 Aug 2026 00:00:00 +0800</pubDate><guid>https://gobravedev.github.io/gobrave-doc/docs/node-completion-bootstrap/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;NodeCompletionBootstrap is the startup wiring component that guarantees DAG analysis nodes are eventually finalized when their runtime containers reach terminal states.&lt;/p&gt;
&lt;p&gt;It separates infrastructure concerns from DAG orchestration logic by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;constructing NodeCompletionCoordinator with cleanup policies&lt;/li&gt;
&lt;li&gt;subscribing the coordinator to container lifecycle events&lt;/li&gt;
&lt;li&gt;starting a background poll loop for reconciliation fallback&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This ensures node finalization still happens after process restarts, missed events, or transient bus delivery gaps.&lt;/p&gt;
&lt;h2 id="architecture"&gt;Architecture&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 subgraph Startup[Startup Wiring]
 C[DI Container Build]
 B[NodeCompletionBootstrap]
 BUS[event.Bus]
 end

 subgraph Coordinator[Reconciliation Engine]
 N[NodeCompletionCoordinator]
 P[Poll Loop every 2s]
 EH[Event Handler for ContainerStopped or ContainerFailed]
 end

 subgraph Data[Data Layer]
 CR[(ContainerInstance Repository)]
 AR[(AnalysisNode Repository)]
 end

 subgraph Runtime[Node Finalization]
 RE[RuntimeEngine CompleteNode]
 PUB[Publish DAG RuntimeEvent]
 end

 subgraph Cleanup[Container Cleanup]
 CM[ContainerManager Stop or Delete]
 CFG[container config policies]
 end

 C --&amp;gt; B
 B --&amp;gt;|Subscribe| BUS
 B --&amp;gt;|Start goroutine| N

 BUS --&amp;gt; EH
 N --&amp;gt; EH
 N --&amp;gt; P

 EH --&amp;gt; CR
 P --&amp;gt; CR
 CR --&amp;gt; AR
 AR --&amp;gt; RE
 RE --&amp;gt; PUB

 CFG --&amp;gt; B
 B --&amp;gt; CM
 N --&amp;gt;|on failed node| CM
 N --&amp;gt;|on successful node if enabled| CM&lt;/pre&gt;
&lt;h2 id="startup-lifecycle"&gt;Startup Lifecycle&lt;/h2&gt;
&lt;p&gt;At application startup:&lt;/p&gt;</description></item><item><title>Outbox Dispatcher and Worker Concurrency</title><link>https://gobravedev.github.io/gobrave-doc/docs/outbox-dispatcher-worker-concurrency/</link><pubDate>Tue, 11 Aug 2026 00:00:00 +0800</pubDate><guid>https://gobravedev.github.io/gobrave-doc/docs/outbox-dispatcher-worker-concurrency/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;This document explains how &lt;code&gt;RunOutboxDispatcher&lt;/code&gt;, &lt;code&gt;OutboxDispatcher&lt;/code&gt;, and &lt;code&gt;ContainerCreateWorker&lt;/code&gt;
work together to implement queue backpressure and runtime concurrency control for &lt;code&gt;ContainerInstance&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The key goals are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Limit how many container create/start operations can run at the same time (&lt;code&gt;maxConcurrency&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Limit how many create requests can wait in queue (&lt;code&gt;maxPending&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Keep requests asynchronous by using &lt;code&gt;OutboxEvent&lt;/code&gt; + event bus.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="components-and-responsibilities"&gt;Components and Responsibilities&lt;/h2&gt;
&lt;h3 id="runoutboxdispatcher"&gt;&lt;code&gt;RunOutboxDispatcher&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Starts the dispatcher loop in a goroutine.&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;dispatcher.Start(context.Background())&lt;/code&gt; asynchronously.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
 &lt;button class="code-copy" type="button" hidden aria-label="Copy code to clipboard"&gt;
 &lt;span class="code-copy-label" aria-hidden="true"&gt;Copy&lt;/span&gt;
 &lt;/button&gt;
 &lt;div class="highlight"&gt;&lt;div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ff7b72"&gt;func&lt;/span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#d2a8ff;font-weight:bold"&gt;RunOutboxDispatcher&lt;/span&gt;(dispatcher&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#ff7b72;font-weight:bold"&gt;*&lt;/span&gt;OutboxDispatcher)&lt;span style="color:#6e7681"&gt; &lt;/span&gt;{&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#ff7b72"&gt;go&lt;/span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;dispatcher.&lt;span style="color:#d2a8ff;font-weight:bold"&gt;Start&lt;/span&gt;(context.&lt;span style="color:#d2a8ff;font-weight:bold"&gt;Background&lt;/span&gt;())&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
 &lt;/div&gt;&lt;h3 id="outboxdispatcher"&gt;&lt;code&gt;OutboxDispatcher&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Polls pending outbox rows (&lt;code&gt;ListPendingOutboxEvent&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Marks each request as &lt;code&gt;processing&lt;/code&gt; before publish.&lt;/li&gt;
&lt;li&gt;Publishes typed request events to the event bus:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;OutboxCreateRequestEvent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OutboxStartRequestEvent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OutboxStopRequestEvent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OutboxDeleteRequestEvent&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="containercreateworker"&gt;&lt;code&gt;ContainerCreateWorker&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Subscribes to bus events above.&lt;/li&gt;
&lt;li&gt;Handles create/start/stop/delete asynchronously.&lt;/li&gt;
&lt;li&gt;For create/start requests, uses capacity checks via &lt;code&gt;acquireCapacityAndTransition&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Marks outbox &lt;code&gt;sent&lt;/code&gt; on success, or back to &lt;code&gt;pending&lt;/code&gt; on retriable failure.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="event-bus-flow"&gt;Event Bus Flow&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[API / Manager enqueue] --&amp;gt; B[(go_outbox_event)]
 B --&amp;gt; C[OutboxDispatcher poll]
 C --&amp;gt; D[mark processing]
 D --&amp;gt; E[event.Bus publish]
 E --&amp;gt; F[ContainerCreateWorker Handle]
 F --&amp;gt; G{capacity &amp;#43; state valid?}
 G -- yes --&amp;gt; H[create or start container]
 G -- no --&amp;gt; I[keep request for retry]
 H --&amp;gt; J[mark outbox sent]
 I --&amp;gt; K[mark outbox pending]
 K --&amp;gt; C&lt;/pre&gt;
&lt;h2 id="containerinstance-status-and-queue-behavior"&gt;&lt;code&gt;ContainerInstance&lt;/code&gt; Status and Queue Behavior&lt;/h2&gt;
&lt;h3 id="create-request-path"&gt;Create request path&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;A create API path performs queue check and enqueue in a single DB transaction.&lt;/li&gt;
&lt;li&gt;The transaction checks pending create requests against &lt;code&gt;maxPending&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If pending create requests are already greater than or equal to &lt;code&gt;maxPending&lt;/code&gt;, the transaction returns error and rolls back, so no &lt;code&gt;ContainerInstance&lt;/code&gt; and no &lt;code&gt;OutboxEvent&lt;/code&gt; are created.&lt;/li&gt;
&lt;li&gt;If accepted, the same transaction writes:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ContainerInstance{status: pending}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OutboxEvent{Type: ContainerCreateRequest, Status: pending}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="5"&gt;
&lt;li&gt;&lt;code&gt;OutboxDispatcher&lt;/code&gt; publishes &lt;code&gt;OutboxCreateRequestEvent&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ContainerCreateWorker&lt;/code&gt; handles the event and calls &lt;code&gt;acquireCapacityAndTransition&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="capacity-decision-maxconcurrency"&gt;Capacity decision (&lt;code&gt;maxConcurrency&lt;/code&gt;)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The worker counts active container instances occupying concurrency slots.&lt;/li&gt;
&lt;li&gt;If active count is less than &lt;code&gt;maxConcurrency&lt;/code&gt;, transition is allowed and container goes to &lt;code&gt;creating&lt;/code&gt;, then &lt;code&gt;running&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If active count is greater than or equal to &lt;code&gt;maxConcurrency&lt;/code&gt;, capacity is denied and request is not executed in this round.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Result when denied:&lt;/p&gt;</description></item></channel></rss>