A clean full-stack starter running on vinext, with optional Cloudflare D1 and Drizzle support.
- Node.js
>=22.13.0
npm install
npm run dev
npm run buildThis starter does not use wrangler.jsonc.
- edit site code under
app/ .openai/hosting.jsondeclares optional Sites D1 and R2 bindingsvite.config.tssimulates declared bindings for local developmentdb/schema.tsstarts intentionally emptyexamples/d1/contains an optional D1 example surfacedrizzle.config.tssupports local migration generation when needed
Signed-in visitors receive both oai-authenticated-user-id and oai-authenticated-user-email. Private Sites require every visitor to sign in; public Sites may also have anonymous visitors, for whom neither header is present.
The user ID is stable for the same user on the same Site and different across Sites. Email and name are intended for display or contact purposes.
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 userId = requestHeaders.get("oai-authenticated-user-id");
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:
- Use
getChatGPTUser()for optional signed-in UI. - Use
requireChatGPTUser(returnTo)for server-rendered pages that should send anonymous visitors through Sign in with ChatGPT. - Use
chatGPTSignInPath(returnTo)andchatGPTSignOutPath(returnTo)for browser links or actions. - Pass a same-origin relative
returnTopath for the destination after sign-in or sign-out. The helper validates and safely encodes it. - Mark protected pages with
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 dev: start local developmentnpm run build: verify the vinext build outputnpm test: build the starter and verify its rendered loading skeletonnpm run db:generate: generate Drizzle migrations after schema changes
The local Codex scheduled task runs at 08:30 in Shenzhen (Asia/Shanghai). It
opens original source pages, verifies publication dates, updates
app/page.tsx, runs the static build, and pushes the verified result to
main. .github/workflows/deploy.yml then builds and publishes GitHub Pages.
No OPENAI_API_KEY or paid OpenAI API call is required. The legacy
.github/workflows/daily-intelligence.yml file is retained as a manual-only
notice so an old GitHub schedule cannot trigger paid collection. The computer
must be on with Codex running at the scheduled time; after a shutdown, sleep,
network outage, or missed run, the next task run detects the gap, reports it,
and backfills every missing Shenzhen date before the normal review window.
For unattended GitHub publication, the Codex task's permission profile must
allow writes to this workspace including .git, outbound access to GitHub,
and local loopback binding for the static prerender step. GitHub CLI must be
logged in and the repository must have an origin remote.