DevPrint pulls your GitHub identity through OAuth, crunches your repo data server-side, and spits out a developer card. No forms, no manual input, you log in and your card is already there. You can also search any other GitHub user from the homepage.
No stats widgets, no client-rendered dashboard. Language breakdown, star totals, and the contribution heatmap are all computed server-side from raw GitHub REST + GraphQL responses, then cached in MongoDB so repeat views don't re-hit the API.
- GitHub OAuth login: one click via Auth0, no forms, no separate account, no password to manage. Your GitHub identity is your DevPrint identity.
- Instant card generation: the moment you log in, your card is built from your session data. Nothing to configure.
- Search any GitHub user: no login required. The homepage search bar looks anyone up and generates their card.
- Public shareable links: every generated card lives at a permanent
/u/usernameURL that anyone can open, no login needed on either end. - On-demand regeneration: a "Regenerate" button re-fetches your data and busts the cache, if your stats have changed since the last fetch.
- Server-side stats, zero third-party widgets: language breakdown, star totals, and the contribution heatmap are all computed from raw GitHub REST + GraphQL responses, not an embedded badge service.
- Cached, not re-fetched: a 1hr TTL cache in MongoDB means repeat views and popular searches don't hit GitHub's API again.
| Layer | Tech |
|---|---|
| Runtime | Node.js 20 |
| Server | Express 5 |
| Templating | EJS |
| Auth | Auth0 · GitHub OAuth (OpenID Connect) |
| Data | GitHub REST API v3 + GraphQL v4 |
| Persistence | MongoDB (cache-aside, 1hr TTL) |
| Deployment | Render + Namecheap domain |
| Uptime | UptimeRobot, pings /healthz every 14 min |
Auth0 handles the OAuth complexity (token exchange, session management, provider config) so the app logic stays focused on the GitHub data layer. EJS over a frontend framework, there's no client-side state to manage, server rendering is simpler and faster for this use case.
GET / → unauthenticated → landing
→ authenticated → /card
GET /search → public, no login required
→ redirects to /u/:username
GET /card → pulls github username from session (req.oidc.user.nickname)
→ cache check (MongoDB, 1hr TTL) → hit: return cached, miss: fetch
→ Promise.all: profile + repos + GraphQL heatmap fetched in parallel
→ language frequency computed server-side from raw repo objects
→ renders card.ejs with data
GET /u/:username → public, no login required
→ shareable permalink, same data pipeline as /card
* → unmatched routes and unhandled errors render a styled error page
(404 for missing routes, 500 for real failures), no default Express
stack-trace pages reach the client
Auth is handled by express-openid-connect. Username comes straight from the OAuth session token, no user input needed for your own card. No tokens stored; session lives in a signed cookie.
| Route | Auth | |
|---|---|---|
GET / |
None | Landing, redirects to /card if logged in |
GET /login |
None | Kicks off GitHub OAuth via Auth0 |
GET /callback |
None | Auth0 redirect target |
GET /logout |
✓ | Clears session |
GET /search?username=x |
None | Public search, redirects to /u/:username |
GET /card |
✓ | Your card, auto-generated from session |
GET /u/:username |
None | Public shareable card, no login required |
GET /healthz |
None | JSON status + uptime (keep-alive target) |
GET /stats |
None | Global usage counters (total cards generated, unique developers) |
git clone https://github.com/adrish-mage/devprint.git
cd devprint
npm install
cp env.example .env
node index.js.env:
AUTH0_SECRET= # openssl rand -hex 32
AUTH0_BASE_URL=http://localhost:3000
AUTH0_CLIENT_ID=
AUTH0_CLIENT_SECRET=
AUTH0_ISSUER_BASE_URL= # https://your-tenant.auth0.com
GITHUB_TOKEN= # PAT with public_repo read scope, used for both REST and GraphQL calls
MONGO_URI= # MongoDB connection string, e.g. mongodb+srv://user:[email protected]/devprint
PORT=3000Auth0 needs GitHub as a social connection and http://localhost:3000/callback whitelisted.
- OAuth identity drives the card:
req.oidc.user.nicknamegives the GitHub username directly from the session, no form needed Promise.allfor parallel API calls: profile, repos, and GraphQL heatmap all fetched simultaneously, not sequentially- Cache-aside layer in MongoDB: a 1hr TTL means repeat views and popular searches never re-hit GitHub's API
- Language breakdown, stars, and heatmap all computed server-side from raw API responses, no client-side widget, no third-party dependency
- Parameterized GraphQL queries: usernames are passed as query variables, not interpolated into the query string
- Public search and public share links (
/search,/u/:username) are fully separated from the authenticated dashboard (/card), no auth wall on the lookup path - A global 404 handler and error middleware mean no unmatched route or unhandled exception ever reaches the client as a default Express page
API & Data
- GraphQL: Heatmap (contribution graph via GitHub's GraphQL API)
- REST: Stats tiles (additional stat blocks from REST endpoints)
- Route: Public profile (
/u/:usernameshareable permalink without login)
Persistence
- MongoDB: Persistent cache (TTL-checked cache layer that also serves as durable storage, refetch and retrieve share the same collection)
Production
- Prod: Error handler (404 + global error middleware, inline fallback for failed searches)
- Prod: Rate limiting (per-IP throttling to protect the API)
- Prod: Logging (structured request/error logging for observability)
GitHub API calls use a single server-side PAT shared across all visitors (5,000 req/hr REST, separate GraphQL budget). Fine for demo traffic; a production version would need per-user tokens or rate-limiting middleware.
Adrish Dey, IT, Calcutta University github.com/adrish-mage · linkedin.com/in/adrish
MIT