# ray910408/fairbite architecture

> Architecture diagram of the GitHub repository ray910408/fairbite, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-28). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/ray910408/fairbite
- Repository: https://github.com/ray910408/fairbite

## Overview

今天吃什麼是多人餐廳決策應用：成員加入房間、設定並準備個人條件，房主搜尋候選，成員投票後由伺服器加權抽選；之後可評分並查看個人足跡。瀏覽器以 Supabase 直接處理文件所述的個人資料與即時讀取，改變房間狀態的操作則交由 Go API。圖中保留自製轉盤、地點調整及天氣等主要能力。Go 與 React 的部分內部連線依 README 架構說明呈現；未取樣的細節不作推定。

Main entry points: [`server/handlers.go`](https://github.com/ray910408/fairbite/blob/main/server/handlers.go) (API 路由與交易), [`web/src/lib/supabase.ts`](https://github.com/ray910408/fairbite/blob/main/web/src/lib/supabase.ts) (Supabase 用戶端), [`web/src/App.tsx`](https://github.com/ray910408/fairbite/blob/main/web/src/App.tsx) (路由與登入狀態), [`web/src/pages/RoomPage.tsx`](https://github.com/ray910408/fairbite/blob/main/web/src/pages/RoomPage.tsx) (房間操作介面)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_web["瀏覽器應用"]
  node_app["路由與登入狀態<br/>[App.tsx]"]
  node_auth["登入註冊<br/>[AuthPage.tsx]"]
  node_home["首頁與自製轉盤<br/>[HomePage.tsx]"]
  node_join["加入房間<br/>[JoinPage.tsx]"]
  node_roompage["房間操作介面<br/>[RoomPage.tsx]"]
end

subgraph group_room["房間決策"]
  node_conditions["條件與準備<br/>[ConditionsForm.tsx]"]
  node_roomstate["房間資料與即時更新<br/>[useRoom.ts]"]
  node_api["房間狀態 API<br/>[api.ts]"]
  node_dbclient["Supabase 用戶端<br/>[supabase.ts]"]
  node_relocation["改地點表決<br/>[relocation.go]"]
end

subgraph group_services["決策服務"]
  node_api_server["API 路由與交易<br/>[handlers.go]"]
  node_authmw["Token 驗證<br/>[auth.go]"]
  node_engine["篩選與機率引擎<br/>[engine.go]"]
  node_places["餐廳搜尋提供者<br/>[places.go]"]
  node_mock["Mock 餐廳資料<br/>[mockdata.go]"]
  node_weather["天氣資料<br/>[weather.go]"]
  node_draw["可重播加權抽選<br/>[draw.go]"]
end

subgraph group_history["用餐足跡"]
  node_historypage["足跡時間軸<br/>[HistoryPage.tsx]"]
  node_rating["餐後評分<br/>[RatingPrompt.tsx]"]
  node_historydata[("同席紀錄<br/>[rescore.go]")]
end

node_guest(("使用者"))
node_google["Google Places"]
node_openmeteo["Open-Meteo"]
node_pg[("Supabase Postgres")]

node_guest -->|"使用"| node_app
node_app -->|"導向登入"| node_auth
node_app -->|"顯示首頁"| node_home
node_app -->|"開啟邀請"| node_join
node_app -->|"開啟房間"| node_roompage
node_auth -->|"驗證帳號"| node_dbclient
node_home -->|"建房讀寫"| node_dbclient
node_join -->|"加入房間"| node_dbclient
node_roompage -->|"編輯條件"| node_conditions
node_roompage -->|"載入與同步"| node_roomstate
node_roompage -->|"呼叫房間操作"| node_api
node_conditions -->|"寫入條件與準備"| node_dbclient
node_roomstate -->|"讀取與訂閱"| node_dbclient
node_api -->|"送出狀態操作"| node_api_server
node_api_server -->|"驗證請求"| node_authmw
node_authmw -->|"傳遞使用者身分"| node_api_server
node_api_server -->|"交易讀寫房間狀態"| node_pg
node_api_server -->|"搜尋候選餐廳"| node_places
node_places -.->|"搜尋（選用）"| node_google
node_places -.->|"未設定金鑰時取用"| node_mock
node_api_server -->|"取得天氣因素"| node_weather
node_weather -->|"查詢天氣"| node_openmeteo
node_api_server -->|"評估候選"| node_engine
node_api_server -->|"執行抽選"| node_draw
node_draw -->|"保存抽選結果"| node_pg
node_api_server -->|"寫入紀錄與讀取重算資料"| node_historydata
node_historypage -->|"讀取個人足跡"| node_dbclient
node_rating -->|"寫回評分"| node_dbclient
node_roompage -->|"發起改地點"| node_relocation
node_relocation -->|"更新房間地點"| node_pg

click node_app "https://github.com/ray910408/fairbite/blob/main/web/src/App.tsx"
click node_auth "https://github.com/ray910408/fairbite/blob/main/web/src/pages/AuthPage.tsx"
click node_home "https://github.com/ray910408/fairbite/blob/main/web/src/pages/HomePage.tsx"
click node_join "https://github.com/ray910408/fairbite/blob/main/web/src/pages/JoinPage.tsx"
click node_roompage "https://github.com/ray910408/fairbite/blob/main/web/src/pages/RoomPage.tsx"
click node_conditions "https://github.com/ray910408/fairbite/blob/main/web/src/components/ConditionsForm.tsx"
click node_roomstate "https://github.com/ray910408/fairbite/blob/main/web/src/hooks/useRoom.ts"
click node_api "https://github.com/ray910408/fairbite/blob/main/web/src/lib/api.ts"
click node_dbclient "https://github.com/ray910408/fairbite/blob/main/web/src/lib/supabase.ts"
click node_api_server "https://github.com/ray910408/fairbite/blob/main/server/handlers.go"
click node_authmw "https://github.com/ray910408/fairbite/blob/main/server/auth.go"
click node_engine "https://github.com/ray910408/fairbite/blob/main/server/engine.go"
click node_places "https://github.com/ray910408/fairbite/blob/main/server/places.go"
click node_mock "https://github.com/ray910408/fairbite/blob/main/server/mockdata.go"
click node_weather "https://github.com/ray910408/fairbite/blob/main/server/weather.go"
click node_draw "https://github.com/ray910408/fairbite/blob/main/server/draw.go"
click node_historypage "https://github.com/ray910408/fairbite/blob/main/web/src/pages/HistoryPage.tsx"
click node_rating "https://github.com/ray910408/fairbite/blob/main/web/src/components/RatingPrompt.tsx"
click node_historydata "https://github.com/ray910408/fairbite/blob/main/server/rescore.go"
click node_relocation "https://github.com/ray910408/fairbite/blob/main/server/relocation.go"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_app,node_auth,node_home,node_join,node_roompage toneBlue
class node_conditions,node_roomstate,node_api,node_dbclient,node_relocation,node_pg toneAmber
class node_api_server,node_authmw,node_engine,node_places,node_mock,node_weather,node_draw toneMint
class node_historypage,node_rating,node_historydata toneRose
class node_guest,node_google,node_openmeteo toneIndigo
```

## Components

### 瀏覽器應用

- [路由與登入狀態](https://github.com/ray910408/fairbite/blob/main/web/src/App.tsx): `web/src/App.tsx`
- [登入註冊](https://github.com/ray910408/fairbite/blob/main/web/src/pages/AuthPage.tsx): `web/src/pages/AuthPage.tsx`
- [首頁與自製轉盤](https://github.com/ray910408/fairbite/blob/main/web/src/pages/HomePage.tsx): `web/src/pages/HomePage.tsx`
- [加入房間](https://github.com/ray910408/fairbite/blob/main/web/src/pages/JoinPage.tsx): `web/src/pages/JoinPage.tsx`
- [房間操作介面](https://github.com/ray910408/fairbite/blob/main/web/src/pages/RoomPage.tsx): `web/src/pages/RoomPage.tsx`

### 房間決策

- [條件與準備](https://github.com/ray910408/fairbite/blob/main/web/src/components/ConditionsForm.tsx): `web/src/components/ConditionsForm.tsx`
- [房間資料與即時更新](https://github.com/ray910408/fairbite/blob/main/web/src/hooks/useRoom.ts): `web/src/hooks/useRoom.ts`
- [房間狀態 API](https://github.com/ray910408/fairbite/blob/main/web/src/lib/api.ts): `web/src/lib/api.ts`
- [Supabase 用戶端](https://github.com/ray910408/fairbite/blob/main/web/src/lib/supabase.ts): `web/src/lib/supabase.ts`
- [改地點表決](https://github.com/ray910408/fairbite/blob/main/server/relocation.go): `server/relocation.go`

### 決策服務

- [API 路由與交易](https://github.com/ray910408/fairbite/blob/main/server/handlers.go): `server/handlers.go`
- [Token 驗證](https://github.com/ray910408/fairbite/blob/main/server/auth.go): `server/auth.go`
- [篩選與機率引擎](https://github.com/ray910408/fairbite/blob/main/server/engine.go): `server/engine.go`
- [餐廳搜尋提供者](https://github.com/ray910408/fairbite/blob/main/server/places.go): `server/places.go`
- [Mock 餐廳資料](https://github.com/ray910408/fairbite/blob/main/server/mockdata.go): `server/mockdata.go`
- [天氣資料](https://github.com/ray910408/fairbite/blob/main/server/weather.go): `server/weather.go`
- [可重播加權抽選](https://github.com/ray910408/fairbite/blob/main/server/draw.go): `server/draw.go`

### 用餐足跡

- [足跡時間軸](https://github.com/ray910408/fairbite/blob/main/web/src/pages/HistoryPage.tsx): `web/src/pages/HistoryPage.tsx`
- [餐後評分](https://github.com/ray910408/fairbite/blob/main/web/src/components/RatingPrompt.tsx): `web/src/components/RatingPrompt.tsx`
- [同席紀錄](https://github.com/ray910408/fairbite/blob/main/server/rescore.go): `server/rescore.go`

### Other components

- **使用者**
- **Google Places**
- **Open-Meteo**
- **Supabase Postgres**

## Connections

- 使用者 → 路由與登入狀態: 使用
- 路由與登入狀態 → 登入註冊: 導向登入
- 路由與登入狀態 → 首頁與自製轉盤: 顯示首頁
- 路由與登入狀態 → 加入房間: 開啟邀請
- 路由與登入狀態 → 房間操作介面: 開啟房間
- 登入註冊 → Supabase 用戶端: 驗證帳號
- 首頁與自製轉盤 → Supabase 用戶端: 建房讀寫
- 加入房間 → Supabase 用戶端: 加入房間
- 房間操作介面 → 條件與準備: 編輯條件
- 房間操作介面 → 房間資料與即時更新: 載入與同步
- 房間操作介面 → 房間狀態 API: 呼叫房間操作
- 條件與準備 → Supabase 用戶端: 寫入條件與準備
- 房間資料與即時更新 → Supabase 用戶端: 讀取與訂閱
- 房間狀態 API → API 路由與交易: 送出狀態操作
- API 路由與交易 → Token 驗證: 驗證請求
- Token 驗證 → API 路由與交易: 傳遞使用者身分
- API 路由與交易 → Supabase Postgres: 交易讀寫房間狀態
- API 路由與交易 → 餐廳搜尋提供者: 搜尋候選餐廳
- 餐廳搜尋提供者 → Google Places: 搜尋（選用）
- 餐廳搜尋提供者 → Mock 餐廳資料: 未設定金鑰時取用
- API 路由與交易 → 天氣資料: 取得天氣因素
- 天氣資料 → Open-Meteo: 查詢天氣
- API 路由與交易 → 篩選與機率引擎: 評估候選
- API 路由與交易 → 可重播加權抽選: 執行抽選
- 可重播加權抽選 → Supabase Postgres: 保存抽選結果
- API 路由與交易 → 同席紀錄: 寫入紀錄與讀取重算資料
- 足跡時間軸 → Supabase 用戶端: 讀取個人足跡
- 餐後評分 → Supabase 用戶端: 寫回評分
- 房間操作介面 → 改地點表決: 發起改地點
- 改地點表決 → Supabase Postgres: 更新房間地點
