<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>文章 on 紙上集</title><link>https://c6a81954.notes-54i.pages.dev/posts/</link><description>Recent content in 文章 on 紙上集</description><generator>Hugo</generator><language>zh-tw</language><lastBuildDate>Sat, 05 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://c6a81954.notes-54i.pages.dev/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>Operations and Hospital Collaboration Guide</title><link>https://c6a81954.notes-54i.pages.dev/posts/operations-hospital-collaboration-guide-en/</link><pubDate>Sat, 05 Sep 2026 00:00:00 +0000</pubDate><guid>https://c6a81954.notes-54i.pages.dev/posts/operations-hospital-collaboration-guide-en/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Traditional Chinese version: [[content/posts/operations-hospital-collaboration-guide]]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="1-purpose"&gt;1. Purpose&lt;/h2&gt;
&lt;p&gt;This guide is intended for the TAMS Backend, Hospital Integration, RMF/Robot Integration, QA, and Operations teams. It describes the actual boundaries of the current Modular Monolith, how Operations and Hospital communicate, and the rules that all contributors must follow when changing the codebase.&lt;/p&gt;
&lt;p&gt;The system is still deployed as one NestJS process, one npm package, and one versioned release. Modules communicate through NestJS dependency injection and in-process method calls. There are no internal HTTP calls, message brokers, or additional worker frameworks between modules.&lt;/p&gt;</description></item><item><title>Operations 與 Hospital 協作開發指南</title><link>https://c6a81954.notes-54i.pages.dev/posts/operations-hospital-collaboration-guide/</link><pubDate>Sat, 05 Sep 2026 00:00:00 +0000</pubDate><guid>https://c6a81954.notes-54i.pages.dev/posts/operations-hospital-collaboration-guide/</guid><description>&lt;blockquote&gt;
&lt;p&gt;English version: [[Users/rubinette/Vaults/notes/content/posts/operations-hospital-collaboration-guide-en]]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="1-文件目的"&gt;1. 文件目的&lt;/h2&gt;
&lt;p&gt;本文件提供給 TAMS Backend、Hospital Integration、RMF/Robot Integration、QA 與維運團隊，說明目前 Modular Monolith 的實際程式邊界、Operations 與 Hospital 的互動方式，以及修改程式時必須共同遵守的規則。&lt;/p&gt;
&lt;p&gt;本架構仍部署為單一 NestJS process、單一 npm package 與單一版本。模組之間使用 NestJS dependency injection 與記憶體內方法呼叫，不透過內部 HTTP、message broker 或額外 worker framework。&lt;/p&gt;
&lt;p&gt;核心原則如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hospital 決定「醫院流程要求什麼」，Operations 保證「機器人任務如何安全執行」，Adapters 處理「如何與外部技術系統溝通」。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="2-快速判斷程式應該放在哪裡"&gt;2. 快速判斷：程式應該放在哪裡&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;需求&lt;/th&gt;
					&lt;th&gt;所屬位置&lt;/th&gt;
					&lt;th&gt;範例&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;通用任務、機器人或設施規則&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;src/operations/&amp;lt;feature&amp;gt;&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;任務取消、派工、機器人可用性、充電站查找&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;跨多個 Operations feature 的背景流程&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;src/operations/workflows&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Queue Worker、Robot Keeper&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;CSH/CMP/HIS 或醫院專屬流程&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;src/csh-hospital&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;緊急返回藥局、員工同步、藥品查詢&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;HTTP validation 與 response mapping&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;src/product-api&lt;/code&gt;、&lt;code&gt;src/csh-hospital/api&lt;/code&gt; 或現有 controller&lt;/td&gt;
					&lt;td&gt;DTO、guard、Swagger decorator&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;MongoDB、Redis、RMF、Axios、ROS、Socket.IO&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;src/adapters&lt;/code&gt; 或既有 infrastructure layer&lt;/td&gt;
					&lt;td&gt;repository、RMF adapter、robot-control adapter&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;登入、JWT、RBAC、session、audit&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;src/access&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Actor、permission、使用者管理&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;多個模組共同使用的純粹型別&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;src/domain&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;與單一 Operations feature 無關的共用型別&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;若需求包含醫院名稱判斷，例如 &lt;code&gt;if (hospital === 'CSH')&lt;/code&gt;，不要直接加入 Operations。先確認差異是否能由 Hospital config 表達；只有行為真的不同時，才建立小而明確的跨模組契約。&lt;/p&gt;</description></item><item><title>多醫院機器人平台</title><link>https://c6a81954.notes-54i.pages.dev/posts/%E5%A4%9A%E9%86%AB%E9%99%A2%E6%A9%9F%E5%99%A8%E4%BA%BA%E5%B9%B3%E5%8F%B0%E6%9E%B6%E6%A7%8B%E8%A6%8F%E5%8A%83/</link><pubDate>Thu, 03 Sep 2026 00:00:00 +0000</pubDate><guid>https://c6a81954.notes-54i.pages.dev/posts/%E5%A4%9A%E9%86%AB%E9%99%A2%E6%A9%9F%E5%99%A8%E4%BA%BA%E5%B9%B3%E5%8F%B0%E6%9E%B6%E6%A7%8B%E8%A6%8F%E5%8A%83/</guid><description>&lt;h2 id="1-架構定位"&gt;1. 架構定位&lt;/h2&gt;
&lt;p&gt;採用：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Modular Monolith + Hexagonal Architecture + Clean Dependency Rule&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;原則：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;目前維持單一 NestJS 應用。&lt;/li&gt;
&lt;li&gt;使用模組邊界隔離業務能力。&lt;/li&gt;
&lt;li&gt;使用 Ports &amp;amp; Adapters 隔離外部系統。&lt;/li&gt;
&lt;li&gt;程式碼依賴只能指向 Application、Domain 與 Ports。&lt;/li&gt;
&lt;li&gt;不拆微服務、不拆資料庫。&lt;/li&gt;
&lt;li&gt;第二家醫院出現前，不建立額外 npm packages 或 repositories。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="2-目標結構"&gt;2. 目標結構&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;src/
├── operations/
│ ├── task/
│ ├── robot/
│ ├── fleet/
│ ├── device/
│ ├── maps/
│ ├── facility/
│ ├── charging/
│ ├── application/
│ ├── domain/
│ ├── ports/
│ └── operations.module.ts
│
├── access/
│ ├── authentication/
│ ├── authorization/
│ ├── users/
│ ├── sessions/
│ ├── audit/
│ └── access.module.ts
│
├── product-api/
│ ├── controllers/
│ ├── gateways/
│ ├── dto/
│ └── product-api.module.ts
│
├── adapters/
│ ├── rmf/
│ ├── robot-control/
│ ├── fleet-manager/
│ ├── mongo/
│ ├── redis/
│ ├── websocket/
│ ├── scheduler/
│ └── adapters.module.ts
│
├── hospital/
│ └── csh/
│ ├── controllers/
│ ├── workflows/
│ ├── policies/
│ ├── integrations/
│ ├── config/
│ └── csh-hospital.module.ts
│
├── app.module.ts
└── main.ts&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id="3-核心依賴方向"&gt;3. 核心依賴方向&lt;/h2&gt;

&lt;figure class="mermaid-diagram" data-mermaid&gt;
 &lt;pre class="mermaid-diagram__source"&gt;&lt;code&gt;flowchart TB
 API[&amp;#34;Product API&amp;#34;] --&amp;gt; APP[&amp;#34;Application Services&amp;#34;]
 HOSPITAL[&amp;#34;Hospital Workflows&amp;#34;] --&amp;gt; APP
 WORKER[&amp;#34;Workers / Schedulers&amp;#34;] --&amp;gt; APP
 RMF_IN[&amp;#34;RMF State Listener&amp;#34;] --&amp;gt; APP

 APP --&amp;gt; DOMAIN[&amp;#34;Domain Rules&amp;#34;]
 APP --&amp;gt; PORTS[&amp;#34;Ports&amp;#34;]

 RMF_OUT[&amp;#34;RMF Adapter&amp;#34;] --&amp;gt; PORTS
 ROBOT[&amp;#34;Robot Control Adapter&amp;#34;] --&amp;gt; PORTS
 FLEET[&amp;#34;Fleet Manager Adapter&amp;#34;] --&amp;gt; PORTS
 MONGO[&amp;#34;Mongo Adapter&amp;#34;] --&amp;gt; PORTS
 REDIS[&amp;#34;Redis Adapter&amp;#34;] --&amp;gt; PORTS
 WS[&amp;#34;WebSocket Adapter&amp;#34;] --&amp;gt; PORTS&lt;/code&gt;&lt;/pre&gt;
&lt;/figure&gt;
&lt;p&gt;允許：&lt;/p&gt;</description></item><item><title>PolyMedX HTTPS Edge Proxy 教學</title><link>https://c6a81954.notes-54i.pages.dev/posts/polymedx-https-edge-proxy-%E6%95%99%E5%AD%B8/</link><pubDate>Mon, 17 Aug 2026 00:00:00 +0000</pubDate><guid>https://c6a81954.notes-54i.pages.dev/posts/polymedx-https-edge-proxy-%E6%95%99%E5%AD%B8/</guid><description>&lt;p&gt;這個 Nginx proxy 安裝在 TAMS 主機上，統一處理 HTTPS/WSS，並依網域將流量送往 TAMS、HMI 與 rosbridge。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;網址&lt;/th&gt;
					&lt;th&gt;目的地&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;https://tams.hospital.internal&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;TAMS frontend、backend、Swagger、Socket.IO&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;https://hmi-amr701.hospital.internal&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;HMI frontend、backend、Swagger、Socket.IO&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;wss://amr701.hospital.internal&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;AMR rosbridge&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;以下命令都從 PolyMedX workspace 根目錄執行。&lt;/p&gt;
&lt;h2 id="前置條件"&gt;前置條件&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Docker 與 Docker Compose 已啟動。&lt;/li&gt;
&lt;li&gt;TAMS 主機可連到 AMR 的 &lt;code&gt;5173&lt;/code&gt;、&lt;code&gt;3000&lt;/code&gt;、&lt;code&gt;9090&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;主機的 &lt;code&gt;80&lt;/code&gt;、&lt;code&gt;443&lt;/code&gt; 尚未被其他程式占用；測試時也可改用 &lt;code&gt;8080&lt;/code&gt;、&lt;code&gt;8443&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;TAMS backend 與 frontend 使用同一個 &lt;code&gt;tams-network&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="建立設定"&gt;建立設定&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;make edge-init&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;這會建立 &lt;code&gt;workspace-config/edge-proxy/.env&lt;/code&gt;；若檔案已存在則保留原檔，不會覆寫。&lt;/p&gt;
&lt;p&gt;開發環境範例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;SSL_BASE_DOMAIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;hospital.internal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;TAMS_DOMAIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;tams.hospital.internal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;HMI_DOMAIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;hmi-amr701.hospital.internal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;AMR_DOMAIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;amr701.hospital.internal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;TAMS_APP_UPSTREAM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;frontend:80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;TAMS_API_UPSTREAM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;backend:3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;TAMS_API_PREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/api&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;AMR_IP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;172.18.35.29&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;HMI_APP_UPSTREAM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;${AMR_IP}:5173&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;HMI_API_UPSTREAM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;${AMR_IP}:3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;ROS_BRIDGE_UPSTREAM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;${AMR_IP}:9090&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;SELF_SIGNED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;HSTS_MAX_AGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;HTTP_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;HTTPS_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;443&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意：&lt;/p&gt;</description></item><item><title>MongoDB 完整資料庫備份與還原教學</title><link>https://c6a81954.notes-54i.pages.dev/posts/mongodb-%E5%AE%8C%E6%95%B4%E8%B3%87%E6%96%99%E5%BA%AB%E5%82%99%E4%BB%BD%E8%88%87%E9%82%84%E5%8E%9F%E6%95%99%E5%AD%B8/</link><pubDate>Mon, 10 Aug 2026 00:00:00 +0000</pubDate><guid>https://c6a81954.notes-54i.pages.dev/posts/mongodb-%E5%AE%8C%E6%95%B4%E8%B3%87%E6%96%99%E5%BA%AB%E5%82%99%E4%BB%BD%E8%88%87%E9%82%84%E5%8E%9F%E6%95%99%E5%AD%B8/</guid><description>&lt;p&gt;此流程會將來源資料庫完整備份，再還原到目標 MongoDB，並可改成新的資料庫名稱。&lt;/p&gt;
&lt;h2 id="設定環境變數"&gt;設定環境變數&lt;/h2&gt;
&lt;p&gt;請依實際環境替換以下的內容，參考 &lt;code&gt;production.env&lt;/code&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;SOURCE_MONGODB_URI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mongodb://&amp;lt;username&amp;gt;:&amp;lt;password&amp;gt;@&amp;lt;source-host&amp;gt;:27017/?authSource=&amp;lt;auth-database&amp;gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;TARGET_MONGODB_URI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mongodb://&amp;lt;username&amp;gt;:&amp;lt;password&amp;gt;@&amp;lt;target-host&amp;gt;:27017/?authSource=&amp;lt;auth-database&amp;gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;SOURCE_DATABASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tams&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;TARGET_DATABASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tams&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;BACKUP_DIRECTORY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/db/backup&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SOURCE_MONGODB_URI&lt;/code&gt;：來源 MongoDB 的連線字串。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TARGET_MONGODB_URI&lt;/code&gt;：目標 MongoDB 的連線字串。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;authSource&lt;/code&gt;：帳號建立所在的驗證資料庫，通常是 &lt;code&gt;admin&lt;/code&gt; 或應用資料庫本身。&lt;/li&gt;
&lt;li&gt;密碼如包含 &lt;code&gt;@&lt;/code&gt;、&lt;code&gt;:&lt;/code&gt;、&lt;code&gt;/&lt;/code&gt;、&lt;code&gt;?&lt;/code&gt;、&lt;code&gt;#&lt;/code&gt; 等特殊字元，必須先進行 URL encoding。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;不要把真實帳密提交到 Git；若使用 &lt;code&gt;.env&lt;/code&gt; 檔，請將它加入 &lt;code&gt;.gitignore&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="備份來源資料庫"&gt;備份來源資料庫&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mongodump &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --uri&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SOURCE_MONGODB_URI&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --db&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SOURCE_DATABASE&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --out&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIRECTORY&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;完成後，備份會位於：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$HOME/db/backup/tams/&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;其中通常包含各 collection 的 &lt;code&gt;.bson&lt;/code&gt; 資料檔與 &lt;code&gt;.metadata.json&lt;/code&gt; 索引／設定檔。&lt;/p&gt;
&lt;h2 id="還原成新資料庫"&gt;還原成新資料庫&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mongorestore &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --uri&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$TARGET_MONGODB_URI&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --nsInclude&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SOURCE_DATABASE&lt;/span&gt;&lt;span class="s2"&gt;.*&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --nsFrom&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SOURCE_DATABASE&lt;/span&gt;&lt;span class="s2"&gt;.*&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --nsTo&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$TARGET_DATABASE&lt;/span&gt;&lt;span class="s2"&gt;.*&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --drop &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIRECTORY&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--nsFrom&lt;/code&gt;：指定備份中的來源資料庫及所有 collections。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--nsTo&lt;/code&gt;：將資料還原到目標資料庫。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--drop&lt;/code&gt;：先刪除目標資料庫內同名的 collection，再進行還原。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--nsInclude&lt;/code&gt;：只還原哪些 namespace。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;若不希望覆蓋目標資料庫既有的同名 collection，請移除 &lt;code&gt;--drop&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="驗證還原結果"&gt;驗證還原結果&lt;/h2&gt;
&lt;p&gt;查看目標資料庫的 collections：&lt;/p&gt;</description></item><item><title>Log 循環紀錄部署（TAMS + HMI)</title><link>https://c6a81954.notes-54i.pages.dev/posts/log-%E5%BE%AA%E7%92%B0%E7%B4%80%E9%8C%84%E9%83%A8%E7%BD%B2-tams-hmi/</link><pubDate>Fri, 07 Aug 2026 00:00:00 +0000</pubDate><guid>https://c6a81954.notes-54i.pages.dev/posts/log-%E5%BE%AA%E7%92%B0%E7%B4%80%E9%8C%84%E9%83%A8%E7%BD%B2-tams-hmi/</guid><description>&lt;ul&gt;
&lt;li&gt;TAMS：每小時更新當天 log；每日 &lt;code&gt;00:10&lt;/code&gt; 完整匯出前一天。&lt;/li&gt;
&lt;li&gt;HMI：每日 &lt;code&gt;12:00&lt;/code&gt; 從 &lt;code&gt;172.18.35.29:3100&lt;/code&gt; 完整匯出前一天。&lt;/li&gt;
&lt;li&gt;兩者皆保留 90 天。&lt;/li&gt;
&lt;li&gt;輸出格式為 JSONL。&lt;/li&gt;
&lt;li&gt;Log 儲存根目錄為 &lt;code&gt;/Data/Log/&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;loki-readers&lt;/code&gt; 群組控管讀取權限。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;目錄結構：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/Data/Log/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── tams/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── 2026-08-04.jsonl
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── 2026-08-05.jsonl
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── hmi/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── 2026-08-04.jsonl
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── loki-export-cron.log
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── loki-export-hmi-cron.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="安裝-logcli"&gt;安裝 LogCLI&lt;/h2&gt;
&lt;p&gt;已安裝者可跳過。&lt;/p&gt;
&lt;p&gt;LogCLI 建議與 Loki 使用相同版本。以下以 Loki &lt;code&gt;v2.9.2&lt;/code&gt;、Linux amd64 為例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get install -y curl unzip util-linux
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;tmp_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;mktemp -d&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fL &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://github.com/grafana/loki/releases/download/v2.9.2/logcli-linux-amd64.zip &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -o &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$tmp_dir&lt;/span&gt;&lt;span class="s2"&gt;/logcli.zip&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;unzip &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$tmp_dir&lt;/span&gt;&lt;span class="s2"&gt;/logcli.zip&amp;#34;&lt;/span&gt; -d &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$tmp_dir&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo install &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -m &lt;span class="m"&gt;0755&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$tmp_dir&lt;/span&gt;&lt;span class="s2"&gt;/logcli-linux-amd64&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /usr/local/bin/logcli
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm -rf &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$tmp_dir&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo /usr/local/bin/logcli --version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="建立群組授權"&gt;建立群組授權&lt;/h2&gt;
&lt;p&gt;建議使用群組授權，不要直接開放所有帳號讀取 backend log。&lt;/p&gt;</description></item><item><title>PolyMedX Production 部署精簡版</title><link>https://c6a81954.notes-54i.pages.dev/posts/polymedx-production-%E9%83%A8%E7%BD%B2%E7%B2%BE%E7%B0%A1%E7%89%88-%E5%9F%B7%E8%A1%8C%E7%94%A8/</link><pubDate>Fri, 07 Aug 2026 00:00:00 +0000</pubDate><guid>https://c6a81954.notes-54i.pages.dev/posts/polymedx-production-%E9%83%A8%E7%BD%B2%E7%B2%BE%E7%B0%A1%E7%89%88-%E5%9F%B7%E8%A1%8C%E7%94%A8/</guid><description>&lt;blockquote&gt;
&lt;p&gt;正式環境：MongoDB Server（獨立） + Application Server（polymed-system）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;這裏假設:&lt;/p&gt;
&lt;p&gt;Application Server：10.10.0.10
MongoDB Server： 10.10.0.20&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="0-首次取得原始碼application-server"&gt;0. 首次取得原始碼（Application Server）&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkdir -p /opt/polymedx
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chown &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$USER&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; /opt/polymedx
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /opt/polymedx
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;repo init &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -u git@ssh.dev.azure.com:v3/pixsee/PolyMedX/polymedx-manifest &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -b main &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -m default.xml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;repo sync -c -j8&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="1-mongodb-server"&gt;1. MongoDB Server&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 1. 設定目錄&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkdir -p /opt/polymedx
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chown &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$USER&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; /opt/polymedx
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /opt/polymedx
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 2. 複製檔案&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 將其中的 Application Server 中的 workspace-config/mongodb-deployment 整個目錄複製到 MongoDB Server 的 /opt/polymedx/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 3. 確認目錄（從 Application Server 複製過來）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# /opt/polymedx/mongodb-deployment/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ├── docker-compose.yml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ├── production.mongodb.env.example&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# └── mongo-init/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /opt/polymedx/mongodb-deployment
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 4. 設定&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cp production.mongodb.env.example production.mongodb.env
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod &lt;span class="m"&gt;600&lt;/span&gt; production.mongodb.env
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 編輯 production.mongodb.env（IP、帳密、INIT_CLIENT_*）&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;production.mongodb.env 關鍵項目：&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>離線部署 docker image</title><link>https://c6a81954.notes-54i.pages.dev/posts/%E9%9B%A2%E7%B7%9A%E9%83%A8%E7%BD%B2-docker-image/</link><pubDate>Fri, 07 Aug 2026 00:00:00 +0000</pubDate><guid>https://c6a81954.notes-54i.pages.dev/posts/%E9%9B%A2%E7%B7%9A%E9%83%A8%E7%BD%B2-docker-image/</guid><description>&lt;p&gt;以下是 frontend + backend 的離線部署流程。假設建置機有外網、部署機為一般 Linux x86_64。&lt;/p&gt;
&lt;h2 id="有外網的建置機建立-image"&gt;有外網的建置機：建立 image&lt;/h2&gt;
&lt;p&gt;在專案根目錄執行（版本號可自行替換）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;RELEASE_TAG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;20260804&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Frontend：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; tams-frontend
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker buildx build &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --platform linux/amd64 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --load &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -t tams-frontend:&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RELEASE_TAG&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -t tams-frontend:latest &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --build-arg &lt;span class="nv"&gt;VITE_WS_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;same-origin &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --build-arg &lt;span class="nv"&gt;VITE_API_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/api/v1 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --build-arg &lt;span class="nv"&gt;VITE_LIDAR_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;real &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --build-arg &lt;span class="nv"&gt;VITE_LIDAR_TEST_ROBOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --build-arg &lt;span class="nv"&gt;VITE_HOSPITAL_INITIAL_RELEASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --build-arg &lt;span class="nv"&gt;VITE_LOW_BATTERY_THRESHOLD_MIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Backend：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ../tams-backend-service
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker buildx build &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --platform linux/amd64 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --target production &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --load &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -t tams-backend:&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RELEASE_TAG&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -t tams-backend:production &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;VITE_API_URL=/api/v1&lt;/code&gt; 會編譯進 frontend bundle，因此瀏覽器會對前端同源 &lt;code&gt;/api/v1/...&lt;/code&gt; 發請求，再由 Nginx 轉送至 backend。&lt;/p&gt;</description></item><item><title/><link>https://c6a81954.notes-54i.pages.dev/posts/robot-snapshot-log-%E7%B4%80%E9%8C%84/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://c6a81954.notes-54i.pages.dev/posts/robot-snapshot-log-%E7%B4%80%E9%8C%84/</guid><description>&lt;h1 id="robot-snapshot-log-紀錄"&gt;robot snapshot Log 紀錄&lt;/h1&gt;
&lt;p&gt;目前共有 6 種 &lt;code&gt;robot_snapshot&lt;/code&gt; operation，涵蓋 API 與背景任務。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Operation&lt;/th&gt;
					&lt;th&gt;Phase&lt;/th&gt;
					&lt;th&gt;觸發來源&lt;/th&gt;
					&lt;th&gt;記錄時機&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;create_task_request&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;selected&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;一般建立、工程師建立、returnHome、autoCharge、RobotKeeper&lt;/td&gt;
					&lt;td&gt;Robot 選定後、TaskHistory 建立前&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;create_task_by_library&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;selected&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;by-library API&lt;/td&gt;
					&lt;td&gt;Robot assignment 驗證後、TaskHistory 建立前&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;task_cancel&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;before_reset&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;取消任務 API、院內返藥局流程&lt;/td&gt;
					&lt;td&gt;清除 robot task 資訊前&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;task_continue&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;before_queue&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;藥車 continue API&lt;/td&gt;
					&lt;td&gt;Robot 驗證完成、下一段 queue 建立前&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;hospital_return_to_pharmacy&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;evaluating&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Hospital ReturnToErPharmacy&lt;/td&gt;
					&lt;td&gt;逐台判斷返回或等待前&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;rmf_dispatch&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;before_dispatch&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;TaskQueue 背景派送&lt;/td&gt;
					&lt;td&gt;通過 RMF readiness 檢查、呼叫 RMF 前&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="對應-api"&gt;對應 API&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;create_task_request&lt;/code&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /api/v1/tasks&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /api/v1/tasks/create-by-engineer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /api/v1/tasks/returnHome&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /api/v1/tasks/autoCharge&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此外，RobotKeeper 自動充電也會觸發，但不是 HTTP API。&lt;/p&gt;</description></item><item><title>polymedx-production-部署流程</title><link>https://c6a81954.notes-54i.pages.dev/posts/polymedx-production-%E9%83%A8%E7%BD%B2%E6%B5%81%E7%A8%8B/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://c6a81954.notes-54i.pages.dev/posts/polymedx-production-%E9%83%A8%E7%BD%B2%E6%B5%81%E7%A8%8B/</guid><description>&lt;p&gt;&lt;strong&gt;Application Server + 獨立 MongoDB Server 正式環境部署指南&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="架構概述"&gt;架構概述&lt;/h2&gt;
&lt;p&gt;正式環境採分離式架構：MongoDB 獨立運行於 MongoDB Server，Application Server 只運行應用服務群（polymed-system）。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;MongoDB Server
└── polymed-mongodb

Application Server
└── polymed-system
 ├── redis
 ├── backend
 ├── frontend
 ├── rmf-api-service
 ├── loki
 └── grafana&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;**ℹ 說明
&lt;code&gt;polymed-system&lt;/code&gt; 不會**啟動本機 MongoDB，而是透過網路連線至獨立 MongoDB Server。此設計便於資源隔離與獨立擴展。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="首次初始化僅-application-server-第一次部署需要"&gt;首次初始化（僅 Application Server 第一次部署需要）&lt;/h2&gt;
&lt;p&gt;在 Application Server 建立完整 PolyMedX workspace：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir polyMedX
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; polyMedX
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;repo init &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -u git@ssh.dev.azure.com:v3/pixsee/PolyMedX/polymedx-manifest &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -b main &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -m default.xml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;repo sync -c -j8&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;完成後目前目錄即為 &lt;code&gt;polyMedX&lt;/code&gt; workspace root。接著執行：&lt;/p&gt;</description></item></channel></rss>