OpenAthlete
AGPLv3 endurance training platform: EU-oriented hosting, transparent CTL/ATL/TSB logic in code, self-hosting, and full export. Built in Grenoble.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證แอปสำหรับช่วยจัดคู่แบดมินตันแบบรวดเร็ว พร้อมเลือกจำนวนคอร์ดและสุ่มผู้เล่นลงสนาม
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
แอปสำหรับช่วยจัดคู่แบดมินตันแบบรวดเร็วและยุติธรรม รองรับทั้ง 1v1 และ 2v2 พร้อมเลือกจำนวนคอร์ด สุ่มผู้เล่นลงสนาม และบันทึกข้อมูลลง MongoDB จริง (แชร์ session เดียวกันได้) พัฒนาด้วย Next.js (App Router) + TypeScript + Tailwind CSS + ชุดคอมโพเนนต์แนว shadcn/ui • ทุกครั้งที่มีการเพิ่มฟีเจอร์ใหม่, ปรับ UI/UX สำคัญ, หรือแก้ไขบั๊กที่กระทบผู้ใช้ • ก่อนจะ merge หรือปล่อย production ทุกครั้ง檢視完整 README ↗
แอปสำหรับช่วยจัดคู่แบดมินตันแบบรวดเร็วและยุติธรรม รองรับทั้ง 1v1 และ 2v2 พร้อมเลือกจำนวนคอร์ด สุ่มผู้เล่นลงสนาม และบันทึกข้อมูลลง MongoDB จริง (แชร์ session เดียวกันได้)
พัฒนาด้วย Next.js (App Router) + TypeScript + Tailwind CSS + ชุดคอมโพเนนต์แนว shadcn/ui
Current Version: v0.9.25
yarn version --patch หรือ yarn version --minor เพื่อแก้ไขเลขเวอร์ชันใน package.jsonCHANGELOG.md (เพิ่มหัวข้อเวอร์ชันใหม่และสรุปสิ่งที่เปลี่ยนแปลง)yarn version:sync เพื่อ sync เวอร์ชันไปที่ README.md และหัวข้อ changelog อัตโนมัติดูรายละเอียดการเปลี่ยนแปลงทั้งหมดที่ CHANGELOG.md
/checkin/[sessionId] (ไม่ต้องมี PIN) รองรับทั้งคนที่ลงชื่อไว้ก่อนและ walk-in ที่ยังไม่เคยลงทะเบียน — คนที่ยังไม่เช็คอินจะไม่ถูกเอาไปสุ่มจนกว่าจะยืนยันว่าถึงคอร์ดแล้ว (แอดมินเช็คอินแทนได้จาก dashboard ด้วยถ้าผู้เล่นไม่มีมือถือ)แก้ชื่อ / ลบผู้เล่น)Singles หรือ Doubles1-3 คอร์ดพร้อมเริ่ม, กำลังเล่น, จบแล้ว)เริ่ม, จบแมตช์)คู่ถัดไป และรองรับเลื่อนรอบอัตโนมัติเมื่อจบครบทุกคอร์ดแมตช์รวมที่เล่นไปแล้ว แบบสะสม⇄ ที่ชื่อผู้เล่นใน court card ได้โดยตรง ระบบจะ confirm แล้วสุ่มคนพักมาแทนอัตโนมัติ ผู้เล่นเดิมจะ ไปพัก (ไม่ถูกลบจากรายชื่อ)/board (ลิงก์อยู่ในเมนูบนสุด, เช่น รายงานว่าวันนี้มากี่คน) รูปอัปโหลดตรงไปที่ Vercel Blob จากเบราว์เซอร์เลย ใครก็ดู feed/โพสต์/ลบโพสต์ได้ที่หน้านี้โดยไม่ต้องมี PIN/scoreboard/[sessionId] (ไม่ต้องมี PIN, อัปเดตทุก 2 วินาที) เอาไปเปิดจอทีวี/โปรเจกเตอร์ข้างคอร์ดได้ย้อนกลับคอร์ดนี้ โผล่เฉพาะคอร์ดที่กด จบแมตช์ ล่าสุดจริง ๆ เท่านั้น (ครั้งเดียว ไม่ใช่ stack หลายขั้น) ยกเลิกไม่ได้ถ้ามีคนถูกจัดลงแมตช์อื่นไปแล้วหลังจากนั้นnext@14 (App Router)react@18typescript@5tailwindcss@3sonner (toast notifications)lucide-react + @iconify/react (icons)qrcode (QR code generation for the self check-in link)mongoose (MongoDB) + bcryptjs (PIN hashing)@vercel/blob (photo storage for the webboard)src/
app/
layout.tsx
page.tsx
globals.css
not-found.tsx
how-to-use/page.tsx # in-app usage guide
checkin/[sessionId]/page.tsx # public self check-in page (no PIN)
board/page.tsx # public webboard feed (no PIN)
scoreboard/[sessionId]/page.tsx # public live scoreboard display (no PIN, polls every 2s)
api/
health/route.ts
players/[playerId]/route.ts
posts/route.ts # webboard: list/create
posts/[postId]/route.ts # webboard: delete
posts/upload/route.ts # Vercel Blob client-upload handler
sessions/route.ts
sessions/[id]/route.ts
sessions/[id]/close-court/route.ts
sessions/[id]/reset-stats/route.ts
sessions/[id]/register/route.ts # public — pre-registration
sessions/[id]/checkin/route.ts # public — check-in
sessions/[id]/players/route.ts
sessions/[id]/players/[sessionPlayerId]/route.ts
sessions/[id]/matches/route.ts
sessions/[id]/matches/[matchId]/route.ts
sessions/[id]/matches/[matchId]/score/route.ts # +/- point scoring
sessions/[id]/matches/[matchId]/substitute/route.ts
sessions/[id]/matches/[matchId]/undo-finish/route.ts
sessions/[id]/partner-history/route.ts
features/
home/home-page.tsx
components/
CourtSelector.tsx
MatchBoard.tsx
ModeSelector.tsx
PlayerList.tsx
QrCode.tsx
ui/
button.tsx
card.tsx
input.tsx
sonner.tsx
lib/
utils.ts
appVersion.ts
api/sessionApi.ts # typed fetch client the UI uses to call the API above
api/postsApi.ts # webboard client (list/create/delete + Blob upload helper)
auth/pin.ts # PIN hash/verify (bcrypt)
db/
mongodb.ts # connection singleton
models/ # mongoose schemas (session, player, sessionPlayer, match, partnerHistory, post)
services/
matchLifecycle.ts # shared stat/partner-history bump+revert logic, serializeMatch, getGameWinner
sessionPlayers.ts # shared add-player/find-by-name-or-id logic (admin + public register/checkin)
types/
styles.d.ts
public/
favicon.ico
robots.txt
yarn install
yarn dev
เปิดเบราว์เซอร์ที่ http://localhost:3000
หน้าเว็บหลักเรียก API จริงแล้ว (ไม่ใช่ localStorage) — ทุก action (เพิ่มผู้เล่น, จับคู่, จบแมตช์, ปิดคอร์ด ฯลฯ) ต้องมี MongoDB ต่ออยู่ถึงจะใช้งานได้ รายละเอียด endpoint ทั้งหมดดู docs/roadmap.md และ docs/database-design.md
.env.example เป็น .env แล้วปรับ MONGODB_URI ให้ชี้ไปที่ MongoDB local ของตัวเอง (ใช้ database name แยกจากโปรเจกต์อื่น)yarn dev แล้วลองยิง GET /api/health เพื่อเช็คว่าเชื่อม MongoDB สำเร็จ ก่อนเปิดหน้าเว็บหลักBLOB_READ_WRITE_TOKEN ใน .env — คัดลอกมาจาก Vercel project ที่ enable Blob storage แล้ว (Storage tab) ไม่งั้นการโพสต์ข้อความล้วนยังใช้ได้ปกติ แต่แนบรูปจะ error สุภาพว่ายังไม่ได้ตั้งค่าyarn dev รันโหมดพัฒนาyarn build สร้าง production buildyarn compile alias ของ yarn buildyarn start รัน production serveryarn lint ตรวจ lintyarn test รัน unit test (Vitest) — เทสฟังก์ชัน pure logic (buildMatchesFromPlayers, assignTeams, getGameWinner ฯลฯ) ไม่ต้องมี server/DByarn test:watch เหมือน yarn test แต่รันแบบ watch modeyarn test:e2e รัน E2E test (Playwright) — ต้องมี local MongoDB (docker) รันอยู่ก่อน จะ auto start yarn dev ให้เอง ดู tests/e2e/โปรเจกต์นี้มี test 2 ระดับ:
src/**/*.test.ts, รันด้วย yarn test) — เทสฟังก์ชัน pure logic ล้วน ๆ (matching algorithm, scoring) รันเร็ว ไม่ต้องมี server/DB จับบัคเรื่อง algorithm ผิดได้ แต่ไม่จับบัคเรื่อง state transition/wiringtests/e2e/*.spec.ts, รันด้วย yarn test:e2e) — จำลอง flow เต็มผ่านเบราว์เซอร์จริงกับ server+DB จริง (ต้องมี local MongoDB รันอยู่ก่อน — ดู Getting Started) ใช้จับบัคระดับ state machine ที่ unit test จับไม่ได้ เช่น "จบแมตช์แล้ว undo ไม่ได้จริง" (v0.9.14) และ "เพิ่มคอร์ดกลางเกมไม่สร้างแมตช์จริงให้" (v0.9.15) — ทั้งสองอันนี้เก็บไว้เป็น regression test แล้วที่ tests/e2e/undo-finish.spec.ts และ tests/e2e/add-court.spec.ts⚠️ E2E test สร้าง/แก้ข้อมูลจริงใน MongoDB ที่ .env ชี้ไป — เช็คให้แน่ใจว่าเป็น local Docker mongo เสมอ ห้ามรันตอน .env ชี้ไปที่ Atlas จริงเด็ดขาด (ดู Troubleshooting)
เมื่อกดปุ่มจับคู่ ระบบจะ:
queuedAt) — เท่ากันเป๊ะจริง ๆ ค่อยสุ่มจบแมตช์ (หรือ ปิดคอร์ด ระหว่างกำลังเล่น) เพิ่มสถิติ matches, บันทึกประวัติการจับคู่ (partner history), และรีเซ็ต queuedAt ให้ผู้เล่นที่อยู่ในคอร์ดนั้น ณ เวลานั้นNoto Sans Thai ผ่าน next/fontdropDatabase() หรือคล้ายกัน) ระหว่างทดสอบ ให้ cat .env เช็คก่อนเสมอว่า MONGODB_URI ยังชี้ localhost อยู่ — เคยเกิดเหตุการณ์ local .env ถูกแก้ให้ชี้ไป Atlas จริงตอน debug deploy แล้วลืมเปลี่ยนกลับ ทำให้การทดสอบไปกระทบ database จริงที่ deploy ใช้งานอยู่โดยไม่ตั้งใจ (ดู docs/decision-log.md#adr-012) ค่า connection string ของ Atlas จริงควรอยู่ใน Vercel Environment Variables เท่านั้น ไม่ใส่ใน .env ของเครื่อง devroute.ts มีอยู่จริง (โดยเฉพาะถ้าเพิ่งสลับไปมาระหว่าง yarn build กับ yarn dev) — .next cache ค้าง แก้ด้วย rm -rf .next && yarn dev ใหม่test แทนที่จะเป็น badminton-matcher — connection string ที่ copy จากปุ่ม "Connect" ใน Atlas ไม่มีชื่อ database อยู่ในนั้น (เช่น mongodb+srv://user:[email protected]/?retryWrites=true...) พอไม่ระบุมา MongoDB driver จะ default ไปที่ database ชื่อ test ให้เอง ต้องเติมชื่อ database เข้าไปเองก่อน ? เช่น .../badminton-matcher?retryWrites=true...*-git-*.vercel.app) แล้วเด้งไป vercel.com/sso-api — พฤติกรรมปกติของ Vercel, preview deployment ถูก protect ไว้ให้เห็นเฉพาะคนที่ login เข้าทีม Vercel เดียวกัน ถ้าจะแชร์ให้คนนอกทีมดู ต้อง deploy ขึ้น production domain แทน หรือเชิญเขาเข้าทีม Vercelแผนเดิมเคยระบุ Supabase ไว้ตรงนี้ แต่เปลี่ยนมาใช้ MongoDB แทนแล้ว (เหตุผล/รายละเอียดดู docs/decision-log.md) แผนฉบับเต็มพร้อมลำดับเฟสอยู่ที่ docs/roadmap.md — สรุปสั้น ๆ ด้านล่าง