跳至主要内容

專案程式結構

本文說明花店管理系統參考實作的程式結構,包括後端 (app-server)、前端 (app-web / app-web-mockup) 的目錄組織與各層職責。

模組總覽

模組關係圖

各模組定位

模組定位API 方式技術棧
app-web-mockupPrototype 參考模板Mock (MSW)React 19 + TypeScript
app-web生產級 SPAMock → 真實(漸進切換)React 19 + TypeScript
app-server生產級 RESTful API真實 APISpring Boot 3.5 + Java 25
app-web-host前端托管層N/ASpring Boot (WAR)
app-docs-host文檔托管層N/ASpring Boot (WAR)
app-docs應用文檔站N/ADocusaurus

app-server 結構

Package 結構

io.leandev.app/
├── actuator/ # 健康檢查端點
├── config/ # 應用配置
│ ├── SecurityConfig # JWT + OAuth2 + Spring Security
│ ├── TenantConfig # 多租戶配置
│ ├── CacheConfig # 快取配置
│ ├── FileStorageConfig # 檔案儲存配置
│ └── ...

├── controller/ # REST API 層
│ ├── auth/ # 認證端點
│ ├── customer/ # 客戶管理
│ ├── order/ # 訂單管理
│ ├── sales/ # 產品管理
│ └── ...

├── dto/ # DTO 與請求物件
│ ├── auth/
│ ├── order/
│ └── ...

├── entity/ # JPA 實體
│ ├── auth/ # Account, Role, Authority
│ ├── base/ # 基礎類別(AuditableTenantEntity)
│ ├── customer/ # Customer
│ ├── order/ # Order, OrderItem
│ ├── sales/ # Product, ProductCategory
│ └── tenant/ # Tenant

├── exception/ # 自訂異常
├── handler/ # 全域異常處理(RFC 7807)
├── initializer/ # 資料初始化
├── mapper/ # MapStruct 映射器
├── repository/ # Spring Data JPA
├── scheduler/ # 排程任務
├── security/ # 安全相關
├── service/ # 業務邏輯層
│ ├── auth/
│ ├── cache/
│ ├── customer/
│ ├── file/
│ ├── mail/
│ ├── order/
│ └── sales/
└── util/ # 工具函數

各層職責

層級職責說明
ControllerHTTP 請求處理參數驗證、權限檢查(@PreAuthorize)、呼叫 Service
Service業務邏輯事務管理(@Transactional)、業務規則、快取
Repository資料持久化Spring Data JPA、自動多租戶過濾
Entity資料模型JPA 實體、驗證註解、狀態管理
Config應用配置依賴注入、框架配置

核心設計特點

多租戶架構

  • Entity 層:繼承 AuditableTenantEntity,自動注入 tenantId
  • Repository 層:繼承 TenantAwareRepository,自動過濾租戶資料
  • 無需手動:開發者不需撰寫 WHERE tenant_id = ? 條件

Entity 繼承結構

TenantAwareEntity(框架提供)

AuditableTenantEntity(應用層基類)

具體業務實體(Order, Product, Customer)

DTO vs PropertyMap 策略

情境使用範例
輸入結構 ≠ EntityDTOCreateOrderRequest
輸入結構 = EntityPropertyMapProduct、Customer 的 CRUD
PATCH 部分更新PropertyMap天然支援部分欄位更新

開發規範摘要

應該做

  • 使用 TenantContext 自動獲取租戶 ID
  • 利用 Hibernate Filter 自動過濾多租戶資料
  • Service 層統一負責事務邊界
  • 使用語義化異常(NotFoundExceptionDuplicateException

避免

  • Repository 層的讀取操作加 @Transactional
  • 在 Entity 中混合業務邏輯與映射邏輯
  • 手動編寫租戶過濾 WHERE 子句

app-web / app-web-mockup 結構

目錄結構

src/
├── applets/ # 業務功能模組
│ ├── customer-applet/ # 客戶管理
│ ├── order-applet/ # 訂單管理
│ ├── product-applet/ # 產品管理
│ ├── dashboard-applet/ # 儀表板
│ ├── delivery-applet/ # 配送管理
│ └── shared/ # 跨模組共用

├── components/ # 全域應用組件
│ ├── applet-shell/ # Applet 外框
│ ├── application-launcher/ # 應用啟動器
│ ├── loading-fallback/ # 載入中 UI
│ └── ...

├── features/ # Redux Slices
│ ├── iam/ # 身份與授權
│ │ └── me-slice.ts # 使用者狀態
│ ├── crm/ # CRM 相關
│ ├── product/ # 產品相關
│ └── root-reducers.ts # 根 reducers

├── hooks/ # 全域自定義 Hooks
├── layouts/ # 佈局組件
├── mocks/ # MSW 配置(開發環境)
│ ├── browser.ts # MSW worker
│ ├── handlers/ # API 處理器
│ └── data/ # Mock 數據

├── nls/ # 國際化資源
├── pages/ # 系統頁面
├── routes/ # 路由配置
├── services/ # API 服務層
│ ├── api-client.ts # Axios HTTP 客戶端
│ ├── core/ # 核心服務
│ └── iam/ # 認證服務

├── store/ # Redux Store 配置
├── types/ # TypeScript 類型
├── utils/ # 工具函數

├── App.tsx # 應用主組件
├── main.tsx # 應用入口
└── tailwind.css # Tailwind 配置

各目錄職責

目錄職責說明
applets/業務功能模組花店系統特定功能(客戶、訂單、產品等)
applets/shared/跨模組共用跨 Applet 共用的組件和 hooks
components/全域應用組件與框架庫無關的應用層組件
features/Redux Slices全域狀態管理(用戶、授權、應用配置)
hooks/自定義 Hooks跨組件共用的 hooks
layouts/佈局組件頁面頭部、菜單、側邊欄
mocks/MSW 配置Mock API 端點、種子數據
nls/國際化資源多語言翻譯文件
routes/路由配置路由定義和路由保護
services/API 服務層HTTP 客戶端、API 調用
store/Redux StoreStore 配置、中間件
types/類型定義全域 TypeScript 類型

Applet 架構模式

每個 Applet(業務模組)遵循統一結構:

xxx-applet/
├── components/ # 該模組特有的 UI 組件
├── hooks/ # 該模組的自定義 hooks
├── utils/ # 該模組的工具函數
├── types.ts # 該模組的類型定義
├── index.ts # 模組導出
├── xxx-applet.tsx # 模組主組件(路由入口)
├── xxx-finder.tsx # 搜尋/列表頁面
├── xxx-detail.tsx # 詳細頁面
├── xxx-editor.tsx # 編輯/新增頁面
└── xxx-form.tsx # 共用表單組件
組件職責
xxx-applet.tsx路由入口,定義模組級路由
xxx-finder.tsx列表/搜尋頁面
xxx-detail.tsx詳細頁面
xxx-editor.tsx編輯/新增頁面
xxx-form.tsx表單邏輯,可被 editor 和 detail 複用

開發規範摘要

色彩規範(必須遵守)

// ❌ 禁止硬編碼顏色
className="text-gray-900 bg-blue-500 dark:text-white"

// ✅ 使用 DaisyUI 語義化顏色
className="text-base-content bg-primary"

國際化(必須遵守)

// ❌ 禁止硬編碼中文
<button>創建客戶</button>

// ✅ 使用 useTranslation
import { useTranslation } from '@appfuse/appfuse-web'
const { t } = useTranslation()
<button>{t('Create Customer')}</button>

用戶通知(必須遵守)

// ❌ 禁止原生對話框
alert('成功')
confirm('確認?')

// ✅ 使用 prompt API
import { prompt } from '@appfuse/appfuse-web'
prompt.success('Customer created')
prompt.confirm('確認刪除?')

TypeScript(必須遵守)

  • 禁止使用 any
  • 必須定義明確類型

app-web vs app-web-mockup 差異

項目app-web-mockupapp-web
用途Prototype,需求確認生產級應用
API 方式僅 Mock (MSW)Mock → 真實(可切換)
後端服務無需需要 app-server
生產部署不適用需要 app-web-host(WAR 封裝)
數據持久化內存(刷新丟失)資料庫
主要受眾產品經理、設計師開發團隊、運維

程式碼差異:極小,MSW 控制方式相同:

  • 開發環境(npm run dev):MSW 自動啟用
  • 生產環境(npm run build):MSW 預設關閉

詳細說明請參閱「Mock → 真實 API 漸進切換


技術棧總覽

後端 (app-server)

類別技術
框架Spring Boot 3.5.6
語言Java 25
建構Gradle (Kotlin DSL)
ORMSpring Data JPA + Hibernate
安全Spring Security + OAuth2 Resource Server + JWT
資料庫H2(開發)/ MySQL / PostgreSQL / Oracle / SQL Server
快取Spring Cache + 自訂實作
檔案儲存Local / Database / S3 / Azure / SFTP

前端 (app-web / app-web-mockup)

類別技術
框架React 19
語言TypeScript 5.9
建構Vite 7
狀態管理Redux Toolkit + TanStack React Query
路由React Router 7
表單React Hook Form
樣式TailwindCSS 4 + DaisyUI 5
HTTPAxios
MockMSW (Mock Service Worker)
測試Vitest + Playwright

相關資源