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

108 lines
4.8 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
- React Router 規劃 SPA 路由
- Zustand 追蹤 UI 狀態(訪問表單 Modal 與初始座標)
- React Query 統一處理資料讀寫與快取
- React Hook Form + Zod 表單驗證
- react-leaflet + OpenStreetMap 圖資,支援地圖點擊新增足跡
- Tailwind CSS (JIT) 打造快速 UI
### 模組切分
- `features/map`Leaflet 地圖、點擊事件、旅遊標記
- `features/visits`資料型別、LocalStorage Repository、React Query hooks、統計卡片與表單元件
- `components/layout`:頁面主框架、側邊欄
- `state`Zustand store 控制訪問建立/編輯的 Modal
- `components/overlay/VisitModal`:以 Modal 呈現足跡表單,地圖右下角的 `+` 漂浮按鈕或點擊地圖即可開啟
### LocalStorage → API 的切換
- 預設 `VisitProvider mode="local"` 會載入 `localVisitRepository`
- 改為 `mode="api"` 並設定 `apiBaseUrl` 後,就會改用 `VisitApiClient` 透過 REST API 存取。
- Vite `proxy` 已轉發 `/api``http://localhost:4000`,未來後端啟動後無需改動前端呼叫。
### 多語系支援
- 透過 `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`)。
### 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`
## 授權
本專案採用 MIT License詳見 `LICENSE`