
Who
I got tired of leasing short links from tools that treat a redirect like a subscription upsell.
Operators (marketers, founders, agencies, anyone pasting campaign URLs into SMS and decks) need a domain they own, a dashboard that lists what they created, and click facts that survive the redirect. Developers already on Convex and Clerk do not need a fifth SaaS login for "paste URL, get code."
s12.in is for that seat: MarTech folks, Next.js-on-Vercel shippers, and anyone who wants s12.in/abc instead of a twenty-character tracking URL.
What
I shipped a URL shortener and file host at s12.in.
Stack facts: Next.js 16.1.6 (App Router, Turbopack) on Vercel, React 19.2, Convex for links/files/clicks/users plus _storage uploads, Clerk for auth, Tailwind CSS v4, Radix primitives, Resend in the lockfile, Biome + oxlint + tsgo. Package name s12, version 0.1.0, packageManager bun@1.3.1. Repo is private under HurleyUS.

Paste a long URL on the homepage or dashboard. Convex links.create issues a short code (optional customCode / password / expiresAt exist on the schema; the public form only sends url + optional userId). app/[code]/route.ts resolves the code, parses user-agent, reads Vercel geo headers, hashes the IP with SHA-256 + a salt (16 hex chars), fires recordClick without blocking, then 302s. Files take the same path: viewable MIME types redirect to the Convex storage URL; others return an attachment stream.
Dashboard tabs list your links and files with copy/delete. Click and download counters are denormalized on the row. getAnalytics can roll up by day/country/browser/device/referrer. Charts are not on the dashboard yet.
A Manifest V3 Chrome extension scaffold lives under extension/ and posts to /api/shorten with CORS. Icon PNGs are still marked ICONS_NEEDED.md (SVG only in tree).
Honesty operators can smell: the hero still prints 10M+ / 50K+ / 99.9% as static JSX. The live Clerk publishable key I hit was pk_test on *.clerk.accounts.dev. README still names PostHog and Sentry; those packages were removed Feb 21. Footer GitHub still points at michaelmonetized/s12.in while the working private remote is HurleyUS/s12.in. Schema users.plan free|pro|team is ahead of any billing UI.

Where
Product: s12.in (apex redirects toward www). Vercel project alias on the GitHub homepage field: s12-in.vercel.app. Routes that matter: /, /dashboard, /sign-in, /sign-up, /privacy, /terms, /refunds, /api/shorten, /[code].
Code: github.com/HurleyUS/s12.in. Private, no topics, no license file, no tagged releases. Deploy path is Vercel continuous with a Blacksmith ship.yml gate. Local path: bun install, bunx convex dev, bun dev.
Audience sits next to every "just use Bitly" thread and every Convex starter that never grew a redirect route.

When
2026-01-08. Initial commit: Next.js, Convex, Tailwind. Same day: OPPORTUNITIES.md and homepage improvements; PLAN.md improvement list. Early docs still daydream about a CDN. The product that shipped is the shortener + files.
2026-01-31 to 02-05. Sync. Tailwind v4 @import. Prod build ready.
2026-02-06. The spine. Core URL shortening. Upgrade to Next.js 16 and React 19; middleware renamed toward proxy.ts (and briefly back during Next's naming war). Convex backend configured and deployed. Clerk auth keys landed.
2026-02-11. Dashboard UI improvements: links/files mental model.
2026-02-15–21. Docs say proxy.ts. Footer gets real social URLs. Unused posthog-js and @sentry/nextjs leave the lockfile.
2026-02-27. Security headers in next.config.ts. sitemap.ts / robots.ts. Error boundaries. Auth checks on links and files mutations.
2026-03-23. PR #23 strips console.error noise.
2026-05-14–15. Blacksmith CI standardized. Providers tolerate missing Clerk keys so builds do not die. Deploy URL / health-check fixes.
2026-08-08. HEAD d6c074f. vercel.json sets X-Robots-Tag: index, follow. Thirty-eight commits on the clock.
Why
A short link you do not control is a tax with a dashboard skin. I wanted the domain, the Convex tables, and the redirect that writes analytics before the visitor leaves, on the same Clerk identity I already use everywhere else.
Shortening and file hosting landed on s12.in. Clicks record geo and device fields. Shipping continued until CI and robots headers stopped being the embarrassment.
It is still 0.1.0. Custom codes, password gates, plan limits, and analytics charts sit in schema or queries waiting for UI. Clerk on the observed deploy is still test-mode. That is fine to say out loud. The redirect path and the dashboard list already do the job a rented shortener charges monthly for.
What would you put on s12.in/yourcode first: the campaign URL, the PDF, or the deck you keep resending as a thirty-line Google Drive link?
