2026年2月28日 星期六

使用 Gemini CLI 與透過自然語言來動手實作進行開發出一個 FHIR 為基礎的病人時序圖應用系統

使用 Gemini CLI 與透過自然語言來動手實作進行開發出一個 FHIR 為基礎的病人時序圖應用系統

先說結論,在這裡使用了 Gemini CLI 在一個小時之內,開發出一個病人時序圖網頁系統,可是,產生出來的結果不如預期且功能欠缺很多,但是,整體操作過程上也不會很複雜,但是相較於 OpenAI Codex 來說,說實在的還是有點繁瑣。

在上一篇 使用 OpenAI Codex 與透過自然語言來動手實作進行開發出一個 FHIR 為基礎的病人時序圖應用系統 文章中,我使用了 OpenAI Codex 來開發這個病人時序圖的前端應用程式,並且在這個過程中,我也對於 OpenAI Codex 的使用有了初步的認識與體驗,這些經驗對於未來如果要再次使用 OpenAI Codex 來進行專案開發,將會有很大的幫助。

在這篇文章中,將會使用 Gemini CLI 來開發這個病人時序圖的前端應用程式,使用的體驗也與使用 OpenAI Codex 相同,在使用之前,並沒有 Gemini CLI 的使用經驗與知識,因此,在使用的過程中,會先閱讀 Gemini CLI 的官方文件,來了解 Gemini CLI 的基本概念、功能以及使用方法,這些文件將會幫助我快速地上手 Gemini CLI,並且讓我能夠順利地使用 Gemini CLI 來開發這個病人時序圖的前端應用程式。

從無到有,總共花費的時間同樣的也是在 1 個小時內可以完成,雖然說完成的結果不如預期,但是,整體的操作過程上也不會很複雜,不過,這個過程讓我對於 Gemini CLI 的使用有了初步的認識與體驗,也讓我了解了在使用 Gemini CLI 來進行專案開發時,需要注意的一些事項和步驟,這些經驗對於未來如果要再次使用 Gemini CLI 來進行專案開發,將會有很大的幫助。

事前準備

在前一周,我下載的 Synthea™ 產生出來的 10 個模擬 FHIR 病人就醫紀錄,並且將這些紀錄匯入到網路上的免費 FHIR Server 上 ( https://server.fire.ly ),這些模擬病人就醫紀錄資料將會包含這些 FHIR 資源,包括 Organization、Location、Practitioner、PractitionerRole、Patient、Encounter、Condition、AllergyIntolerance、Immunization、Device、Observation、Procedure、DiagnosticReport、DocumentReference 以及 MedicationRequest 等等,這些資料將會成為我們開發病人時序圖應用系統的測試資料,讓我們能夠在開發過程中有實際的資料來進行測試和驗證。

使用 OpenAI Codex 來進行病人時序圖開發

  • 由於我毫無 Gemini CLI 的經驗與知識,因此,我打開了 Gemini CLI documentation 這個平網頁面,來閱讀 Gemini CLI 的官方文件,並且了解 Gemini CLI 的基本概念、功能以及使用方法,這些文件將會幫助我快速地上手 Gemini CLI,並且讓我能夠順利地使用 Gemini CLI 來開發這個病人時序圖的前端應用程式。
  • 在這裡想要產生一個 [GEMINI.md] 檔案,這個檔案將會包含這個專案的目標、需求、開發工具與環境設定,以及每一個步驟的詳細說明,讓我可以順利地使用 Gemini CLI 來開發這個病人時序圖的前端應用程式。
  • 所以,在這裡先把想要開發出來的 App 需求整理出來,可以參考底下所述
我從 Synthea™ Patient Generator (GitHub) 下載了 Synthea™ 生成的 FHIR 資料,並使用 HAPI FHIR CLI 工具將資料匯入到 Firely Server 上 ( https://server.fire.ly )。以下是匯入的 FHIR Resource :
   * Organization : 模擬的醫療機構資料。
   * Location : 模擬的醫療機構地點資料。
   * Practitioner : 模擬的醫療人員資料。
   * PractitionerRole : 模擬的醫療人員角色資料。
   * Patient : 模擬的病人資料。
   * Encounter : 模擬的就診事件資料。
   * Condition : 模擬的疾病或健康狀態資料。
   * AllergyIntolerance : 模擬的過敏或不耐受資料。
   * Immunization : 模擬的疫苗接種資料。
   * Device : 模擬的醫療設備資料。
   * Observation : 模擬的觀察資料。
   * Procedure : 模擬的醫療程序資料。
   * DiagnosticReport : 模擬的診斷報告資料。
   * DocumentReference : 模擬的文件參考資料。
   * MedicationRequest : 模擬的用藥請求資料。

我需要一份使用 Gemini CLI 來進行詳細操作指引規劃文件,可以參考 https://geminicli.com/docs/ 官方文件的操作與建議說明,在這裡需要開發一個採用 React / TypeScript 的前端應用程式,該系統是病人時序圖,用於展示病人從就診到治療的整個過程。在這裡可以輸入病人 ID,如 fb7c882a-f897-e7c5-67e0-825e7fd55d15,然後從 Firely Server 上獲取該病人的相關 FHIR 資料,並將這些資料以時序圖的形式展示出來。例如,這個病人可以從這個 URL 取得 https://server.fire.ly/Patient/fb7c882a-f897-e7c5-67e0-825e7fd55d15

從病人時序圖畫面,可以看到指定區間內該病人的所有就醫紀錄與該病人的綜合摘要說明,並且可以點擊每一筆就醫紀錄來查看該就醫紀錄的詳細資訊。這些就醫紀錄可以包括病人就診的日期、就診的醫療機構、就診的醫療人員、就診的疾病或健康狀態、就診的過敏或不耐受、就診的疫苗接種、就診的醫療設備、就診的觀察、就診的醫療程序、就診的診斷報告、就診的文件參考以及就診的用藥請求等資訊。

由於我沒有使用過 Gemini CLI 工具的經驗,需要列出如何安裝那些工具與軟體或檔案,輸入那些指令,在哪裡做甚麼操作, Prompt 該輸入甚麼內容,每一個步驟的詳細說明,讓我可以順利地使用 Gemini CLI 來開發這個病人時序圖的前端應用程式。開發工具將會採用 VS Code

最後,產生一個 markdown 檔案,告訴 Gemini CLI,這個專案的目標、需求、開發工具與環境設定,以及每一個步驟的詳細說明,讓我可以順利地使用 Gemini CLI 來開發這個病人時序圖的前端應用程式。
  • 在這裡先把這些內容送到 LLM 內,產生出一個 [GEMINI.md]
# Project: Patient Timeline (React + TypeScript) for Firely Server (FHIR R4)
> Repo Context File for Gemini CLI (GEMINI.md)

## 0) 專案目標(Goal)
建立一個使用 React + TypeScript 的前端 Web App(Vite),用來:
1. 輸入 Patient ID(例如:fb7c882a-f897-e7c5-67e0-825e7fd55d15)
2. 從 Firely Server 取得該病人相關 FHIR 資料
3. 以「病人時序圖」呈現指定區間內的所有就醫紀錄(Encounter 為主軸,並整合/關聯其他 resources)
4. 提供「病人綜合摘要」以及「點擊某次就醫即可查看詳情」的互動 UI

FHIR Server 基底:
- https://server.fire.ly
示例病人:
- https://server.fire.ly/Patient/fb7c882a-f897-e7c5-67e0-825e7fd55d15

匯入的資源類型(Synthea 生成並已匯入):
Organization, Location, Practitioner, PractitionerRole, Patient, Encounter, Condition,
AllergyIntolerance, Immunization, Device, Observation, Procedure, DiagnosticReport,
DocumentReference, MedicationRequest

## 1) 使用者故事(User Stories)
### US-01:查詢病人
- 我可以輸入 Patient ID
- 系統會顯示病人基本資料(姓名、性別、年齡/生日、識別碼等)
- 若 Patient 不存在,顯示清楚的錯誤訊息

### US-02:指定區間時序圖
- 我可以選擇日期區間(預設:最近 1 年,或由資料最早到最晚)
- 時序圖以 Encounter 為主(每筆 Encounter 是一個 timeline item)
- item 上顯示:日期/期間、機構、就醫類型(門診/急診/住院等)、關鍵摘要(診斷/處置/用藥等)

### US-03:就醫詳情檢視
- 點擊某一筆 Encounter(或事件)後,右側 Drawer/Modal 顯示:
  - Encounter details
  - 關聯到該 Encounter 的 Condition / Observation / Procedure / DiagnosticReport / DocumentReference / MedicationRequest 等
  - 顯示關聯依據(reference / encounter / context 等欄位)

### US-04:病人摘要(Summary)
- 左側或上方顯示病人摘要卡(可折疊):
  - Demographics
  - 近期重大診斷(Condition)
  - 過敏(AllergyIntolerance)
  - 近期用藥(MedicationRequest)
  - 近期檢驗(Observation / DiagnosticReport)

## 2) 系統與技術選型(Tech Stack)
- Frontend: React + TypeScript + Vite
- UI: 建議先用簡單方案(例如 MUI / Ant Design / Chakra)其一,避免自刻太多 UI
- Timeline 視覺化:優先選擇具備縮放/拖曳/群組功能的 timeline library(例如 vis-timeline),避免只用靜態列表
- HTTP Client:fetch 或 axios 均可,但需有清楚的錯誤處理與 retry/backoff(可選)
- FHIR 資料處理:以 FHIR JSON(R4)為主,不使用後端 proxy 亦可,但需處理 CORS;若 CORS 被擋,改用 Vite dev proxy

## 3) 目錄結構(Target Structure)
repo-root/
  GEMINI.md
  package.json
  vite.config.ts
  src/
    main.tsx
    app/
      App.tsx
      routes.tsx
    features/
      patient-lookup/
      timeline/
      encounter-details/
      summary/
    fhir/
      client.ts           # Firely Server base + fetch wrapper
      types.ts            # 最小必要的 FHIR typings(或直接用 any,但要有 guard)
      normalize.ts        # 轉換 Bundle/Resources -> domain model
      index.ts
    models/
      timeline.ts         # TimelineEvent, Group, etc.
    utils/
      date.ts
      errors.ts
  README.md

## 4) FHIR 資料取得策略(Data Fetch Strategy)
### 4.1 優先方案:使用 Patient/$everything(若 server 支援)
- GET /Patient/{id}/$everything
- 優點:一次拿到多數相關資料(Encounter, Condition, Observation...)
- 缺點:資料量可能大;需要分頁(next link)處理;不一定包含所有你想要的關聯(依 server 行為)

### 4.2 保底方案:以 Encounter 為中心逐步查
最穩定可控的方式(建議實作):
1) 先抓 Patient
- GET /Patient/{id}

2) 抓 Encounter(指定日期區間 + 病人)
- GET /Encounter?patient={id}&date=ge{from}&date=le{to}&_count=200
- 需要處理 Bundle 分頁(link[relation="next"]3) 針對該區間,平行抓相關 resources(依需求)
常見查法(視 server 支援):
- Condition?patient={id}&recorded-date=ge...&recorded-date=le...
- Observation?patient={id}&date=ge...&date=le...
- Procedure?patient={id}&date=ge...&date=le...
- DiagnosticReport?patient={id}&date=ge...&date=le...
- DocumentReference?patient={id}&date=ge...&date=le...
- MedicationRequest?patient={id}&_count=200 (可用 authoredon/date filter 若支援)

4) 將上述 resources 以「參考欄位」做 Encounter 關聯(normalize)
常見關聯線索:
- resource.encounter (Reference -> Encounter)
- resource.context.encounter (部分資源)
- DiagnosticReport.encounter
- DocumentReference.context.encounter

若沒有 encounter reference,則以時間落點(effective[x], issued, performed[x], authoredOn)做近似歸屬(但要清楚標註是 heuristic)。

## 5) Timeline 規格(UI/UX Spec)
### 5.1 主畫面布局(建議)
- Header:Patient ID input + Date Range picker + Fetch button
- Left/Top:Patient Summary (cards)
- Center:Timeline(縮放/拖曳/群組)
- Right:Encounter Detail Drawer(點擊 timeline item 開啟)

### 5.2 Timeline 事件定義(Domain Model)
TimelineEvent:
- id: string
- type: "Encounter" | "Condition" | "Observation" | "Procedure" | "DiagnosticReport" | "DocumentReference" | "MedicationRequest" | ...
- start: Date
- end?: Date
- title: string (短標題)
- subtitle?: string
- encounterId?: string (若可關聯)
- resourceRef: { resourceType: string; id: string }
- raw?: any (保留原始 resource 方便 detail panel)

### 5.3 顯示策略
- 第一階段:只顯示 Encounter item(最清楚)
- 第二階段:同一條 timeline 上,加上關聯事件(Observation/Procedure…)做小點/標記(可分 group)
- 第三階段:可加 filter(只看用藥/只看檢驗/只看報告)

## 6) CORS / Proxy(非常重要)
若前端直接呼叫 https://server.fire.ly 被 CORS 擋:
- 使用 Vite dev proxy:
  - 前端改呼叫 /fhir/Patient/{id}
  - Vite proxy 轉發到 https://server.fire.ly

vite.config.ts(示例):
- server.proxy = {
    "/fhir": {
      target: "https://server.fire.ly",
      changeOrigin: true,
      secure: true,
      rewrite: (path) => path.replace(/^\/fhir/, "")
    }
  }

## 7) 程式碼規範(Coding Conventions)
- TypeScript strict 模式(能開就開)
- Component 命名 PascalCase
- 每個 feature 用資料夾隔離(feature-first)
- 所有 fetch 都要:
  - timeout(可選)
  - status code handling
  - OperationOutcome 顯示(若回傳)
- UI 不要一次做太花:先完成資料正確性與互動,再美化

## 8) 測試與品質門檻(Quality Gate)
每次改動完成後,務必執行:
- npm run lint
- npm run build
- npm run test(若已導入 vitest)

## 9) Gemini CLI:安裝與使用(給「人」的操作手冊)
> 這段是「你照做就能跑起來」的步驟;同時也讓 Gemini CLI 理解你希望它怎麼帶你做事。

### 9.1 安裝清單(Windows + VS Code)
你需要先安裝:
1) Git
2) Node.js(建議使用 Node 20+)
3) VS Code(含內建 terminal)

Gemini CLI 安裝(npm 全域安裝):
- npm install -g @google/gemini-cli
驗證:
- gemini --version

啟動 Gemini CLI:
- gemini

首次啟動會引導你用 Google account 認證(free tier)。  
(若公司/特殊帳號要求 Google Cloud project,依 Gemini CLI Authentication 文件處理。)

### 9.2 建議工作流程(像「結對程式設計」)
你在 repo root 以 gemini 開啟互動後,採用「小步快跑」:
- 每次只做一個可驗證的小任務
- 讓 Gemini 先「提 plan」再「產生 patch」
- 每次 patch 後你都跑 lint/build,確保沒壞

請 Gemini 的固定開場 prompt(每次進新 repo 建議跑一次):
「請先閱讀 GEMINI.md,理解專案目標與規範。接著列出你打算用 8~12 個 step 完成 MVP 的計畫(每個 step 有可驗證產出)。先不要改 code。」

### 9.3 你要輸入的關鍵 Prompt 模板(直接複製貼上)
#### (A) 初始化專案(Vite React TS)
「請在 repo root 建立 Vite + React + TypeScript 專案(npm)。完成後告訴我執行與驗證指令,並確保專案能 npm run dev 跑起來。」

#### (B) 加入 Vite proxy(避免 CORS)
「請在 vite.config.ts 加入 /fhir -> https://server.fire.ly 的 proxy(rewrite 移除 /fhir)。並把 FHIR client 的 baseUrl 改成 /fhir。」

#### (C) 建立 FHIR client(帶錯誤處理)
「請在 src/fhir/client.ts 建立 getJson<T>() 封裝 fetch:包含 status code 檢查、FHIR OperationOutcome 的錯誤訊息萃取、以及可重用的 baseUrl。」

#### (D) Patient Lookup + Summary 卡
「請建立 PatientLookup 元件:輸入 Patient ID、按下查詢後顯示 Patient summary(至少 name/gender/birthDate/identifier)。錯誤要顯示在 UI。」

#### (E) 抓 Encounter + Timeline MVP
「請建立 Timeline MVP:抓 Encounter?patient={id}&date=ge...&date=le...,把每筆 Encounter 轉成 timeline item。先用簡單列表/時間軸皆可,但要能點擊 item。」

#### (F) Encounter Detail Drawer + 關聯資源
「點擊 Encounter 後:右側 Drawer 顯示 Encounter 原始 JSON(可折疊)+ 關聯 resources(Condition/Observation/Procedure/DiagnosticReport/DocumentReference/MedicationRequest)。關聯優先用 resource.encounter reference;沒有則先略過。」

#### (G) Bundle 分頁
「請把 FHIR Bundle 分頁(next link) 支援起來,確保 Encounter 查詢能完整抓完指定區間內資料。」

### 9.4 每一輪迭代你要做的固定驗證
你每次接受變更後,請在 terminal 執行:
- npm install
- npm run dev
- npm run build
- npm run lint

如果 build/lint 有錯,把錯誤貼回 Gemini:
「我執行 npm run build 失敗,錯誤如下:...。請修到通過為止,並解釋你改了什麼。」

## 10) Gemini CLI:對 Agent 的行為要求(給模型看的硬規則)
- 每次大改動前先提出 plan(含檔案列表與改動點)
- 優先做 MVP 可跑起來,再逐步加功能
- 任何 FHIR 查詢都要:
  - 在程式內集中管理(不要散落在各元件)
  - 有清楚型別/guards(至少對 resourceType/id/date 欄位)
- UI 互動最小可用即可,先把資料正確性做穩

## 11) MVP Done Definition(完成定義)
以下全部達成即算 MVP:
- 可輸入 Patient ID
- 顯示 Patient summary
- 可選日期區間
- 可取得並顯示 Encounter timeline
- 點擊 Encounter 可看到詳細資訊(至少 Encounter 本身 + 關聯 resources 清單或 raw JSON)
- 能處理分頁(next link)
- npm run build / lint 通過
  • 我在 Github 網頁上建立一個新的 Repository PatientTimelineGemini
  • 接著將這個 Repository 複製 Clone 到本地端的電腦上,並且在本地端的電腦上使用 VS Code 開啟這個 Repository 的資料夾,準備開始進行開發工作。
  • 將剛剛產生的 [GEMINI.md] 檔案放到這個 Repository 的根目錄下,並且將這個檔案的內容貼上剛剛產生的內容,然後將這個檔案進行 Commit 並且 Push 到 Github 上,讓這個檔案成為這個 Repository 的一部分,並且讓其他人也能夠看到這個檔案的內容。
  • 由於是第一次使用,因此,使用底下命令安裝 Gemini CLI 工具
npm install -g @google/gemini-cli
  • 這裡是安裝過程
npm warn deprecated node-domexception@1.0.0: Use your platform's native DOMException instead
npm warn deprecated glob@10.5.0: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
npm warn deprecated prebuild-install@7.1.3: No longer maintained. Please contact the author of the relevant native addon; alternatives are available.

added 627 packages in 30s

175 packages are looking for funding
  run `npm fund` for details
  • 在這個 Repository 目錄下,開啟一個命令提示字元視窗
  • 在命令提示字元視窗中,輸入命令 gemini 來啟動 GEMINI CLI
  • 詳細過程就不再紀錄了
  • 當出現 How would you like to authenticate for this project? 的提示時,選擇 Login with Google,然後按照提示進行 Google 帳戶的認證過程,完成認證後,GEMINI CLI 就會成功地連接到你的 Google 帳戶,並且可以開始使用 GEMINI CLI 來進行專案的開發工作了。
  • 這裡看到了 You have successfully logged in with Google. Gemini CLI needs to be restarted. Press 'r' to restart, or 'escape' to │ │ choose a different auth method. 的提示,按下 r 鍵來重新啟動 GEMINI CLI,讓 GEMINI CLI 能夠使用剛剛完成的 Google 認證來進行專案的開發工作。
  • 輸入底下內容給 GEMINI CLI : [參考 GEMINI.md 的內容,開發出所需要的病人時序圖網頁]

  • 若出現 Allow execution of: 'npm'? 的提示,選擇 Allow for this session 來允許 GEMINI CLI 執行 npm 命令,這樣 GEMINI CLI 就能夠使用 npm 來安裝專案所需要的依賴包,並且進行專案的開發工作了。

  • 完成之後,啟動這個專案,並開啟網頁 [http://localhost:5173]
  • 現在會看到網頁畫面

  • 輸入完病人 ID 後,點選 [LOOKUP] 按鈕,會看到病人時序圖的畫面

 




使用 OpenAI Codex 與透過自然語言用 Blazor 來動手實作進行開發出一個 FHIR 為基礎的病人時序圖應用系統

使用 OpenAI Codex 與透過自然語言用 Blazor 來動手實作進行開發出一個 FHIR 為基礎的病人時序圖應用系統

先說結論,經過最終結果,雖然花了約 1 個小時的時間,但是,我也是完成了採用 ASP.NET Core Blazor 開發框架技術來開發出另外一套病人時序圖的前端應用程式,並且在開發過程中,我也是順利地使用 OpenAI Codex 來幫助我完成這個專案的開發,從專案的建立、到功能的實作、到測試與驗證,整個過程都是非常順利的,並且最終也成功地完成了這個專案的開發。這裡可以確認的是,比起之前採用純粹人工的方式來開發這個病人時序圖的前端應用程式,當時花費了兩個星期的時間,但是,比起一個小時的時間,這次使用 OpenAI Codex 來開發這個病人時序圖的前端應用程式,確實是大幅度地縮短了開發的時間,並且在開發過程中,也確實是非常順利的,沒有遇到什麼特別大的問題,整個過程也是非常愉快的。

在上一篇文章 使用 OpenAI Codex 與透過自然語言來動手實作進行開發出一個 FHIR 為基礎的病人時序圖應用系統,我第一次使用 OpenAI Codex 工具,此用 React + TypeScript 來建立一個系統,這個系統是採用讀取 FHIR Server 上的資料,然後將這些資料以時序圖的形式展示出來,這個系統的功能是可以輸入病人 ID,然後從 Firely Server 上獲取該病人的相關 FHIR 資料,並且將這些資料以時序圖的形式展示出來,從病人時序圖畫面,可以看到指定區間內該病人的所有就醫紀錄與該病人的綜合摘要說明,並且可以點擊每一筆就醫紀錄來查看該就醫紀錄的詳細資訊。

現在,我將會使用 OpenAI Codex 來開發一個採用 ASP.NET Core Blazor (Server Side Interactive Rendering & 不要 per page 方式,而是採用 Global 方式) 的前端應用程式,該系統是病人時序圖,用於展示病人從就診到治療的整個過程。在這裡可以輸入病人 ID,如 129c6ac7-8d06-89de-ad63-0204a93e76c3,然後從 Firely Server 上獲取該病人的相關 FHIR 資料,並將這些資料以時序圖的形式展示出來。例如,這個病人可以從這個 URL 取得 https://server.fire.ly/Patient/129c6ac7-8d06-89de-ad63-0204a93e76c3

我的目的在於需要驗證使用 OpenAI Codex 來開發這個病人時序圖的前端應用程式的可行性,是否可以採用另外一種技術,也就是採用 ASP.NET Core Blazor 的技術來開發這個病人時序圖的前端應用程式,並且看看使用 OpenAI Codex 來開發這個系統的過程中,是否可以順利地完成這個專案的開發,以及在開發過程中,是否可以順利地使用 OpenAI Codex 來幫助我完成這個專案的開發。

事前準備

在前一周,我下載的 Synthea™ 產生出來的 10 個模擬 FHIR 病人就醫紀錄,並且將這些紀錄匯入到網路上的免費 FHIR Server 上 ( https://server.fire.ly ),這些模擬病人就醫紀錄資料將會包含這些 FHIR 資源,包括 Organization、Location、Practitioner、PractitionerRole、Patient、Encounter、Condition、AllergyIntolerance、Immunization、Device、Observation、Procedure、DiagnosticReport、DocumentReference 以及 MedicationRequest 等等,這些資料將會成為我們開發病人時序圖應用系統的測試資料,讓我們能夠在開發過程中有實際的資料來進行測試和驗證。

使用 OpenAI Codex 來進行病人時序圖開發

    • 使用網頁開啟 OpenAI Codex 的平台後,並且登入到平台上
  • 我在 Github 網頁上建立一個新的 Repository PatientTimelineBlazor
  • 在 OpenAI Codex 網頁上,設定與綁定此次要做的後續工作,將會在這個 Repository 內來呈現
  • 在 OpenAI Codex 網頁上,介面相當的簡單,如同 ChatGPT 一樣,就只有一個文字輸入框
  • 然後在這個文字輸入框裡面,我就可以輸入我想要 OpenAI Codex 來幫我完成的工作內容,這些工作內容可以是一些具體的指令,例如「建立一個 React / TypeScript 的前端應用程式」,或者是一些更抽象的描述,例如「開發一個 FHIR 為基礎的病人時序圖應用系統」,無論是什麼樣的內容,我都可以直接在這個文字輸入框裡面輸入,然後 OpenAI Codex 就會根據我的輸入來生成相應的程式碼和文件,讓我能夠快速地完成我的專案開發。
  • 我將底下的內容輸入到這個文字輸入框裡面,讓 OpenAI Codex 來幫我完成這個專案的開發,這些內容包括了專案的目標、需求、開發工具與環境設定,以及每一個步驟的詳細說明,讓我能夠順利地使用 OpenAI Codex 來開發這個病人時序圖的前端應用程式。
我從 Synthea™ Patient Generator (GitHub) 下載了 Synthea™ 生成的 FHIR 資料,並使用 HAPI FHIR CLI 工具將資料匯入到 Firely Server 上 ( https://server.fire.ly )。以下是匯入的 FHIR Resource :
   * Organization : 模擬的醫療機構資料。
   * Location : 模擬的醫療機構地點資料。
   * Practitioner : 模擬的醫療人員資料。
   * PractitionerRole : 模擬的醫療人員角色資料。
   * Patient : 模擬的病人資料。
   * Encounter : 模擬的就診事件資料。
   * Condition : 模擬的疾病或健康狀態資料。
   * AllergyIntolerance : 模擬的過敏或不耐受資料。
   * Immunization : 模擬的疫苗接種資料。
   * Device : 模擬的醫療設備資料。
   * Observation : 模擬的觀察資料。
   * Procedure : 模擬的醫療程序資料。
   * DiagnosticReport : 模擬的診斷報告資料。
   * DocumentReference : 模擬的文件參考資料。
   * MedicationRequest : 模擬的用藥請求資料。

我需要一份使用 OpenAI Codex 來進行詳細操作指引規劃文件,可以參考 https://developers.openai.com/codex 官方文件的操作與建議說明,在這裡需要開發一個採用 ASP.NET Core Blazor (Server Side Interactive Rendering & 不要 per page 方式,而是採用 Global 方式) 的前端應用程式,該系統是病人時序圖,用於展示病人從就診到治療的整個過程。在這裡可以輸入病人 ID,如 129c6ac7-8d06-89de-ad63-0204a93e76c3,然後從 Firely Server 上獲取該病人的相關 FHIR 資料,並將這些資料以時序圖的形式展示出來。例如,這個病人可以從這個 URL 取得 https://server.fire.ly/Patient/129c6ac7-8d06-89de-ad63-0204a93e76c3

從病人時序圖畫面,可以看到指定區間內該病人的所有就醫紀錄與該病人的綜合摘要說明,並且可以點擊每一筆就醫紀錄來查看該就醫紀錄的詳細資訊。這些就醫紀錄可以包括病人就診的日期、就診的醫療機構、就診的醫療人員、就診的疾病或健康狀態、就診的過敏或不耐受、就診的疫苗接種、就診的醫療設備、就診的觀察、就診的醫療程序、就診的診斷報告、就診的文件參考以及就診的用藥請求等資訊。

由於我沒有使用過 OpenAI Codex 工具的經驗,需要列出如何安裝那些工具與軟體或檔案,輸入那些指令,在哪裡做甚麼操作, Prompt 該輸入甚麼內容,每一個步驟的詳細說明,讓我可以順利地使用 OpenAI Codex 來開發這個病人時序圖的前端應用程式。開發工具將會採用 VS Code,並且已經安裝 https://marketplace.visualstudio.com/items?itemName=openai.chatgpt 這個 VS Code 擴充套件來使用 OpenAI Codex 進行 開發與完成此專案。

最後,產生一個 markdown 檔案,告訴 OpenAI Codex,這個專案的目標、需求、開發工具與環境設定,以及每一個步驟的詳細說明,讓我可以順利地使用 OpenAI Codex 來開發這個病人時序圖的前端應用程式。
  • 在這裡,將會建立一個檔案 [Codex_Blazor_Patient_Timeline_Implementation_Guide_zh-TW.md]
  • 底下將會是這個檔案內容
# 使用 OpenAI Codex 開發「FHIR 病人時序圖」前端系統完整操作指引(ASP.NET Core Blazor)

> 適用對象:第一次使用 OpenAI Codex / VS Code ChatGPT 擴充套件的開發者  
> 專案型態:ASP.NET Core Blazor(Server Side Interactive Rendering,採 **Global** 互動模式,非 per-page)  
> 後端資料來源:Firely Server(FHIR R4 API,`https://server.fire.ly`

---

## 1. 專案目標(Project Goal)

建立一個「病人時序圖」前端應用程式,讓使用者可輸入病人 ID(例如:`129c6ac7-8d06-89de-ad63-0204a93e76c3`),並從 Firely Server 取得該病人的 FHIR 資料,彙整成可視化時間軸(Timeline),支援:

1. 指定時間區間(起迄日期)查詢病人就醫紀錄。
2. 顯示病人的綜合摘要(Summary)。
3. 以 Encounter 為主軸,串連同次或相近時段的臨床事件(Condition、Observation、Procedure、MedicationRequest…)。
4. 點擊任一就醫紀錄後,顯示詳細資訊(醫療機構、醫療人員、診斷報告、文件參考等)。

---

## 2. 功能需求(Functional Requirements)

### 2.1 主要查詢流程

- 使用者輸入 Patient ID。
- 系統向 Firely Server 查詢 Patient 基本資料。
- 以 Patient 為條件查詢:
  - Encounter
  - Condition
  - AllergyIntolerance
  - Immunization
  - Device
  - Observation
  - Procedure
  - DiagnosticReport
  - DocumentReference
  - MedicationRequest
- 前端將資料轉換為「時間軸事件模型」,依時間排序顯示。

### 2.2 明細檢視

- 點擊任一 Encounter(或事件節點)開啟詳細面板:
  - 就診日期、醫療機構(Organization / Location)
  - 醫療人員與角色(Practitioner / PractitionerRole)
  - 對應疾病、觀察、處置、檢查報告、用藥等

### 2.3 非功能需求

- UI 需可處理資料量偏大的病人(例如 Synthea 產生的長期病史)。
- 支援錯誤處理(找不到病人、FHIR API timeout、部分資源缺漏)。
- 使用可重複維護的分層設計(UI / Service / Mapping)。

---

## 3. 技術選型與架構(Tech Stack & Architecture)

## 3.1 技術選型

- .NET 8 SDK(建議)
- ASP.NET Core Blazor Web App
- Render mode:**Interactive Server(Global)**
- FHIR SDK:`Hl7.Fhir.R4`(或依目標版本選擇)
- HTTP:`HttpClientFactory`
- 開發工具:VS Code + C# + ChatGPT 擴充套件(OpenAI Codex 協作)

### 3.2 建議分層

- `Pages/`:查詢頁、時間軸頁
- `Components/`:Timeline、EventCard、SummaryPanel、DetailDrawer
- `Services/`:FHIR 查詢與聚合邏輯
- `Models/`:ViewModel / DTO(TimelineEvent、PatientSummary)
- `Mapping/`:FHIR Resource → UI Model

---

## 4. 開發環境安裝與設定(一步一步)

## 4.1 必要安裝清單

1. 安裝 .NET SDK 8
2. 安裝 VS Code
3. 安裝 VS Code Extensions:
   - C#(ms-dotnettools.csharp)
   - C# Dev Kit(建議)
   - ChatGPT(你已安裝)
4. 安裝 Git

## 4.2 驗證安裝

在終端機執行:

```bash
dotnet --version
code --version
git --version

若均正常輸出版本號,即可進入下一步。


5. 建立專案(Blazor + Global Interactive Server)

在專案資料夾執行:

dotnet new blazor -n PatientTimelineBlazor
cd PatientTimelineBlazor

若範本支援參數,可使用互動模式相關選項;若未提供,後續手動設定。

5.1 設定 Global Interactive Server

在 Program.cs 概念上需確保:

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

這代表全域啟用 Interactive Server,而非每頁 individually 指定。


6. Firely Server/FHIR 連線策略

6.1 基本 URL

  • Base URL:https://server.fire.ly
  • Patient 例:GET /Patient/129c6ac7-8d06-89de-ad63-0204a93e76c3

6.2 建議查詢方式

先查病人,再依病人關聯查詢資源:

  • Encounter?patient={id}
  • Condition?patient={id}
  • Observation?patient={id}
  • Procedure?patient={id}
  • MedicationRequest?patient={id}
  • 其他同理

6.3 CORS 注意事項

若直接由瀏覽器呼叫 Firely Server 遭遇 CORS,建議:

  • 由 Blazor Server 端(伺服器端)發送 FHIR API 請求,再回傳 UI。
  • 避免將第三方 API 呼叫留在瀏覽器端。

7. 實作步驟(可直接給 Codex 的工作拆解)

以下每一階段都可以用「小步驟 + 可驗證輸出」方式讓 Codex 逐步完成。

Step 1:建立骨架與路由

  • 建立頁面:
    • Pages/PatientTimeline.razor
  • 建立元件:
    • Components/Timeline/TimelineView.razor
    • Components/Timeline/TimelineEventCard.razor
    • Components/Timeline/EncounterDetailPanel.razor

驗收標準:可進入 /patient-timeline 頁面,看到 Patient ID 輸入框與查詢按鈕。

Step 2:FHIR 查詢服務

  • 建立 IFhirDataService / FhirDataService
  • 封裝方法:
    • GetPatientAsync(patientId)
    • GetEncountersAsync(patientId, from, to)
    • GetConditionsAsync(patientId, from, to)
    • …(其餘資源)

驗收標準:可在查詢後列印資源筆數(先文字顯示即可)。

Step 3:資料聚合(Timeline Mapping)

  • 建立 TimelineEvent 模型(DateTime、Type、Title、ReferenceIds、EncounterId、Details)。
  • 將各資源投影成統一事件模型。
  • 依日期排序後輸出。

驗收標準:畫面可顯示時間排序的事件清單。

Step 4:摘要與細節面板

  • PatientSummary:年齡、性別、慢性病摘要、最近就醫日期。
  • 點擊事件顯示 detail drawer/modal。

驗收標準:點擊某筆 Encounter 可看到該次就醫關聯資料。

Step 5:區間篩選與錯誤處理

  • 加入 From/To 日期篩選。
  • 處理 404、timeout、空資料。
  • 顯示 loading/skeleton。

驗收標準:指定區間後資料會變更,錯誤情境有友善提示。

Step 6:視覺優化與可維護性

  • 類型顏色標示(Condition/Observation/Medication…)。
  • 統一元件樣式與命名。
  • 補上 README 與操作說明。

驗收標準:畫面可讀性佳、結構清楚、便於後續擴充。


8. 在 VS Code 使用 OpenAI Codex 的實際操作流程

你已安裝 ChatGPT 擴充套件,可直接在 VS Code 內用對話方式驅動開發。

8.1 建議工作模式

  1. 先手動建立最小專案骨架。
  2. 每次給 Codex 一個明確、可驗證的小任務。
  3. 要求 Codex 回覆「修改哪些檔案 + 驗證指令」。
  4. 你執行測試後,再給下一步。

8.2 Prompt 模板(可直接貼)

模板 A:建立服務層

你是資深 ASP.NET Core Blazor 工程師。
請在目前專案中新增 FHIR 查詢服務層,需求:
1) 建立 IFhirDataService 與 FhirDataService
2) 透過 HttpClient 呼叫 https://server.fire.ly
3) 實作 GetPatientAsync、GetEncountersAsync、GetConditionsAsync、GetObservationsAsync
4) 加入基本錯誤處理與 cancellation token
5) 更新 DI 註冊
請直接產生可編譯程式碼,並列出你修改的檔案與原因。

模板 B:建立時間軸 UI

請在 Blazor Server (global interactive) 專案中建立病人時序圖頁面:
1) Patient ID 輸入欄位 + 查詢按鈕
2) 日期區間篩選
3) Timeline 元件(按日期排序)
4) 點擊事件顯示 Detail Panel
5) 使用可重用元件拆分
請以最小可用版本完成,並附上每個元件用途。

模板 C:重構與品質提升

請檢查目前程式碼並進行重構:
1) 移除重複邏輯
2) 補上 XML 註解
3) 改善命名一致性
4) 增加單元測試(至少涵蓋 mapping)
5) 確保 dotnet build 與 dotnet test 可通過
請提供變更摘要與測試結果。

8.3 對 Codex 下指令的技巧

  • 一次只做一件事(例如「先做 service,不要動 UI」)。
  • 在 prompt 中寫出「完成定義(Definition of Done)」。
  • 要求「不要改動無關檔案」。
  • 每次完成都執行:
    • dotnet build
    • dotnet test(若已有測試)

9. 建議開發里程碑(Milestones)

  • M1:可以輸入 Patient ID 並顯示基本資料。
  • M2:可載入 Encounter 並顯示時間序。
  • M3:可串聯 Condition/Observation/Procedure/MedicationRequest。
  • M4:摘要 + 詳細面板完成。
  • M5:日期篩選、錯誤處理、效能優化。
  • M6:文件化與部署準備。

10. 驗證與測試建議

10.1 最小驗證清單

  1. Patient ID 合法時可取得資料。
  2. Patient ID 不存在時顯示明確錯誤。
  3. 日期區間可正確過濾。
  4. 點擊事件可看到正確明細。
  5. 大量資料仍可順暢瀏覽(必要時分頁/虛擬化)。

10.2 命令列檢查

dotnet restore
dotnet build
dotnet test

11. 風險與排除建議

  • CORS/跨網域問題:改由 Blazor Server 後端代理請求。
  • FHIR 資源關聯不完整:Mapping 層需容忍 null 與缺漏 reference。
  • 資料過大造成 UI 卡頓:使用分段載入、虛擬清單、延遲展開明細。
  • Prompt 太大導致 Codex 回覆失焦:拆小任務、逐步整合。

12. 建議專案初始化命令(範例)

# 1) 建立專案
dotnet new blazor -n PatientTimelineBlazor
cd PatientTimelineBlazor

# 2) 新增常用套件(依需求調整)
dotnet add package Hl7.Fhir.R4

# 3) 啟動
DOTNET_ENVIRONMENT=Development dotnet run

# 4) 驗證建置
dotnet build

13. 交付物定義(你最終應該擁有)

  1. 可執行的 Blazor Server(Global Interactive)專案。
  2. 可輸入 Patient ID 並查詢 Firely FHIR 的時序圖頁面。
  3. 時序圖事件點選後可看完整細節。
  4. 專案文件(README + 本指引檔)。
  5. 基本測試與建置驗證流程。

14. 給 Codex 的「專案總指令」範本(可貼在新對話第一句)

請協助我開發一個 ASP.NET Core Blazor Web App(Interactive Server Global)專案:
- 專案名稱:PatientTimelineBlazor
- 目標:輸入 Patient ID 後,從 https://server.fire.ly 取得病人與相關 FHIR 資源,顯示病人時序圖與摘要
- 資源包含:Encounter、Condition、AllergyIntolerance、Immunization、Device、Observation、Procedure、DiagnosticReport、DocumentReference、MedicationRequest,以及 Organization/Location/Practitioner/PractitionerRole 的關聯資訊
- 要求:
  1) 以服務層封裝 FHIR 查詢
  2) 建立 Timeline 映射模型
  3) 使用元件化 UI 呈現時間軸與明細面板
  4) 支援日期區間篩選、錯誤處理、loading 狀態
  5) 每完成一步都提供:修改檔案清單、程式碼說明、驗證命令
請先從最小可用版本開始,並確保 dotnet build 可通過。

  • 接著,回到 OpenAI Codex
  • 輸入這樣的文字 建立這個專案的 README.md,內容就是上面這個 markdown 的內容
  • 經過一些時間,就發現到這個 ASP.NET Core Blazor 專案已經建立完成了
  • 由於對於這些工具不太孰悉,花了一些時間來熟悉這些工具的使用方式
  • 第一次建立的專案發現到建置上的錯誤與問題
  • 我將這些錯誤訊息貼到 OpenAI Codex 的對話框裡面,讓 OpenAI Codex 來幫我分析這些錯誤訊息,並且給我一些建議的解決方案
  • 經過這次之後,我得到一個正確的 Blazor 專案骨架,並且可以成功地建置與執行這個專案了
  • 現在執行這個專案,看看是否能夠成功地從 Firely Server 上獲取到指定病人的相關 FHIR 資料,並且將這些資料以時序圖的形式展示出來,看看整個系統的功能是否正常運作,以及使用體驗是否良好。
  • 打開瀏覽器,將會看到底下畫面 
  • 點擊 [Patient Timeline] 連結,將會看到這個畫面
  • 由於病歷號已經預設在畫面上了,這裡將僅輸入開始與結束時間
  • 點擊 [Search] 按鈕之後,將會出現這個畫面