Feature 模組架構指南
🛠️ 這是給開發者/工程師的技術文件(程式碼模組架構)。一般使用者看 快速開始 就夠了。
📋 概述
本專案採用 Feature-based Organization(功能導向組織),每個功能模組都是獨立、可插拔的單元。每個 feature 都有一個 Barrel File (index.ts) 定義其公開 API,強制執行封裝並防止功能間的耦合。
🏗️ 架構規則
✅ 正確做法:從 feature 的公開 API 匯入
// ✅ 正確 - 使用 barrel file
import { MedicalChatFeature } from '@/features/medical-chat'
import { DataSelectionDrawer } from '@/features/data-selection'
import { AllergiesCard, VitalsCard } from '@/features/clinical-summary'
import { AuthDialog, useAuthDialog } from '@/features/auth'
❌ 錯誤做法:匯入內部實作
// ❌ 錯誤 - 不要直接存取內部檔案
import MedicalChat from '@/features/medical-chat/components/MedicalChat'
import { useStreamingChat } from '@/features/medical-chat/hooks/useStreamingChat'
❌ 錯誤做法:跨 feature 依賴
// ❌ 錯誤 - Features 之間不應該相互依賴
import { SomeHook } from '@/features/other-feature/hooks/SomeHook'
📦 Feature 目錄
1. Auth(使用者認證)
Entry Point: @/features/auth
import {
AuthDialog,
AuthStatus,
HeaderAuthButton,
useAuthDialog
} from '@/features/auth'
// Usage
<HeaderAuthButton />
<AuthDialog />
功能:
- Firebase Authentication 整合
- Google 登入
- Email/密碼登入
- Email 驗證
- 登入狀態管理
2. Chat History(對話歷史)
Entry Point: @/features/chat-history
import { ChatHistoryDrawer } from '@/features/chat-history'
// Usage
<ChatHistoryDrawer />
功能:
- 依病人分類儲存對話
- Firestore 雲端同步
- 對話搜尋和管理
- 繼續先前的對話
3. Medical Chat(AI 對話)
Entry Point: @/features/medical-chat
import { MedicalChatFeature } from '@/features/medical-chat'
// Usage
<MedicalChatFeature />
功能:
- 直接提問,依問題自行查詢目前病人的 FHIR 資料
- 支援 OpenAI、Gemini、Anthropic 等可用模型
- 提示範本庫與自訂範本
- 語音錄製和轉錄
- 對話歷史整合
4. Clinical Insights(自訂摘要內嵌模組)
Runtime: @/features/clinical-insights/*,由 @/features/medical-summary/Feature 組合
// 不是 right-panel 獨立分頁。
// MedicalSummaryFeature 透過 ClinicalInsightsRuntimeProvider,
// 在「自訂摘要」TabsContent 內呈現 CustomInsightModulesSection。
功能:
- 自訂提示詞與摘要模組
- 最多啟用 5 個模組顯示於醫療摘要的「自訂」子分頁
- 共用臨床洞察設定、執行與快取 provider
- 由模組管理抽屜新增、編輯、排序與重跑
5. Data Selection(AI 資料範圍抽屜)
Entry Point: @/features/data-selection
import { DataSelectionDrawer } from '@/features/data-selection'
// 由 MedicalSummaryFeature 的「設定 → 資料範圍」開啟
<DataSelectionDrawer open={open} onOpenChange={setOpen} />
功能:
- 不是 right-panel 獨立分頁
- 初診/追蹤/自訂等資料範圍範本
- 依病人、就診、報告、用藥、文件細調範圍
- 顯示估算 token 與模型上下文占比
- 標準摘要與自訂摘要共用;臨床對話按問題自行查詢,IPS 匯出另有 scope panel
6. Prompt Gallery(提示範本庫)
Entry Point: @/features/prompt-gallery
import {
PromptGalleryDialog,
usePromptGallery
} from '@/features/prompt-gallery'
// Usage
<PromptGalleryDialog />
功能:
- 瀏覽社群共享的提示範本
- 依類型、專科、標籤篩選
- 分享自己的提示範本
- 使用計數追蹤
7. Settings(設定)
Entry Point: @/features/settings
import { SettingsFeature } from '@/features/settings'
// Usage
<SettingsFeature />
功能:
- AI 偏好設定(模型選擇、API 金鑰)
- 提示範本管理
- 自訂摘要模組管理
- 外觀設定(深色/亮色模式)
8. Clinical Summary(臨床摘要)
Entry Point: @/features/clinical-summary
特殊說明:此 feature 匯出多個卡片元件,支援靈活組合。
import {
AllergiesCard,
DiagnosesCard,
MedListCard,
PatientInfoCard,
ReportsCard,
VisitHistoryCard,
VitalsCard
} from '@/features/clinical-summary'
// Usage - 依需求組合
<div>
<PatientInfoCard />
<VitalsCard />
<MedListCard />
</div>
可用卡片:
AllergiesCard- 過敏史DiagnosesCard- 診斷/病況MedListCard- 用藥清單PatientInfoCard- 病人基本資料ReportsCard- 診斷報告VisitHistoryCard- 就診紀錄VitalsCard- 生命徵象
9. Medical Calculator(醫療計算機)
Entry Point: @/features/medical-calculator
import MedicalCalculatorFeature from '@/features/medical-calculator/Feature'
// Usage(右側面板分頁)
<MedicalCalculatorFeature />
功能:
- MDCalc 風格的臨床計算工具/評分量表,共 10 類、50+ 個(腎、肝、GI、電解質、心血管、肺、血液、神經、精神、一般)
- 自動帶入病人數值:檢驗值依 canonical/LOINC/檢體(
Observation.specimen)解析後自動填入,顯示原始單位並在維度相符時自動換算(僅在真正無法換算時顯示 ⚠) - 每個計算機附「適用時機(When to Use)」與「注意事項(Pearls/Pitfalls)」,結果含風險分層與處置建議
- 我的最愛、最近使用、依受眾(醫療/民眾)與科別/用途篩選、搜尋
- 民眾可自填的量表(PHQ-9、GDS-15、Epworth…)
- 結果可一鍵複製成病歷可貼上的一行摘要
資料驅動架構:calculators/(依類別分檔,每個 CalculatorDef 帶純函式 compute)+純模組 list-logic.ts/format.ts/autofill-compute.ts(resolveInput 為自動帶入的唯一真相來源),154 個單元測試。新增一個計算機=新增一筆 CalculatorDef(+ CALC_TAGS/CALC_INFO)。
10. Medical Summary(醫療摘要)
Entry Point: @/features/medical-summary/Feature
import MedicalSummaryFeature from '@/features/medical-summary/Feature'
// Usage(右側面板第一個分頁,開啟病人後的預設分頁)
<MedicalSummaryFeature />
功能:
- 零點擊 AI 簡報:載入病人後自動產生,單頁縱向流
- 跨院病程摘要:3–5 句敘事,附逐筆對回 FHIR bundle 驗證的引用;查無來源標「未驗證」
- 用藥安全警示(內嵌):
features/proactive-safety-alerts的SafetyAlertsPanel以 embedded 模式呈現,依嚴重度分級密度 - 跨院時間軸:App 端確定性抽取事件骨架(日期、院所、就診類別),AI 只負責策展與標籤——零幻覺日期/院所
- 資料涵蓋卡:純計算(零 AI)——日期範圍、院所數、各資源計數與健康存摺涵蓋邊界聲明
- 雙受眾:醫療人員版/民眾版跟隨全域 audience,各自生成與快取(12 小時)
「臨床洞察」(第 4 節)不再是 right-panel 分頁,而是內嵌於本功能的「自訂摘要」子分頁;資料選擇也由本功能的設定選單開啟。
11. Report Interpretation(報告 AI 翻譯解讀)
Entry Point: @/features/report-interpretation
import { ReportInterpretationButton, ReportInterpretationPanel } from '@/features/report-interpretation'
不是右側面板分頁,而是內嵌在報告/文件卡片標頭的小型子功能——每則報告可一鍵生成忠實中譯 + 白話解讀,面板顯示在原文上方。
功能:
- 隨選生成、不預先耗用額度:按鈕按下才呼叫 AI;依
reportId::audience::locale::contentSig快取,不同呈現位置(列表內/右側面板 dock)共用同一份結果 - 忠實翻譯優先:譯文是嚴格的忠實轉譯防火牆,解釋只出現在「解讀」欄位(防幻覺);不輸出「建議詢問醫師」清單,直接把答案講清楚
- 雙受眾:醫師/民眾皆可用,語氣依
useAudience()調整;免責聲明恆常顯示、不可收合 - 三個掛載點:
ReportRow.tsx(單一長文報告/結構化 panel 報告)、DocumentSummaryCard.tsx(出院病摘/IPS 文件)、MultiRegionStudyCard.tsx的NarrativeSubCard(健保碼共用卡內的子報告)
🔗 依賴規則
Features 可以依賴:
- ✅
@/src/core/*- 領域實體和用例 - ✅
@/src/application/*- 應用層 hooks 和 providers - ✅
@/src/infrastructure/*- 基礎設施服務 - ✅
@/src/shared/*- 共用工具和元件 - ✅
@/components/ui/*- UI 元件庫(shadcn/ui)
Features 不可以依賴:
- ❌
@/features/*- 其他 features(絕對禁止)
📁 內部結構
每個 feature 遵循以下結構:
features/
feature-name/
├── index.ts # 🚪 公開 API (Barrel File)
├── Feature.tsx # 主要元件
├── components/ # 內部元件
├── hooks/ # 內部 hooks
├── services/ # 內部服務(如有)
├── utils/ # 內部工具函數
└── types/ # 內部類型定義
只有 index.ts 的匯出是公開的。 其他所有內容都是內部實作。
🎯 優勢
- 封裝性 - 內部變更不影響使用者
- 清楚邊界 - 容易理解什麼是公開 vs 私有
- 重構安全 - 可以重組內部結構而不破壞匯入
- 防止耦合 - 強制 features 保持獨立
- 更好的 Tree-shaking - 打包工具可以優化未使用的程式碼
- 可插拔 - 透過 Registry 輕鬆啟用/停用功能
🔌 可插拔架構
左側 Panel(臨床摘要)
Registry 配置:src/shared/config/feature-registry.ts
export const CLINICAL_SUMMARY_FEATURES: FeatureConfig[] = [
{
id: 'patient-info',
name: 'Patient Information',
component: PatientInfoCard,
tab: 'patient',
order: 0,
enabled: true,
},
// ...
]
新增功能:
- 建立功能元件
- 在
feature-registry.ts註冊 - 完成!無需修改 Layout
右側 Panel(AI 功能)
Registry 配置:src/shared/config/right-panel-registry.ts
export const RIGHT_PANEL_FEATURES: FeatureConfig[] = [
{
id: 'medical-chat',
name: 'Medical Chat',
tabLabel: 'medicalChat',
component: () => null,
order: 0,
enabled: true,
},
// ...
]
🛡️ 強制執行
ESLint 規則
建議加入 ESLint 規則來強制執行這些模式:
{
"rules": {
"no-restricted-imports": [
"error",
{
"patterns": [
{
"group": ["@/features/*/*"],
"message": "Import from feature's index.ts instead: @/features/feature-name"
}
]
}
]
}
}
❓ 常見問題
Q: 如果需要在 features 之間共享功能怎麼辦?
考慮以下選項:
- 移到
@/src/shared/*- 用於 UI 元件或工具函數 - 移到
@/src/core/*- 用於業務邏輯 - 移到
@/src/application/*- 用於應用層級的關注點
絕對不要在 features 之間建立直接依賴。
Q: 如何新增一個新的 feature?
- 在
features/目錄建立新資料夾 - 建立
index.tsbarrel file - 建立
Feature.tsx主要元件 - 在適當的 registry 註冊(如果需要)
- 匯出公開 API
Q: 可以在 feature 內部使用其他 feature 的元件嗎?
不可以。如果需要共享元件,應該將其移到 @/src/shared/components/ 或 @/components/ui/。
📚 相關文件
- ARCHITECTURE.md - 完整系統架構
- AI_AGENT_IMPLEMENTATION.md - AI Agent 實作指南
- MEDICAL_CHAT.md - Medical Chat 功能指南
🎯 總結
Feature 模組架構提供:
✅ 清楚的邊界:每個 feature 都是獨立單元
✅ 封裝性:內部實作細節隱藏
✅ 可維護性:容易理解和修改
✅ 可擴展性:透過 Registry 輕鬆新增功能
✅ 重構安全:內部變更不影響外部
遵循這些規則可以保持程式碼庫的整潔和可維護性。