A full-stack URL shortener application built with Java Spring Boot (backend) and React TypeScript (frontend). The service allows users to shorten long URLs, manage them with a modern web interface, and provides comprehensive search and deletion capabilities.
- Features
- Technologies Used
- Prerequisites
- Quick Start
- Local Development
- API Documentation
- Database Schema
- Testing
- Configuration
- Error Handling
- Internationalization
- Monitoring & Observability
- Architecture
- Performance Features
- Future Enhancements
- URL Shortening: Generate short URLs for given long URLs with duplicate detection
- URL Redirection: Redirect short URLs to their original destinations with access tracking
- URL Management: List, search, and delete URLs with pagination support
- Search Functionality: Full-text search across URLs and short codes (case-insensitive)
- REST API: Comprehensive RESTful API with proper error handling
- API Documentation: Interactive Swagger/OpenAPI documentation
- Health Monitoring: Ping endpoint for service availability checks
- Exception Handling: Robust error handling with appropriate HTTP status codes
- Data Validation: Input validation with detailed error messages
- Access Tracking: Track how many times each short URL is accessed
- Modern Web Interface: Responsive Material-UI design with dark/light theme support
- Real-time Search: Debounced search functionality with instant results
- URL Management: Create, view, search, and delete URLs with intuitive interface
- Pagination: Navigate through large sets of URLs efficiently
- Undo Functionality: Undo URL deletions with toast notifications
- Internationalization: Multi-language support (English/Turkish)
- Error Handling: User-friendly error messages and loading states
- Responsive Design: Works seamlessly on desktop and mobile devices
- Containerization: Full Docker Compose setup for easy deployment
- Database: MongoDB for reliable data persistence
- Environment Configuration: Flexible configuration for different environments
- CORS Support: Properly configured cross-origin resource sharing
- Monitoring: New Relic full-stack monitoring (Infrastructure, APM, Browser)
- Java 17 - Programming language
- Spring Boot 3.4.1 - Web framework and dependency injection
- Spring Data MongoDB - Database integration
- MongoDB 6.0.20 - NoSQL database for data persistence
- Swagger/OpenAPI 3 - API documentation
- JUnit 5 & Mockito - Unit and integration testing
- Maven - Build and dependency management
- React 19.1.0 - UI library
- TypeScript - Type-safe JavaScript
- Material-UI (MUI) 7.1.1 - Component library and theming
- Vite - Build tool and development server
- i18next - Internationalization framework
- ESLint - Code linting and formatting
- Docker & Docker Compose - Containerization and orchestration
- MongoDB 6.0.20 - Document database
- Nginx - Frontend web server (in production container)
- New Relic - Full-stack monitoring and observability platform
- Docker and Docker Compose installed on your system
- Git for cloning the repository
- Java 17+ and Maven (for local development)
- Node.js 18+ and npm (for frontend development)
-
Clone the repository:
git clone <repository-url> cd urlshortener
-
Start the application with local MongoDB:
docker-compose -f docker-compose.local.yaml --env-file .env.development up --build
-
Access the applications:
- Frontend: http://localhost:3000
- Backend API: http://localhost:8080
- API Documentation: http://localhost:8080/swagger-ui.html
- MongoDB: localhost:27017 (admin/secret)
-
Clone the repository:
git clone <repository-url> cd urlshortener
-
Configure production environment:
# Copy environment template cp .env.example .env.production # Edit .env.production with your actual MongoDB Atlas connection string and production URLs nano .env.production
⚠️ Security Note: The.env.productionfile contains sensitive database credentials and is already added to.gitignore. -
Start the application:
docker-compose --env-file .env.production up --build
📋 Prerequisites for Production:
- Domain configured:
urlshortener.melihemre.dev - nginx-proxy running on the server with
webnetwork - DNS A records pointing to your server IP
- Project repository cloned on EC2:
/home/ubuntu/urlshortener
** First-time EC2 Setup:**
# On your EC2 server cd /home/ubuntu git clone https://github.com/YOUR_USERNAME/urlshortener.git cd urlshortener
- Domain configured:
The project includes automated CI/CD pipeline that:
- Builds Docker images on every push to
mainbranch - Pushes images to Docker Hub
- Deploys to EC2 server automatically
🔧 Setup GitHub Secrets:
Navigate to your GitHub repository → Settings → Secrets and variables → Actions, and add:
# Docker Hub
DOCKER_HUB_USERNAME=your_dockerhub_username
DOCKER_HUB_ACCESS_TOKEN=your_dockerhub_access_token
# EC2 Deployment
EC2_HOST=your_server_ip_or_domain
EC2_USER=ubuntu
EC2_SSH_KEY=your_private_ssh_key_content
# Application Environment
MONGODB_URI=your_mongodb_atlas_connection_string
SERVICE_URL=https://urlshortener.melihemre.dev
VITE_API_URL=https://urlshortener.melihemre.dev/api
LETSENCRYPT_EMAIL=your_email@domain.com
# Monitoring
NEW_RELIC_LICENSE_KEY=your_newrelic_license_key** Deployment Process:**
-
Push code to
mainbranch -
GitHub Actions automatically builds and pushes Docker images (including New Relic monitoring)
-
Connects to EC2 and updates the application
-
Deploys full-stack monitoring with New Relic
-
Runs health checks to verify deployment
-
Access the applications:
- Frontend: https://urlshortener.melihemre.dev
- Backend API: https://urlshortener.melihemre.dev/api
- API Documentation: https://urlshortener.melihemre.dev/api/swagger-ui.html
When switching from production to development (or vice versa), you may need to clean up Docker networks:
-
Check existing networks:
docker network ls --filter "name=urlshortener" -
Remove the network if needed:
docker network rm urlshortener_default
-
Then start with the desired environment:
# For development docker-compose -f docker-compose.local.yaml --env-file .env.development up --build # For production docker-compose --env-file .env.production up --build
cd backend
mvn clean install
mvn spring-boot:runcd frontend
npm install
npm run dev- Endpoint:
POST /api/url - Request:
{ "longUrl": "https://example.com" } - Response:
{ "shortUrl": "http://localhost:8080/abc123" }
- Endpoint:
GET /{shortCode} - Example:
GET /abc123 - Response: 302 redirect to the original URL
- Endpoint:
GET /api/url - Parameters:
page(optional): Page number (0-based, default: 0)size(optional): Items per page (default: 10)
- Response:
{ "content": [...], "page": 0, "size": 10, "totalElements": 25, "totalPages": 3, "first": true, "last": false }
- Endpoint:
GET /api/url/search - Parameters:
q(optional): Search term for URLs and short codespage(optional): Page number (default: 0)size(optional): Items per page (default: 10)
- Response: Same paginated format as list URLs
- Endpoint:
DELETE /api/url/{id} - Response: 200 OK (empty body)
- Endpoint:
GET /api/ping - Response:
"pong"
- Swagger UI: http://localhost:8080/swagger-ui.html
- OpenAPI Specs: http://localhost:8080/v3/api-docs
The application uses MongoDB with the following document structure:
{
"_id": "ObjectId",
"longUrl": "https://example.com",
"shortCode": "abc123",
"createdAt": "2025-06-15T10:30:00Z",
"accessCount": 42,
"_class": "com.github.melihemreguler.urlshortener.dto.UrlDto"
}cd backend
mvn testTest Coverage:
- Unit Tests: 52 tests covering all service and controller methods
- Integration Tests: 17 tests for MongoDB repository operations
- Mocking: Comprehensive mocking with Mockito
- Test Profiles: Separate test configuration for isolated testing
Test Categories:
UrlServiceTest: Business logic testing (17 tests)UrlControllerTest: REST API endpoint testing (16 tests)UrlRepositoryTest: Database integration testing (17 tests)RedirectControllerTest: URL redirection testing (2 tests)
cd frontend
npm run test # (when configured)The application uses environment files for configuration:
# MongoDB Atlas connection string
MONGODB_URI=mongodb+srv://username:password@cluster.mongodb.net/urlshortenerdb
# Service URL for generating short URLs (your production domain)
SERVICE_URL=https://your-production-domain.com
# Spring profile
SPRING_PROFILES_ACTIVE=production# Local MongoDB connection (for Docker Compose)
MONGODB_URI=mongodb://admin:secret@mongodb:27017/urlshortenerdb?authSource=admin
# Service URL for development
SERVICE_URL=http://localhost:8080
# Spring profile
SPRING_PROFILES_ACTIVE=development# Backend API URL
VITE_API_URL=http://localhost:8080- MongoDB: Local containerized instance (docker-compose.local.yaml)
- Configuration: Uses
.env.development - Frontend: Development server with hot reload
- Database:
mongodb://admin:secret@mongodb:27017/urlshortenerdb?authSource=admin
- MongoDB: MongoDB Atlas cloud database
- Configuration: Uses
.env.production - Frontend: Optimized build served by nginx
- Database: MongoDB Atlas connection string
- Create a MongoDB Atlas cluster
- Get your connection string from Atlas dashboard
- Add it to
.env.productionasMONGODB_URI
- Use
docker-compose.local.yamlto start MongoDB container - MongoDB will be available at
mongodb://admin:secret@mongodb:27017
# Start local development with MongoDB
docker-compose -f docker-compose.local.yaml up --build
# Start production deployment (requires .env.production)
docker-compose up --buildThe application implements comprehensive error handling:
- 400 Bad Request: Invalid input, validation errors, malformed JSON
- 404 Not Found: Short URL not found
- 500 Internal Server Error: Unexpected server errors
- User-friendly error messages
- Loading states and indicators
- Graceful fallbacks for network issues
- Toast notifications for user feedback
The frontend supports multiple languages:
- English (default)
- Turkish
Language detection is automatic based on browser settings, with manual switching available.
The application includes comprehensive New Relic monitoring for optimal performance and reliability:
- Infrastructure: Server metrics, Docker containers, system resources
- APM: Backend performance, database queries, transaction tracing
- Browser: Frontend performance, user experience, JavaScript errors
- Alerts: Real-time notifications for performance thresholds
- Response times and throughput
- Error rates and Apdex scores
- Resource utilization (CPU, memory, disk)
- Database performance and query optimization
Access Dashboard: New Relic Monitoring
Controller Layer (REST endpoints)
↓
Service Layer (Business logic)
↓
Repository Layer (Data access)
↓
MongoDB Database
React Components
↓
Custom Hooks (useUrlManagement)
↓
API Layer (axios/fetch)
↓
Backend REST API
- Pagination: Efficient handling of large datasets
- Debounced Search: Optimized search performance
- Connection Pooling: MongoDB connection optimization
- Caching: Browser caching for static assets
- Lazy Loading: On-demand resource loading
- User authentication and authorization
- URL expiration dates
- Analytics dashboard
- Custom short code support
- QR code generation
- Bulk URL operations
- API rate limiting
- Email notifications
- URL preview functionality
- Advanced search filters