Loading repository data…
Loading repository data…
anishshobithps / repository
Personal website of Anish Shobith P S, Software Developer building modern, scalable web applications and funny projects.
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
Source code for anishshobithps.com: a portfolio, blog, and guestbook. Interfaces, bots, and questionable automation scripts, mostly so I don't have to repeat myself.
| Route | What it does |
|---|---|
/ | Hero, project teasers, latest post, guestbook rotator, Spotify now-playing |
/blogs, /blog/* | MDX posts via fumadocs, reading time, anonymous reactions, view counts, threaded comments |
/projects |
| Pulled from the database, not a hardcoded array — ordered and toggled from the admin |
/resume | PDF rendered inline with react-pdf, streamed from the latest GitHub release |
/guestbook | Clerk-authenticated messages with likes, pinning, and soft delete |
/branding | Logo and colour usage, so people stop stretching the mark |
/admin/* | Owner-only dashboard for comments, guestbook, links, and projects |
/og | Generated OpenGraph images (takumi, not Satori) |
/llms.txt | Machine-readable site summary; every post also serves raw MDX at /blog/<slug>.mdx |
/<slug> | Short-link resolver with click counts — see Short links |
A few things worth calling out:
ip:IP_HASH_SALT (see src/lib/ip.ts) — one row per post per hash, and the raw IP is never stored.content/blog.Node 22+ and pnpm 11 (the repo pins packageManager, so corepack enable is enough).
pnpm install
pnpm db:migrate # applies the committed migrations in drizzle/
pnpm dev # http://localhost:3000
You'll need a few things first:
| What | Where |
|---|---|
| PostgreSQL | neon.tech (free tier works) |
| Auth | clerk.com (for guestbook & comments) |
| Spotify | run pnpm spotify:token once |
Create .env.local at the root:
DATABASE_URL=postgresql://...
IP_HASH_SALT=some-random-secret # required — any long random string; keep it secret
SPOTIFY_CLIENT_ID=
SPOTIFY_CLIENT_SECRET=
SPOTIFY_REFRESH_TOKEN=
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_...
CLERK_SECRET_KEY=sk_...
OWNER_CLERK_USER_ID=user_... # your user ID = admin powers
CLERK_WEBHOOK_SECRET=whsec_... # Clerk > Webhooks > Signing Secret
NEXT_PUBLIC_BASE_URL=https://anishshobithps.com
NEXT_PUBLIC_UMAMI_WEBSITE_ID=... # optional, or remove from layout.tsx
GITHUB_TOKEN=ghp_... # optional — only lifts the API rate limit on repo cards
Only DATABASE_URL and IP_HASH_SALT are truly required to boot. IP_HASH_SALT throws loudly if missing rather than silently hashing with nothing. NEXT_PUBLIC_BASE_URL falls back to the Vercel production URL, then http://localhost:3000.
Clerk webhook: point https://yourdomain.com/api/webhooks/clerk at user.deleted to keep the DB clean when users delete their accounts.
Spotify token: pnpm spotify:token prints the authorize URL to open, then swaps the code it gives back for a refresh token. Register http://127.0.0.1:3000 as a redirect URI in the Spotify dashboard first, or the exchange fails.
content/blog/ MDX posts — the only place posts live
drizzle/ committed SQL migrations + meta
scripts/ one-off tsx scripts (seeding, Spotify token)
tests/ vitest, node environment, pure logic only
src/
app/(site)/ public pages
app/admin/ owner-only dashboard
app/api/ resume proxy + Clerk webhook
app/[...link]/ short-link resolver (catch-all, keep it last)
components/ ui/ (shadcn), shared/, engagement/, layouts/
lib/ db, schema, and everything not React
pnpm dev # dev server — http://localhost:3000
pnpm build # next build
pnpm start # production server
pnpm types:check # fumadocs codegen + next typegen + tsc --noEmit
pnpm lint # ESLint
pnpm test # Vitest
pnpm test:watch # Vitest, watching
pnpm knip # unused code/dependency check
pnpm db:migrate # apply committed migrations
pnpm db:push # push schema directly (dev only — skips migrations)
pnpm db:studio # Drizzle Studio
pnpm db:seed:guestbook # seed fake guestbook entries
pnpm db:seed:guestbook:cleanup # remove seeded entries
pnpm db:seed:links # seed short links
CI (.github/workflows/ci.yml) runs types:check and test on every push to main and every PR. Lint and knip are local-only for now.
Drop an .mdx file in content/blog/. The filename is the slug. Frontmatter is validated by source.config.ts:
---
title: The Hidden Architecture of Emoji
description: One or two sentences. Also used for the OG image and meta description.
date: 2026-03-19
tags:
- Unicode
- Typography
lastModified: 2026-04-02 # optional — set it by hand when an edit is worth announcing
---
lastModified is deliberately manual. It used to come from git history, but shallow clones on the deploy host re-dated every post on every push. Reading time is computed at build time by a remark plugin.
/admin is gated on OWNER_CLERK_USER_ID matching the signed-in Clerk user — there's no role system, just the one ID. It gives you stats, comment and guestbook moderation (pin, soft delete), project CRUD with ordering, short-link management, and a button to bust the cached resume PDF.
Any unclaimed path resolves through /[...link], in one of two shapes:
/<slug> → tag = "" (the default bucket)
/<tag>/<slug> → namespaced, e.g. /talk/react-india
Slugs are unique per (tag, slug). Each link can redirect straight through (permanent or temporary), or — if it has a title, description, or OG image — render an interstitial with preview metadata first, which is the point when you're posting into something that unfurls links. Clicks are counted in after() so the redirect isn't waiting on the write.
Add the env vars and point DATABASE_URL at Neon. The build runs next build only — it does not migrate. Run pnpm db:migrate against the production database yourself when the schema changes.
Two things that bite on a fresh deploy: CSP in next.config.mjs hardcodes clerk.anishshobithps.com, so point that at your own Clerk frontend domain, and any new remote image host needs adding to both images.remotePatterns and the CSP.
Code is MIT. The writing in content/, the branding, and the design are CC BY-NC-ND 4.0 — fork the machinery, not the words.