Skip to content

mattstratton/linkpipe

Repository files navigation

LinkPipe - URL Shortener with UTM Manager

LinkPipe Logo

A professional URL shortener with UTM parameter management, built with a modern stack using PostgreSQL, Prisma, and Docker for easy deployment and development.

✨ Features

  • πŸ”— URL Shortening - Create short, memorable links with custom or auto-generated slugs
  • πŸ“Š UTM Management - Add, manage, and track UTM parameters with predefined options
  • 🌐 Multi-Domain Support - Support for multiple custom domains for redirection
  • 🎯 Click Tracking - Track clicks and analytics for each short link
  • πŸ—„οΈ Modern Database - PostgreSQL with Prisma ORM for type safety and migrations
  • 🎨 Modern UI - React + Tailwind CSS with responsive design
  • 🐳 Docker Ready - Complete Docker setup for easy development and deployment
  • πŸ”„ Flexible Deployment - Deploy to any platform that supports Docker

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   React Frontend β”‚    β”‚  Unified Server  β”‚    β”‚  PostgreSQL DB  β”‚
β”‚   (Built into    │───▢│  Express API    │───▢│   + pgAdmin     β”‚
β”‚    Express)      β”‚    β”‚  + Redirect     β”‚    β”‚                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸš€ Quick Start

Prerequisites

  • Node.js 18+ and npm
  • Docker and Docker Compose
  • Git

Local Development

  1. Clone and Setup

    git clone <repository-url>
    cd linkpipe
  2. Start with Docker Compose ⭐ Recommended

    # Copy environment template
    cp .env.example .env
    
    # Start all services
    docker-compose up -d

    This will start:

  3. Initialize Database

    # Run Prisma migrations
    cd backend
    npx prisma migrate dev
    
    # Seed with sample data
    npm run db:seed
  4. Access the Application

πŸ“ Project Structure

linkpipe/
β”œβ”€β”€ frontend/              # React + Vite frontend (built into backend/public/)
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ components/    # Reusable UI components
β”‚   β”‚   β”œβ”€β”€ pages/         # Route pages
β”‚   β”‚   β”œβ”€β”€ lib/           # API client and utilities
β”‚   β”‚   └── App.tsx        # Main app component
β”‚   └── vercel.json        # Vercel deployment config
β”œβ”€β”€ backend/               # Unified Node.js server (API + Frontend + Redirect)
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ routes/        # Express routes (API + Redirect)
β”‚   β”‚   β”œβ”€β”€ lib/           # Prisma database layer
β”‚   β”‚   β”œβ”€β”€ middleware/    # Express middleware
β”‚   β”‚   └── types.ts       # TypeScript types
β”‚   β”œβ”€β”€ prisma/            # Prisma schema and migrations
β”‚   β”‚   β”œβ”€β”€ schema.prisma  # Database schema
β”‚   β”‚   └── migrations/    # Database migrations
β”‚   β”œβ”€β”€ public/            # Built React frontend (served by Express)
β”‚   └── sql/               # SQL initialization scripts
β”œβ”€β”€ infra/                 # Infrastructure as Code (Pulumi)
β”‚   β”œβ”€β”€ index.ts           # Main infrastructure definition
β”‚   β”œβ”€β”€ package.json       # Pulumi dependencies
β”‚   β”œβ”€β”€ deploy.sh          # Deployment automation script
β”‚   └── README.md          # Infrastructure documentation
β”œβ”€β”€ shared/                # Shared TypeScript types and utilities
└── docker-compose.yml     # Unified Docker setup

πŸ›‘οΈ Environment Configuration

Single .env File Approach

LinkPipe uses a single .env file in the root directory for all services:

# Local Development Ports
LINKPIPE_PORT=8000
POSTGRES_PORT=5433
PGADMIN_PORT=8003

# Database Configuration (PostgreSQL + Prisma)
DATABASE_URL=postgresql://linkpipe:linkpipe@localhost:5433/linkpipe
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_DB=linkpipe
POSTGRES_USER=linkpipe
POSTGRES_PASSWORD=linkpipe

# Local Development Configuration
NODE_ENV=development
SERVE_STATIC=true

# Authentication Configuration
JWT_SECRET=your-super-secret-jwt-key-change-in-production
SESSION_SECRET=your-super-secret-session-key-change-in-production

Port Configuration

All ports are configurable via environment variables. If you have conflicts:

# Edit .env file
LINKPIPE_PORT=9000
POSTGRES_PORT=5434
PGADMIN_PORT=9003

🌍 Deployment Options

Option 1: AWS with Pulumi (Recommended) ⭐

Deploy to AWS using Infrastructure as Code with Pulumi:

# Navigate to infrastructure directory
cd infra

# Run the deployment script (offers to generate secrets automatically)
./deploy.sh dev latest mattstratton/linkpipe

# Or deploy manually
npm install
pulumi stack init dev
pulumi config set aws:region us-east-1
pulumi config set --secret linkpipe:dbPassword your-secure-password
pulumi config set --secret linkpipe:jwtSecret your-jwt-secret
pulumi config set --secret linkpipe:sessionSecret your-session-secret
pulumi up

πŸ’‘ Pro Tip: The deployment script can automatically generate secure secrets for you, or you can provide your own.

πŸ” Secret Requirements:

  • Database Password: Minimum 8 characters
  • JWT Secret: Minimum 32 characters (recommended: 64+)
  • Session Secret: Minimum 32 characters (recommended: 64+)

Multi-Domain HTTPS Setup

LinkPipe supports multiple domains with automatic HTTPS. See docs/MULTI_DOMAIN_SETUP.md for detailed instructions.

Key Features:

  • External DNS Support: Works with any DNS provider (GoDaddy, Namecheap, Cloudflare, etc.)
  • Automatic HTTPS: SSL certificates managed by AWS Certificate Manager
  • Multiple Domains: Single certificate covers all configured domains
  • HTTP to HTTPS Redirect: Automatic redirect for security

Quick Setup:

# Deploy with your primary domain
pulumi config set primaryDomain "linkpipe.example.com"

# Add additional domains
pulumi config set --path additionalDomains '["link2.example.com", "link3.example.com"]'

# Deploy changes
pulumi up --yes

DNS Configuration: After deployment, Pulumi will output the required DNS records:

  1. Certificate Validation: TXT records for SSL certificate validation
  2. Traffic Routing: CNAME records pointing to the ALB

SSL Certificate:

  • SSL certificate is automatically provisioned via AWS Certificate Manager
  • HTTPS redirect is automatically configured
  • Certificate renewal is handled automatically

Features:

  • πŸ—οΈ ECS Fargate - Serverless container orchestration
  • πŸ—„οΈ RDS PostgreSQL - Managed database with high availability
  • πŸ”§ Application Database Setup - Tables and initial data created by application startup
  • 🌐 Application Load Balancer - HTTP/HTTPS traffic distribution
  • πŸ”’ VPC & Security Groups - Isolated network infrastructure
  • πŸ“Š CloudWatch - Logging and monitoring
  • πŸ”„ Auto-scaling - Automatic scaling based on demand
  • πŸ›‘οΈ SSL/TLS - Automatic HTTPS with ACM certificates

Cost: ~$55-75/month for production setup

Option 2: Docker Production

# Build and run production containers
docker-compose -f docker-compose.prod.yml up -d --build

Option 3: Vercel Frontend + Railway Backend

  1. Deploy Backend to Railway

    cd backend
    # Connect to Railway and deploy
  2. Deploy Frontend to Vercel

    cd frontend
    # Update VITE_API_URL in vercel.json
    vercel --prod

Option 4: Full VPS Deployment

# Clone and setup on your VPS
git clone <repository-url>
cd linkpipe
cp .env.example .env
# Edit .env with production values
docker-compose up -d

βš™οΈ Configuration

Database Schema

The application uses Prisma with PostgreSQL:

-- Links table
CREATE TABLE links (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  slug VARCHAR(50) UNIQUE NOT NULL,
  url TEXT NOT NULL,
  domain VARCHAR(255) DEFAULT 'localhost:8000',
  utm_source VARCHAR(255),
  utm_medium VARCHAR(255),
  utm_campaign VARCHAR(255),
  utm_term VARCHAR(255),
  utm_content VARCHAR(255),
  description TEXT,
  tags TEXT[],
  is_active BOOLEAN DEFAULT true,
  click_count INTEGER DEFAULT 0,
  expires_at TIMESTAMP,
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);

-- Settings table (stores domains, UTM options, etc.)
CREATE TABLE settings (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  key VARCHAR(255) UNIQUE NOT NULL,
  value JSONB NOT NULL,
  description TEXT,
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);

Domain Management

Important: Custom domains are managed in the database settings table, not environment variables.

# Get available domains
curl http://localhost:8000/api/settings/domains

# Update domains
curl -X PUT http://localhost:8000/api/settings/domains \
  -H "Content-Type: application/json" \
  -d '{
    "value": ["localhost:8000", "short.example.com"],
    "description": "Available domains for short links"
  }'

The application comes with default domains seeded in the database:

  • localhost:8000 (development)
  • short.example.com (example production domain)

Prisma Management

# Generate Prisma client
cd backend
npx prisma generate

# Run migrations
npx prisma migrate dev

# Reset database
npx prisma migrate reset

# Seed database
npm run db:seed

# Open Prisma Studio
npx prisma studio

πŸ”§ Development

Adding New Features

  1. Update Database Schema in backend/prisma/schema.prisma
  2. Create Migration with npx prisma migrate dev
  3. Update API in backend/src/routes/
  4. Update Frontend in frontend/src/
  5. Update Types in shared/src/types.ts

Development Commands

# Start development environment
docker-compose up -d

# View logs
docker-compose logs -f

# Rebuild services
docker-compose up -d --build

# Stop all services
docker-compose down

# Clean everything
docker-compose down -v

Testing

# Run backend tests
cd backend && npm test

# Run frontend tests  
cd frontend && npm test

# Run all tests
npm test

Linting

# Lint all packages
npm run lint

# Fix linting issues
npm run lint:fix

πŸ“Š API Endpoints

Links Management

POST   /api/links           # Create short link
GET    /api/links           # List all links
GET    /api/links/:slug     # Get specific link
PUT    /api/links/:slug     # Update link
DELETE /api/links/:slug     # Delete link
HEAD   /api/links/:slug     # Check if slug exists

Settings Management

GET    /api/settings        # Get all settings
GET    /api/settings/:key   # Get specific setting
PUT    /api/settings/:key   # Update setting
PUT    /api/settings        # Update multiple settings

Redirection

GET    /:slug           # Redirect to target URL (increment click count)

Example API Usage

// Create a short link
const response = await fetch('/api/links', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    url: 'https://example.com',
    slug: 'my-link', // Optional
    domain: 'short.example.com', // Optional
    utm_params: {
      utm_source: 'newsletter',
      utm_medium: 'email'
    },
    tags: ['marketing'],
    description: 'Marketing campaign link'
  })
});

// Get all links
const links = await fetch('/api/links').then(r => r.json());

// Redirect (increments click count)
window.location.href = 'http://localhost:8000/example';

πŸ’° Cost Estimates

Component Service Est. Monthly Cost
Frontend Vercel/Netlify $0-20
Backend Railway/Render/Railway $5-20
Database PostgreSQL (Railway/PlanetScale) $5-20
Domain & DNS Cloudflare/Route 53 $0-15

Total: $10-75/month depending on usage and platform

πŸ› οΈ Troubleshooting

Common Issues

  1. Port Conflicts

    # Check what's using the ports
    lsof -i :3000
    lsof -i :8000
    lsof -i :8001
    
    # Change ports in .env file
    FRONTEND_PORT=4000
    BACKEND_PORT=9000
    REDIRECT_PORT=9001
  2. Database Connection Issues

    # Check PostgreSQL is running
    docker-compose ps postgres
    
    # Restart PostgreSQL
    docker-compose restart postgres
    
    # Check logs
    docker-compose logs postgres
  3. Prisma Issues

    # Regenerate Prisma client
    cd backend
    npx prisma generate
    
    # Reset database
    npx prisma migrate reset
    
    # Check database connection
    npx prisma db push --preview-feature
  4. Build Issues

    # Clean and rebuild
    docker-compose down
    docker-compose up -d --build
    
    # Check logs
    docker-compose logs -f

Debug Mode

# Enable debug logging
DEBUG=linkpipe:* docker-compose up

# View specific service logs
docker-compose logs frontend
docker-compose logs backend
docker-compose logs postgres

🀝 Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/new-feature
  3. Commit changes: git commit -am 'Add new feature'
  4. Push to the branch: git push origin feature/new-feature
  5. Submit a pull request

πŸ“ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ™ Acknowledgments

  • Built with React, Node.js, PostgreSQL, and Prisma
  • UI components inspired by shadcn/ui
  • Icons by Lucide React
  • Database management with Prisma ORM
  • Containerized with Docker

LinkPipe - Making URL management simple and powerful! πŸš€

🎯 Getting Started Summary

# Quick start - just run this!
git clone <repository-url>
cd linkpipe
cp .env.example .env
docker-compose up -d

# Your services will be available at:
# Unified App: http://localhost:8000 (Frontend + API + Redirect)
# pgAdmin: http://localhost:8003

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages