尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗LINE 群組 Bot + LIFF 記分頁。管理員在群組裡用指令或記分頁記分,Bot 把結果和排行回到群組;其他牌友不用加好友,想看個人戰績的人再到記分頁「認領」自己的名字。
分數只作為遊戲紀錄,不具任何金錢價值。
flowchart LR
subgraph LINE
G[牌友群組] -- 指令 /記 /戰績 ... --> OA[官方帳號<br/>Messaging API]
L[LIFF 記分頁<br/>在 LINE 裡開啟]
end
OA -- webhook --> F
F -- 回覆 / 推播 --> OA
L -- 頁面 --> V[Vercel<br/>liff/index.html]
L -- API + LINE ID token --> F
subgraph Supabase
F[Edge Function mj] --> DB[(Postgres<br/>rooms / players / games / scores / room_admins)]
end
GH[GitHub main] -- push 自動部署 --> V
| 元件 | 負責什麼 | 程式位置 |
|---|---|---|
| LINE 官方帳號(Messaging API) | 群組裡收指令、回覆、推播 | — |
| LINE Login channel + LIFF | 記分頁在 LINE 裡打開、取得使用者身分 | — |
Supabase Edge Function mj | Bot webhook + 記分頁用的 API | supabase/functions/mj/ |
| Supabase Postgres | 存房間、玩家、對局、管理員 | supabase/migrations/ |
| Vercel | 放記分頁(純靜態,只發佈 liff/) | liff/index.html、vercel.json |
| GitHub | 原始碼;推到 main 會觸發 Vercel 部署 | 這個 repo |
| 項目 | 值 |
|---|---|
| GitHub repo | yuxing-lee/mahjong(分支 main) |
| 本機資料夾 | C:\Users\user\Desktop\Side Project\majong-line |
| Supabase 專案 | majong-line,ref hofjzjhqizukceosjufr(Singapore) |
| Edge Function | mj(Verify JWT 關閉) |
| Webhook URL | https://hofjzjhqizukceosjufr.supabase.co/functions/v1/mj/webhook |
| 記分頁 API | https://hofjzjhqizukceosjufr.supabase.co/functions/v1/mj/api |
| 記分頁網址(Vercel) | https://mahjong-gold-ten.vercel.app |
| LINE Provider | AI助手 |
| LIFF ID | 2011866186-iudTebek(LIFF URL:https://liff.line.me/2011866186-iudTebek) |
| 名稱 | 從哪裡拿 |
|---|---|
LINE_CHANNEL_SECRET | Messaging API channel → Basic settings → Channel secret |
LINE_CHANNEL_ACCESS_TOKEN | Messaging API channel → Messaging API 分頁最下面 → Channel access token (long-lived) |
LINE_LOGIN_CHANNEL_ID | LINE Login channel(LIFF 所在的那個)→ Basic settings → Channel ID |
LIFF_ID(選填) | 沒設的話程式預設用 2011866186-iudTebek |
SUPABASE_URL、SUPABASE_SERVICE_ROLE_KEY 由 Supabase 自動提供,不用設。在 Supabase 上程式會自動使用資料庫;STORE 只有本機測試才需要。
這些值不要放進 repo、也不要截圖外流。 外流的話到 LINE Developers 按 Issue 重新產生,再更新 Secrets。
| 指令 | 誰能用 | 說明 |
|---|---|---|
/開房 週五麻將 | 任何人(建的人=房主) | 把群組設成計分房 |
/加人 小明 阿華 老王 阿美 | 管理員 | 加玩家(名字不能有數字、+、-) |
/記 小明+100 阿華-30 老王-70 | 管理員 | 記一場,總和必須是 0(也接受「小明 100 阿華 -30」和全形數字) |
/戰績 | 所有人 | 排行榜卡片(附「開啟記分頁」按鈕) |
/最近 | 所有人 | 最近 5 場 |
/分析 名字 | 所有人 | 個人摘要:勝率、近 10 場、最順的同桌、剋星、提款機(不打名字=看自己,需先認領) |
/撤銷 | 管理員 | 刪最後一場 |
/刪房 | 管理員 | 刪除房間和所有紀錄(會先要求 /刪房 確認) |
/設台費 名字、/取消台費 名字 | 管理員 | 台費帳戶(例如場主設備錢「東」)照樣記分、照樣出現在排行,但不列入個人分析 |
/消費 飲料 300 | 管理員 | 記一筆額外消費(例如飲料錢),只記品項和總金額,不算進任何人的輸贏 |
/消費 | 所有人 | 看這個月的台費收入、額外消費、結餘和最近幾筆消費 |
/選單 | 所有人 | 回一張按鈕卡片:記分、排行、分析、走勢、紀錄、東的消費(點了直接開到記分頁那一頁),下面再一排戰績/最近/本月帳。輸入框上方的快速按鈕也有「選單」 |
/設管理員 @某人 | 管理員 | 設成管理員(也可以用已認領的名字:/設管理員 阿華) |
/移除管理員 @某人 | 管理員 | 取消管理員(房主不能被移除) |
/管理員 | 所有人 | 列出房主和管理員 |
/記分頁 | 所有人 | 取得記分頁連結 |
/說明 | 所有人 | 指令列表 |
/ 開頭的訊息 Bot 不回,不會洗版。/戰績。&tab=record|rank|analysis|trend|history|expense 直接開到某一頁(/選單 的按鈕就是這樣做的);沒權限的分頁會退回第一頁?demo=1 進入試玩模式:不用登入、不連後端,資料只存在那台裝置liff/index.html)推到 GitHub main 就好,Vercel 會自動部署,LINE 不用改。
git add liff/index.html
git commit -m "..."
git push origin main
supabase/functions/mj/)推 GitHub 不會自動更新 Supabase,要另外部署:
npx supabase login # 第一次才需要
npx supabase functions deploy mj --project-ref hofjzjhqizukceosjufr
supabase/config.toml 已經把 mj 設成 verify_jwt = false。如果改從 Supabase 後台部署,記得也要把 Verify JWT 關掉,不然 LINE webhook 和記分頁都會被擋(401)。
supabase/migrations/ 新增一個檔案,例如 003_xxx.sqlnpx supabase link --project-ref hofjzjhqizukceosjufr 後 npx supabase db push目前的資料表:
| 表 | 內容 |
|---|---|
rooms | 房間;line_group_id 綁群組、admin_line_user_id 是房主、code 是記分頁連結用的房號 |
players | 玩家名字;line_user_id 有值代表已被認領 |
games | 每一場 |
scores | 每場每人的分數 |
room_admins | 房主以外的管理員 |
players.is_house = true 代表台費帳戶(目前「紅中」房的「東」)。
記一場是透過資料庫函式 record_game_at()(可指定日期;舊的 record_game() 保留未用),在同一個交易裡再檢查一次「至少兩人、總和為 0、玩家屬於這個房間」。
所有表都開了 RLS 但沒有 policy,這是刻意的:網頁不直接連資料庫,所有讀寫都經過 Edge Function(service role)。Supabase 的安全檢查會提示「RLS Enabled No Policy」,可以忽略。
liff/index.html 最上面的 LIFF_ID、API_BASE兩個 channel 都在 AI助手 Provider 底下(必須同一個 Provider,userId 才對得上)。
Messaging API channel(Bot)
https://hofjzjhqizukceosjufr.supabase.co/functions/v1/mj/webhook,Use webhook 開啟,Verify 成功官方帳號(manager.line.biz → 設定)
LINE Login channel
LINE_LOGIN_CHANNEL_ID2011866186-iudTebek:Size Full、Scopes 勾 openid、profile、Endpoint URL = https://mahjong-gold-ten.vercel.app新的 Messaging API channel 不能直接在 Developers Console 建立,要先在 manager.line.biz 建官方帳號,再到「設定 → Messaging API」啟用。
| 狀況 | 原因 / 處理 |
|---|---|
| Bot 加進群組馬上退出 | 官方帳號沒開「接受邀請加入群組」 |
| Webhook Verify 顯示 timeout | 剛改 Secrets 或剛部署時函式在重啟,等幾秒再按一次 |
| Webhook Verify 顯示 401 | LINE_CHANNEL_SECRET 錯,或 Verify JWT 沒關 |
| 記分頁顯示「LINE Login Channel ID 設定不符」 | LINE_LOGIN_CHANNEL_ID 填成別的 channel 的 ID |
| 記分頁顯示「登入已過期」 | 關掉頁面重新開啟 |
| 記分頁顯示「拿不到 LINE 登入資訊」 | LIFF 的 Scopes 沒勾 openid |
| 群組打指令沒反應 | 看 Supabase → Edge Functions → mj → Logs;確認 Use webhook 有開、自動回應有關 |
| 私訊 Bot 只回「請把我加進群組」 | 目前設計是房間綁群組,指令要在群組裡用 |
查紀錄:Supabase 後台 → Edge Functions → mj → Logs / Invocations。
.
├─ liff/index.html 記分頁(單一檔案,內建試玩模式)
├─ vercel.json Vercel 只發佈 liff/,不跑 build
├─ deno.json dev / test / check 指令
├─ .env.example 本機測試用的環境變數範本
└─ supabase/
├─ config.toml CLI 設定(mj 關閉 verify_jwt)
├─ migrations/
│ ├─ 001_init.sql rooms / players / games / scores + record_game()
│ ├─ 002_room_admins.sql 多位管理員
│ ├─ 003_house_player.sql 台費帳戶(players.is_house)
│ ├─ 004_game_date.sql record_game_at():記分時可指定日期
│ └─ 005_expenses.sql expenses 表:額外消費(品項、金額、日期)
└─ functions/mj/
├─ index.ts Bot webhook + 記分頁 API
├─ logic.ts 解析分數、計算戰績、個人分析(純邏輯)
├─ store.ts 儲存介面;在 Supabase 上自動用資料庫,本機預設用 JSON 檔
├─ store_supabase.ts Supabase 實作
├─ store_file.ts JSON 檔實作(本機測試用)
└─ logic_test.ts / e2e_test.ts 測試
.../functions/v1/mj/ 底下)| 路由 | 說明 |
|---|---|
POST webhook | LINE webhook(用 Channel secret 驗簽章) |
GET api/room?code=房號 | 記分頁讀資料 |
GET api/analysis?code=房號&player=玩家ID | 個人分析 |
POST api/game | 記一場(管理員,可帶 played_at 補記日期),成功後推播到群組 |
POST api/game/delete | 刪一場(管理員) |
POST api/game/date | 改某場的日期(管理員) |
POST api/game/split | 把一場拆成兩桌(管理員;檢查分數對得上後新增兩場、刪掉原本那場) |
POST api/player | 加玩家(管理員) |
POST api/claim | 認領名字 |
GET health | 健康檢查 |
api/* 需要 Authorization: Bearer <LINE ID token>,由記分頁的 LIFF SDK 自動帶入。
需要 Deno 2。
deno task test # 單元測試 + 端到端測試(不連 LINE、不連 Supabase)
deno task check # 型別檢查
想在本機跑一個完整的 Bot(資料存在 ./data.json):
cp .env.example .env # 填 LINE 的值,STORE=file
deno task dev # http://localhost:8000
cloudflared tunnel --url http://localhost:8000 # LINE 需要 HTTPS
再把 LINE 的 Webhook URL 暫時改成 https://<通道網址>/webhook、記分頁的 API_BASE 改成 https://<通道網址>/api。測完記得改回 Supabase 的網址。
沒填 LINE_CHANNEL_ACCESS_TOKEN 時,Bot 要送的訊息只會印在終端機。