Skip to content

dk-a-dev/dev.ly

Repository files navigation

dev.ly — URL Shortener & Analytics Platform

A high-performance URL shortener with a dedicated analytics microservice, real-time click tracking, Redis caching, BullMQ queues, and a modern Next.js dashboard.

Frontend Backend Analytics


System Architecture

graph TB
    subgraph Client Layer
        FE[Next.js Frontend :3000]
    end

    subgraph API Layer
        BE[Backend Service :5001]
        AN[Analytics Service :5002]
        WK[BullMQ Worker]
    end

    subgraph Cache Layer
        RD[(Redis)]
    end

    subgraph Data Layer
        PG[(PostgreSQL)]
    end

    FE -->|REST API| BE
    FE -->|Stats API| AN
    BE -->|1. URL Lookup| RD
    RD -->|Cache Miss| PG
    BE -->|2. Push Click Event| RD
    RD -->|BullMQ Queue| WK
    WK -->|3. Enrich & Write| PG
    AN -->|Read Stats| PG
    BE -.->|Rate Limit Check| RD

    style FE fill:#7c3aed,color:#fff,stroke:none
    style BE fill:#2563eb,color:#fff,stroke:none
    style AN fill:#059669,color:#fff,stroke:none
    style WK fill:#d97706,color:#fff,stroke:none
    style RD fill:#dc2626,color:#fff,stroke:none
    style PG fill:#0ea5e9,color:#fff,stroke:none
Loading

Redirect Flow

sequenceDiagram
    participant C as Client
    participant B as Backend
    participant R as Redis
    participant DB as PostgreSQL
    participant Q as BullMQ Queue
    participant W as Worker

    C->>B: GET /:shortCode?utm_source=twitter
    B->>R: GET url:shortCode
    alt Cache Hit
        R-->>B: { id, original_url }
    else Cache Miss
        B->>DB: SELECT FROM urls
        DB-->>B: { id, original_url }
        B->>R: SET url:shortCode (TTL 1h)
    end
    B-->>C: 302 Redirect (instant)
    B->>R: INCR visit_count
    B->>Q: Push { url_id, ip, ua, utm_* }
    Q-->>W: Consume job
    W->>R: Check dedup (SET key, 30s TTL)
    W->>DB: INSERT url_analytics (enriched)
Loading

Repo Structure

This is a multi-repo project using Git submodules:

Submodule Repo Description
frontend/ dev.ly-frontend Next.js 16 dashboard & landing page
backend/ dev.ly-backend Express 5 URL shortener API
analytics/ dev.ly-analytics Analytics microservice & BullMQ worker
dev.ly/
├── frontend/          ← git submodule (Next.js)
├── backend/           ← git submodule (Express API)
├── analytics/         ← git submodule (Analytics + Worker)
├── docker-compose.yml
├── .gitmodules
└── README.md          ← you are here

Cloning

# Clone with all submodules
git clone --recurse-submodules https://github.com/dk-a-dev/dev.ly.git

# If already cloned without submodules
git submodule update --init --recursive

Tech Stack

Layer Technology
Frontend Next.js 16, React 19, Tailwind CSS 4, Recharts, Framer Motion
Backend Express 5, JWT, bcrypt, Redis, BullMQ
Analytics Express 5, ua-parser-js, geoip-lite, BullMQ Workers
Database PostgreSQL 15
Cache / Queue Redis 7 + BullMQ
Infrastructure Docker, Docker Compose

Database Schema

erDiagram
    users {
        SERIAL id PK
        VARCHAR username UK
        VARCHAR email UK
        VARCHAR password_hash
        TIMESTAMP created_at
    }

    urls {
        SERIAL id PK
        TEXT original_url
        VARCHAR short_code UK
        INTEGER user_id FK
        INTEGER visit_count
        TIMESTAMP created_at
        TIMESTAMP expires_at
    }

    url_analytics {
        SERIAL id PK
        INTEGER url_id FK
        VARCHAR ip_address
        TEXT user_agent
        TEXT referrer
        VARCHAR country
        VARCHAR city
        VARCHAR browser
        VARCHAR os
        VARCHAR device_type
        VARCHAR utm_source
        VARCHAR utm_medium
        VARCHAR utm_campaign
        BOOLEAN is_unique
        TIMESTAMP visited_at
    }

    users ||--o{ urls : "creates"
    urls ||--o{ url_analytics : "has clicks"
Loading

API Reference

Backend (:5001)

Method Endpoint Auth Description
POST /api/auth/register Register user
POST /api/auth/login Login, returns JWT
GET /api/auth/profile Get current user profile
POST /api/url Create short URL
GET /api/url List user's URLs
DELETE /api/url/:id Delete URL
GET /:shortCode Redirect to original URL

Analytics Service (:5002)

Method Endpoint Auth Description
POST /api/log Ingest click event
GET /api/stats Get user's aggregate stats
GET /api/stats/urls-series 7-day time series per URL
GET /api/stats/:id Detailed stats for single URL

Rate Limiting

Endpoint Limit Behavior
POST /api/auth/* 10 req/min Returns 429
POST /api/url 30 req/min Returns 429
GET /api/stats/* 30 req/min Returns 429
GET /:shortCode No limit Always redirects

Quick Start

Prerequisites

  • Docker & Docker Compose
  • Node.js 18+ (for local dev)

Run with Docker (recommended)

# Clone with submodules
git clone --recurse-submodules https://github.com/dk-a-dev/dev.ly.git
cd dev.ly

# Start all services
docker-compose up --build -d

# View logs
docker-compose logs -f

This starts: PostgreSQL (:5432) → Redis (:6379) → Backend (:5001) → Analytics (:5002) → WorkerFrontend (:3000)

Run Locally (dev)

# Start DB + Redis only
docker-compose up -d db redis

# Backend (terminal 1)
cd backend && npm install && node index.js

# Analytics API (terminal 2)
cd analytics && npm install && node index.js

# Analytics Worker (terminal 3)
cd analytics && node src/workers/worker.js

# Frontend (terminal 4)
cd frontend && npm install && npm run dev

Environment Variables

Backend (.env)

PORT=5001
DB_USER=postgres
DB_PASSWORD=postgres
DB_HOST=localhost
DB_NAME=devly
DB_PORT=5432
JWT_SECRET=supersecretkey_change_me_in_prod
ANALYTICS_URL=http://localhost:5002
REDIS_URL=redis://localhost:6379

Analytics (.env)

PORT=5002
DB_USER=postgres
DB_PASSWORD=postgres
DB_HOST=localhost
DB_NAME=devly
DB_PORT=5432
JWT_SECRET=supersecretkey_change_me_in_prod
REDIS_URL=redis://localhost:6379

Docker: When running in Docker, use DB_HOST=db, ANALYTICS_URL=http://analytics:5002, REDIS_URL=redis://redis:6379


v2 Roadmap

Feature Description Status
Redis URL Cache Cache shortCode → URL in Redis. Sub-ms redirects. ✅ Done
BullMQ Click Queue Guaranteed delivery. Zero lost analytics. ✅ Done
Smart Rate Limiting Redis-backed. Protect APIs, never block redirects. ✅ Done
Click Deduplication Same IP + URL within 30s = is_unique: false. ✅ Done
UTM Tracking Parse utm_source, utm_medium, utm_campaign. ✅ Done
QR Code Generation Auto-generate QR codes for each short URL. 🔲 Planned
Link Expiry Dashboard Manage and extend URL expiration from the UI. 🔲 Planned

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages