Live-updating pixel-art GitHub profile cards you embed in your README. Backed by a serverless free-tier stack — no billing, nothing self-hosted for v1.
- Next.js (App Router) on Vercel — builder UI +
/api/renderSVG endpoint. - Supabase — Postgres (configs + derived data cache), Storage (mascot SVGs), Auth (GitHub OAuth).
- GitHub GraphQL — single query for profile, contribution total, top languages, pinned repos, via a GitHub App installation token.
- GitHub Actions
schedule:workflow — background refresh (Vercel Cron is Pro-only; Actions is free, no function timeout, and its DB writes keep the Supabase project awake). - No dedicated cache layer for v1: Postgres
fetched_atstaleness + HTTP cache headers cover the load.
Full design rationale in Project_Plan.md.
[README] --<img src="...svg?v={config_hash}">--> camo --> GET /api/render/{user}/{tpl}.svg
|-> Postgres (config + derived data)
|-> render(template_id, data) -> SVG
also, GitHub Actions cron -> refresh stale profiles into Postgres
Cache-busting is done by versioning the URL (?v=hash), not the header,
because camo caches by URL and the README HTML is cached too.
npm install- Copy
.env.example→.env.localand fill in Supabase project keys. npm run dev→ open http://localhost:3000.
The builder shows a "Supabase not configured" notice until env vars are set; the shipped routes are validation-safe without them.
- Supabase: run
supabase/schema.sqlin the SQL editor. Create themascotspublic bucket (the upload route creates it on demand). - GitHub App: create one at GitHub → Settings → Developer settings. Set
GITHUB_APP_ID,GITHUB_APP_PRIVATE_KEY(raw/blob with\n), and install it on target accounts. Store env vars in Vercel. - Refresh cron:
.github/workflows/refresh.ymlruns once daily (00:00 UTC). Set the same secrets under repo → Settings → Secrets and variables → Actions (SUPABASE_URL,SUPABASE_SERVICE_ROLE_KEY,GITHUB_APP_ID,GITHUB_APP_PRIVATE_KEY). - Register the GitHub Developer Program (Phase 9) — earns the badge and confirms API eligibility. Confirm current terms at docs.github.com.
| Command | Purpose |
|---|---|
npm run dev |
Local dev server |
npm run build |
Production build |
npm run lint |
ESLint |
npm run typecheck |
tsc --noEmit |
npm test |
Vitest suite (pixel-font, templates, sanitize, GitHub client) |
npm run refresh |
Run the background refresh against Supabase + GitHub (used by CI cron) |
- Pixel-font golden tests (one shifted pixel = broken art).
- Template render snapshots across both v1 templates.
- Sanitizer XSS corpus (scripts,
on*,<foreignObject>, external refs, entity bombs) asserting hard rejection, never silent strip. - GitHub API client stubbed so the suite never burns real rate limits.
GET /api/render/{username}/{templateId}.svg?v={hash}— the badge URL.POST /api/upload/user/{username}— sanitize + store a mascot SVG.POST /api/config— save the caller's card config (or upsert).
See Project_Plan.md Phases 1–11 for the full plan, free-tier constraints, and
post-launch expansion options (more templates, community gallery, aggregate
analytics).