Files
traveling-around-the-world/README.md

143 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# traveling-around-the-world
一個以 React 為核心的單頁式應用程式SPA用來記錄自己走訪過的國家、城市與時間軸。初期資料儲存在瀏覽器 LocalStorage並預留後端 Express + MongoDB 的擴充架構,後續可平滑升級成多人同步的雲端服務。
## Monorepo 結構
```
traveling-around-the-world/
├─ client/ # Vite + React + TS 的前端 SPA
├─ server/ # Express + MongoDB (未來) API 服務
└─ shared/ # 前後端共用的型別定義
```
- `client` 預設採 LocalStorage 擷取資料,並透過 `VisitProvider` 可快速切換成 API 模式。
- `server` 已放好 Express + Mongoose 架構與 RESTful routes只需接上 MongoDB 並啟動即可提供資料。
- `shared` 放行程型別 `VisitDto`,讓前後端保持相同資料契約。
## 前端client
### 技術與工具
- Vite + React 18 + TypeScript
- Material UI + Emotion 建構一致的 UI 與主題
- React Router 規劃 SPA 路由
- Zustand 追蹤 UI 狀態(訪問表單 Modal 與初始座標)
- React Query 統一處理資料讀寫與快取
- React Hook Form + Zod 表單驗證
- react-leaflet + OpenStreetMap 圖資,支援地圖點擊新增足跡
- i18next 支援中英文切換,分類與設定等字串同步集中管理
### 模組切分
- `features/map`Leaflet 地圖、點擊事件、旅遊標記
- `features/visits`資料型別、LocalStorage Repository、React Query hooks、統計卡片與表單元件
- `features/categories`:旅程分類 CRUD、React Query 與 sidebar 管理介面
- `components/layout`MUI AppBar + Drawer 布局、語言切換等元件
- `state`Zustand store 控制訪問建立/編輯的 Modal
- `components/overlay/VisitModal`:以 Modal 呈現足跡表單,必須先點擊地圖右下角的 `+` 漂浮按鈕啟用定位,再第二次點擊地圖開啟表單
- `components/overlay/NavControlsDialog`App Bar 右上角的「更多」按鈕會開啟的快速操作 Modal語言、分類切換、相關連結
### LocalStorage → API 的切換
- 預設 `VisitProvider mode="local"` 會載入 `localVisitRepository`
- 改為 `mode="api"` 並設定 `apiBaseUrl` 後,就會改用 `VisitApiClient` 透過 REST API 存取。
- Vite `proxy` 已轉發 `/api``http://localhost:4000`,未來後端啟動後無需改動前端呼叫。
### 旅程分類管理
- 所有旅程可指定分類,未指定時會自動歸入「未分類」。
- 側邊欄可透過 chip 快速篩選「全部 / 未分類 / 自訂分類」。
- 在「管理分類」清單可新增、重新命名或刪除分類;刪除時相關旅程會回到「未分類」。
- 當前分類會記錄在 LocalStorage在地圖右下角新增旅程時會自動帶入。
### 快速操作面板
- App Bar 右上角改為「更多」圖示,點擊後會開啟 Modal。
- Modal 集中展示語言切換、目前分類切換以及開發相關連結OpenStreetMap、React Leaflet
- 便於未來擴充更多設定選項,而不把 App Bar 擠得太滿。
### PWA 支援
- 新增 Web App Manifest`client/public/manifest.webmanifest`)與 service worker 註冊,可在行動裝置安裝為獨立 App。
- 透過 `vite-plugin-pwa` 自動產生快取策略,支援離線瀏覽與版號自動更新。
- 內建 `icons/icon-192.svg``icons/icon-512.svg`,可於日後替換為專屬圖示。
### 多語系支援
- 透過 `react-i18next` 提供繁體中文與英文,語系檔位於 `client/src/locales/`
- 右上角的語言選單 (`LanguageSwitcher`) 可即時切換語言,並記錄在 LocalStorage 方便下次載入。
### 開發啟動
1. 安裝相依套件:`cd client && npm install`
2. 啟動開發伺服器:`npm run dev`
3. 瀏覽器開啟 `http://localhost:5173`
> **注意**Leaflet 需要載入 CSS已在 `TravelMap` 中引入 `leaflet/dist/leaflet.css`)。
### 專案建置
- 推薦將 `client/package.json``build` 指令改為 `"build": "tsc --noEmit && vite build"`,避免 `tsconfig.node.json``noEmit` 限制造成錯誤。
- 調整後可執行 `npm run build`,產出靜態檔案於 `client/dist`
- 首次啟用 PWA 時記得在 `client` 目錄重新執行 `npm install`,以安裝 `vite-plugin-pwa` 相依套件。
### 部署到 Vercel
1. 先在本地確認 `npm run build` 可成功(參考上節的建置指令變更)。
2. 將整個專案推送至 GitHub / GitLab / Bitbucket。
3. 在 Vercel 建立新專案時:
- Project Root`client`
- Build Command`npm run build`
- Output Directory`dist`
4. 連續部署Vercel 會在每次 push default branch、自動建立 preview 的 PR 觸發建置並更新站台。
5. 若後續要加上環境變數,可在 Vercel 專案設定內補上即可。
### Docker Compose 啟動
若想直接以容器方式啟動整個堆疊MongoDB + Node API + Nginx 前端):
1. 建立映像:`docker compose build`
2. 啟動服務:`docker compose up -d`
3. 前端:<http://localhost:3000>
4. API<http://localhost:4000>
> 預設前端仍採 LocalStorage。如果要改用 API 資料來源,請在 `client/src/app/App.tsx` 把 `VisitProvider mode="local"` 改成 `mode="api"`。
## 後端server
### 技術堆疊
- Express 4
- Mongoose 8 + MongoDB內建 visit schema資料結構與前端共用
- Zod 驗證 API 請求 payload
- Helmet、CORS、Morgan 提供基礎安全與紀錄
### 架構亮點
- `src/app.ts` 建立 Express App、共用中介層、`/health` 健康檢查
- `src/modules/visits`模型、Service、Controller、Router 切分清晰
- `visit.mapper.ts` 將 Mongoose Doc 轉成 `shared/visit.ts` 的 DTO
- `infra/db/mongo.ts` 佈建 Mongo 連線抽象
### 啟動指令
1. 安裝套件:`cd server && npm install`
2. 建立 `.env`(可複製 `.env.example`)並設定 `MONGODB_URI`
3. 開發模式:`npm run dev`
4. 編譯產出:`npm run build` -> `dist/`
RESTful 端點:
- `GET /api/visits`:取得全部足跡
- `POST /api/visits`:新增足跡
- `GET /api/visits/:id`
- `PUT /api/visits/:id`
- `DELETE /api/visits/:id`
## 共享型別shared
- `shared/visit.ts` 定義 Visit DTO前端 `Visit` 及後端回傳皆採相同結構。
- Vite 透過 `@shared/*` alias 匯入,後端則直接使用相對路徑,確保型別同步。
## 開發流程建議
1. **LocalStorage MVP**:僅啟動前端即可使用,點擊地圖開啟表單、資料存在瀏覽器。
2. **串接 API**:建立 MongoDB啟動 `npm run dev` 後將前端 `VisitProvider` 切換到 API 模式。
3. **Geocoding**:前端已透過 Nominatim 反向地理編碼在點擊地圖時預填國家 / 城市;若需更高配額可在後端建立 Proxy。
4. **照片/檔案**:後端可擴增 S3/Cloudinary 上傳,再於前端 `VisitCreateInput` 增加檔案欄位。
## 待辦與下一步
- [ ] 實作 geocoding proxy於點擊地圖後自動填入國家 / 城市
- [ ] 加入使用者認證(如 Auth0 或自建 JWT以支援多人服務
- [ ] 將訪問紀錄導出成時間線或統計圖表D3 / Recharts
- [ ] 建立 Vitest / Jest 單元測試與 React Testing Library 元件測試
- [ ] 規劃 CIGitHub Actions自動執行 `lint``test`
- [ ] 自動化部署流程模板Vercel / GitHub Actions
## 授權
本專案採用 MIT License詳見 `LICENSE`