Case study
Steadlink
A self-hosted URL shortener and engagement platform featuring branded domains, QR code generation, landing pages, and webhooks, built with Next.js, PostgreSQL row-level security, and better-auth.
What it is
Steadlink is a self-hosted short link service that runs entirely on your own infrastructure. It handles short links, branded domains, customizable QR codes, landing page blocks, campaigns, webhooks, and analytics, without relying on third-party tracking or external cloud accounts. The click-through path is direct and contains no intermediate pages, ads, or countdowns.
How it works
The application divides data into workspaces (groups) to keep link sets separate. It includes a public REST API under `/api/v4` with scoped personal access tokens, and a link checker at `/check` for unauthenticated destination verification. To ensure secure multi-tenancy, the application connects to PostgreSQL using an unprivileged role. Row-level security (RLS) policies evaluate a transaction-local setting (`app.org_id`), ensuring that a query that fails to scope itself returns nothing rather than leaking other tenants' data. Public routes, such as redirects, bypass these policies for performance but are filtered by `org_id` at the data layer.
How it is built
Steadlink is built with TypeScript on Node 24, using Next.js 16, React 19, Tailwind CSS 4, and Biome. The database layer uses PostgreSQL 17 managed by Drizzle ORM, with background jobs handled by pg-boss. Authentication and session management are implemented via better-auth. End-to-end testing is executed with Playwright against a live, dedicated test database (`steadlink_test`) to verify access rules and user flows across desktop and mobile viewports.
What I learned
- Implementing PostgreSQL row-level security (RLS) with transaction-local variables allows for a highly secure multi-tenant data layer that prevents accidental cross-tenant data leaks.
- Separating database roles between the migration runner (superuser), the application runner (unprivileged), and the worker runner enforces the principle of least privilege directly in the database engine.
What it doesn't do yet
Listed deliberately — a project's limits are as useful to a reviewer as its features.
- There is currently no link import functionality (export is supported via CSV, but importing is unfinished).
- There is no native mobile application (the web app is responsive and installable instead).
- SAML single sign-on (SSO) configuration is incomplete.
- Webhook endpoint verification is only partially implemented.
- Bulk QR code creation and PDF/image dashboard exports are not yet supported.