https://github.com/carvalhocaio/link-arch
A fast, lightweight URL shortener API built with Bun and Elysia. It generates short links, tracks click counts, validates target URL reachability, and exposes auto-generated OpenAPI documentation.
https://github.com/carvalhocaio/link-arch
Last synced: about 1 month ago
JSON representation
A fast, lightweight URL shortener API built with Bun and Elysia. It generates short links, tracks click counts, validates target URL reachability, and exposes auto-generated OpenAPI documentation.
- Host: GitHub
- URL: https://github.com/carvalhocaio/link-arch
- Owner: carvalhocaio
- Created: 2026-03-18T02:46:08.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-03-20T03:57:15.000Z (4 months ago)
- Last Synced: 2026-04-03T01:45:06.549Z (4 months ago)
- Language: TypeScript
- Homepage:
- Size: 876 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Link Arch
Link Arch is a fast, lightweight link management platform built with Bun, Elysia, and Next.js. It supports authenticated URL shortening, custom aliases, click tracking, URL lifecycle management, and auto-generated OpenAPI docs.
## Features
- Authenticated link management with Google sign-in (Better Auth OAuth)
- Create short URLs with custom keys or generated aliases
- URL reachability validation before creating or updating links
- Link administration: update destination, update key, toggle active status, set expiry date, and soft delete
- Redirect and non-redirect preview (`/:key/peek`) endpoints
- Dashboard and My Links UI with search, filtering, sorting, pagination, and CSV export
- OpenAPI documentation generated directly from route schemas
## Tech Stack
### Backend
- **Runtime:** [Bun](https://bun.sh)
- **Framework:** [Elysia](https://elysiajs.com)
- **Auth:** [Better Auth](https://www.better-auth.com)
- **Database:** PostgreSQL
- **ORM:** [Drizzle ORM](https://orm.drizzle.team) (with [postgres.js](https://github.com/porsager/postgres) driver)
### Frontend
- **Framework:** [Next.js](https://nextjs.org) 16 (App Router, Turbopack)
- **UI Components:** [shadcn/ui](https://ui.shadcn.com) v4
- **Data Fetching:** [TanStack React Query](https://tanstack.com/query) v5
- **Theming:** [next-themes](https://github.com/pacocoursey/next-themes) (system, light, dark)
- **Notifications:** [Sonner](https://sonner.emilkowal.dev)
### Tooling
- **Monorepo:** [Turborepo](https://turbo.build)
- **Linter/Formatter:** [Biome](https://biomejs.dev)
- **Load Testing:** [k6](https://k6.io)
## Prerequisites
- [Bun](https://bun.sh) v1.2.0+
- [PostgreSQL](https://www.postgresql.org) running locally or remotely
- [k6](https://k6.io) (optional, for load testing)
## Getting Started
### 1. Clone the repository
```bash
git clone https://github.com/carvalhocaio/link-arch.git
cd link-arch
```
### 2. Install dependencies
```bash
bun install
```
### 3. Configure environment variables
```bash
cp .env.example .env
```
Set values in `.env`:
| Variable | Description | Default |
|---|---|---|
| `DATABASE_URL` | PostgreSQL connection string used by API and migrations | _(required)_ |
| `PORT` | API server listen port | `3000` |
| `BASE_URL` | Public API base URL used to build short links | `http://localhost:3000` |
| `WEB_URL` | Allowed web origin for CORS and trusted auth origins | `http://localhost:3001` |
| `FORWARD_TIMEOUT_MS` | Timeout in milliseconds for URL reachability checks | `5000` |
| `BETTER_AUTH_SECRET` | Better Auth signing secret | _(required)_ |
| `GOOGLE_CLIENT_ID` | Google OAuth 2.0 client ID | _(required)_ |
| `GOOGLE_CLIENT_SECRET` | Google OAuth 2.0 client secret | _(required)_ |
| `NEXT_PUBLIC_API_URL` | API base URL consumed by the Next.js app | `http://localhost:3000` |
> Create the Google OAuth credentials in the [Google Cloud Console](https://console.cloud.google.com/apis/credentials) (type: Web application) and set the authorized redirect URI to `/api/auth/callback/google`.
### 4. Run database migrations
```bash
bun run db:generate
bun run db:migrate
```
### 5. Start development
```bash
bun run dev
```
By default:
- API: `http://localhost:3000`
- Web: `http://localhost:3001`
You can also run only one app:
```bash
bun run dev:api
bun run dev:web
```
## Available Scripts
Run all commands from the monorepo root with `bun run `.
| Script | Description |
|---|---|
| `dev` | Start all apps in development mode |
| `dev:api` | Start only the API app |
| `dev:web` | Start only the web app |
| `build` | Build all apps and packages |
| `lint` | Run lint tasks in workspaces |
| `check` | Run Biome checks in workspaces |
| `test` | Run test tasks in workspaces |
| `format` | Format repository files with Biome |
| `db:generate` | Generate Drizzle migration files |
| `db:migrate` | Apply pending migrations |
## Project Structure
This repository is a Turborepo monorepo:
- `apps/api` - Elysia API (shorten, redirect, auth, admin, OpenAPI)
- `apps/web` - Next.js frontend (landing page, dashboard, my-links, login)
- `packages/db` - Shared Drizzle schema, auth schema, and migration scripts
- `packages/biome-config` - Shared Biome configuration
- `packages/tsconfig` - Shared TypeScript configuration
## API Overview
Common routes include:
- `GET /health` - Health and metadata
- `POST /api/auth/sign-in/social` - Start Google OAuth sign-in (returns redirect URL)
- `GET /api/auth/callback/google` - Google OAuth callback (handled by Better Auth)
- `GET /api/auth/get-session` - Current user session
- `POST /api/auth/sign-out` - End session
- `POST /api/shorten` - Create short URL (authenticated)
- `GET /:key` - Redirect to target URL
- `GET /:key/peek` - Preview URL metadata without redirect
- `GET /api/admin/urls` - List current user URLs (authenticated)
- `PATCH /api/admin/urls/:id` - Update destination URL and expiry (authenticated)
- `PATCH /api/admin/urls/:id/key` - Update short key (authenticated)
- `PATCH /api/admin/urls/:id/status` - Activate/deactivate link (authenticated)
- `DELETE /api/admin/urls/:id` - Soft delete link (authenticated)
## API Documentation
The API is fully documented via auto-generated OpenAPI.
Once the API is running:
```http
GET /openapi
```
You can import this spec into tools like [Swagger UI](https://swagger.io/tools/swagger-ui/) or [Scalar](https://scalar.com).
## Architecture
See [ARCHITECTURE.md](ARCHITECTURE.md) for a detailed breakdown of the monorepo layout, tech stack decisions, database schema, API design, authentication flow, and testing strategy.
## Changelog
See [CHANGELOG.md](CHANGELOG.md) for the full release history.
## Load Testing
A [k6](https://k6.io) script is included to benchmark API latency under load.
### Run the benchmark
Make sure the API server is running:
```bash
k6 run apps/api/k6/latency.js
```
Target a different host:
```bash
k6 run -e BASE_URL=http://your-host:3000 apps/api/k6/latency.js
```
### Scenario details
- Ramps up to **50 virtual users** over 10 seconds
- Sustains 50 virtual users for 20 seconds, then ramps down over 10 seconds
- Each iteration creates a short URL, peeks it, and follows redirect
- Threshold: p95 response time under **200ms**
## License
[MIT](LICENSE) — free to use, modify, and distribute. Attribution appreciated.