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 ↗
正在加载完整 README。
查看完整 README ↗A free, simple diary for the tennis you watch: explore the story of any tour-level singles match since 2003, star the ones you care about, read your saga back, look up the records in Statistics, and play with models of the numbers in Interact. Live at courtsaga.com.
main.drizzle/.scripts/import-matches.ts.| Path | What it is |
|---|---|
app/page.tsx, app/hero*.tsx | The landing page. Its demos run on a sample log and save nothing. |
app/demos/ | The sample log and its hand-checked rivalry records, for the demos only. |
app/diary/ | The log, ranking and saga, used by both the demos and real diaries. library.ts holds the shared types and rules, books.ts the saga's rules, store.tsx the state and saving, and finder.tsx match search. |
app/(app)/ | The app's pages (/explore, /saga, /statistics, /interact, /account) and the server actions that keep a diary. Explore opens signed out only for a shared match, with nowhere to go from it. |
app/diary/records.ts, lib/records.ts | Statistics: every board's rules, and the loader that reads a tour's matches and builds them. The pages are prerendered and rebuilt daily. |
app/diary/models.ts, lib/models.ts | Interact: models fitted to a tour's matches (the top 10 at any moment, upset odds, Elo ratings across eras, serving, big points under pressure, ages), and the loader that fits them. Built ahead of time and rebuilt daily, like Statistics. |
app/(auth)/ | Sign up and log in. |
app/s/[slug]/ | A shared saga: read-only, kept out of search engines. |
app/api/ | Better Auth's endpoints and GET /api/search. |
lib/ | Accounts (auth.ts), diary and search queries (diary.ts). |
db/, drizzle/ | The schema and database client, and the migrations generated from them. |
scripts/ | migrate.ts and import-matches.ts. |
proxy.ts | Sends signed-in fans from / to their log, and everyone else from diary pages to log in. |
npm installunaccent and pg_trgm extensions. A Neon branch works, and so does
local Postgres 15 or later..env.example to .env.local and set DATABASE_URL and BETTER_AUTH_SECRET
(openssl rand -base64 32).npm run db:migrate creates the tables.npm run import:matches -- ~/Desktop/courtsaga/tml-data loads the matches, in about ten seconds.npm run dev, then open http://localhost:3000.The import reads YYYY.csv (ATP) and YYYY_wta.csv (WTA) from a folder, every row of every year it
finds. The CSVs are never committed.
2026.csv and 2026_wta.csv in the folder and run the import again. No code
changes.tour_tourneyId_round_winnerId_loserId (for example atp_2025-540_F_S0AG_A0E2). They
never change between imports, because diary entries point at them.tourney_date is a tournament's first day, so a match's month is estimated from how far into
the event its round falls. The season always comes from the file name.The data is TML-Database (non-commercial use) built on Jeff Sackmann's tennis data (CC BY-NC-SA 4.0). CourtSaga credits both in its footers. Keep the site non-commercial (no ads, no paid tier) unless you get permission, and don't publish the raw data.
A push to main deploys to production. Vercel runs npm run vercel-build, which applies any new
migrations before next build. That only happens on production builds; previews skip it, so a branch's
migrations never reach the production database before it's merged. Every setting is in .env.example.
| Script | What it does |
|---|---|
npm run dev / build / start / lint | The usual Next.js commands. build needs no database, but without one the prerendered pages (the landing page's demo and Statistics) say the match data isn't available. |
npm run db:generate | Writes a new migration to drizzle/ after a change to db/schema.ts. |
npm run db:migrate | Applies migrations to DATABASE_URL_UNPOOLED (or DATABASE_URL). |
npm run import:matches -- <folder> | Loads or refreshes the match data. |