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。 以下为已保存的摘录。
A clean full-stack starter running on vinext, with optional Cloudflare D1 and Drizzle support.
• Node.js >=22.13.0
• Linux with flock, curl, and GNU timeout
The Sites lifecycle CLI runs the locked dependency install before returning this checkout. Edit the source under app/, then checkpoint when a coherent milestone is ready to inspect or share. The remote Sites builder runs npm run build against the pushed commit. Do not repeat install or build as a normal pre-checkpoint step.
This starter does not use wrangler.jsonc.查看完整 README ↗A clean full-stack starter running on vinext, with optional Cloudflare D1 and Drizzle support.
>=22.13.0flock, curl, and GNU timeoutThe Sites lifecycle CLI runs the locked dependency install before returning this checkout. Edit the source under app/, then checkpoint when a coherent milestone is ready to inspect or share. The remote Sites builder runs npm run build against the pushed commit. Do not repeat install or build as a normal pre-checkpoint step.
This starter does not use wrangler.jsonc.
install:ci is intentionally a single, non-retrying npm ci. It refuses a concurrent install for the same project, consumes a matching image-seeded npm cache with --prefer-offline while retaining registry fallback for a missing cache object, otherwise downloads and verifies the complete vinext tarball recorded in package-lock.json, limits npm to one socket, and terminates a stalled install. build applies a short timeout. These helpers target Linux and use GNU timeout; they are not native macOS scripts.
Scripts that need writable project-scoped home, npm, XDG, and temporary paths use scripts/sites-env.sh. The dev and start scripts honor the caller's runtime environment and keep Wrangler logs inside the checkout. The generated .sites-runtime/ directory is disposable and ignored by Git.
app/app/chatgpt-auth.ts provides optional dispatch-owned ChatGPT sign-in helpers.openai/hosting.json declares optional Sites D1 and R2 bindingsvite.config.ts simulates declared bindings for local developmentdb/index.ts reads the D1 binding from the Cloudflare Worker environmentdb/schema.ts starts intentionally emptyexamples/d1/ contains an optional D1 example surfacedrizzle.config.ts supports local migration generation when neededOpenAI workspace sites can read the current user's email from oai-authenticated-user-email.
SIWC-authenticated workspace sites may also receive oai-authenticated-user-full-name when the user's SIWC profile has a non-empty name claim. The full-name value is percent-encoded UTF-8 and is accompanied by oai-authenticated-user-full-name-encoding: percent-encoded-utf-8.
Treat the full name as optional and fall back to email when it is absent:
import { headers } from "next/headers";
export default async function Home() {
const requestHeaders = await headers();
const email = requestHeaders.get("oai-authenticated-user-email");
const encodedFullName = requestHeaders.get("oai-authenticated-user-full-name");
const fullName =
encodedFullName &&
requestHeaders.get("oai-authenticated-user-full-name-encoding") ===
"percent-encoded-utf-8"
? decodeURIComponent(encodedFullName)
: null;
const displayName = fullName ?? email;
// ...
}
Import the ready-to-use helpers from app/chatgpt-auth.ts when the site needs optional or required ChatGPT sign-in:
getChatGPTUser() for optional signed-in UI.requireChatGPTUser(returnTo) for server-rendered pages that should send anonymous visitors through Sign in with ChatGPT.<a href={chatGPTSignInPath(returnTo)} target="_top">. The auth helper module is server-only; do not import it into a Client Component.fetch, XHR, a client-side router, or a framework link that can prefetch the sign-in route. SIWC must start as a top-level navigation./signin-with-chatgpt route must start the SIWC flow.chatGPTSignOutPath(returnTo) for browser sign-out links or actions.returnTo path for the destination after sign-in or sign-out. The helper validates and safely encodes it.export const dynamic = "force-dynamic" because they depend on per-request identity headers.Dispatch owns /signin-with-chatgpt, /signout-with-chatgpt, /callback, the OAuth cookies, and identity header injection. Do not implement app routes for those reserved paths. Routes that do not import and call the helper remain anonymous-compatible.
SIWC establishes identity only; it does not prove workspace membership. Use the Sites hosting platform's access policy controls for workspace-wide restrictions, or enforce explicit server-side membership or allowlist checks.
Use SIWC for account pages, user-specific dashboards, saved records, and write actions tied to the current ChatGPT user. Leave public content anonymous.
npm run install:ci: perform the one bounded lockfile installnpm run dev: start the Vite/Vinext development servernpm run build: build the deployable Sites artifactnpm run start: start the built Vinext applicationnpm test: build and verify the rendered development-preview metadatanpm run db:generate: generate Drizzle migrations after schema changesUse build commands for targeted diagnosis after a remote failure, not as part of the normal checkpoint path.
The timeout defaults can be overridden for a controlled canary with SITES_INSTALL_TIMEOUT, SITES_INSTALL_KILL_AFTER, SITES_BUILD_TIMEOUT, and SITES_BUILD_KILL_AFTER. A timeout fails the command; the helpers never retry an unchanged install or build.