A production-ready, full-stack URL shortening service built with Spring Boot backend and Angular frontend, designed for scalability, performance, and an exceptional user experience.
Shortify is a comprehensive, full-stack URL shortening service that transforms long, unwieldy URLs into short, manageable links. Built with an enterprise-grade Spring Boot backend and a modern Angular frontend, this service provides a robust foundation for production deployment with features like user authentication, personalized URL dashboards, analytics, expiration controls, and an intuitive user interface.
- URL Shortening - Convert long URLs into short, easy-to-share links
- Custom Short URLs - Support for custom short codes (planned)
- URL Analytics - Track click counts and usage statistics
- URL Expiration - Set expiration dates for temporary links
- User Management - Multi-user support with role-based access control
- Premium Accounts - Support for premium user features
- π User Authentication - Secure login and registration system with JWT token-based authentication
- π Personalized URL Dashboard - User-specific dashboard displaying all shortened URLs mapped to individual users
- π Analytics & Insights - Real-time click tracking, geographic data, and URL performance metrics
- π¨ Responsive UI Design - Mobile-first, responsive design for seamless experience across all devices
- β‘ Real-time Updates - Dynamic content updates without page refresh using RxJS observables
- π Search & Filter - Advanced search and filtering capabilities for managing URLs
- π URL Management - Create, edit, delete, and organize shortened URLs with ease
- π€ User Profile Management - Update profile information, change password, and manage account settings
- π Notifications - Toast notifications for user actions and system alerts
- π Dark Mode Support - Theme switching for better user experience (planned)
- RESTful API - Clean, well-documented API endpoints
- Multi-Database Support - MySQL and PostgreSQL compatibility
- Environment Profiles - Separate configurations for development and production
- Health Monitoring - Spring Boot Actuator integration
- CORS Support - Cross-Origin Resource Sharing enabled for Angular frontend
- Connection Pooling - HikariCP for optimized database connections
- Production Ready - Configured for deployment at scale
Shortify follows a modern, decoupled architecture with a clear separation between backend and frontend:
| Layer | Technology | Purpose |
|---|---|---|
| Frontend Framework | Angular 21 | Single-page application with reactive forms and routing |
| Frontend Language | TypeScript 4.3 | Type-safe development with modern JavaScript features |
| Styling | SCSS | Component-scoped and global styling with variables |
| State Management | RxJS 6.6 | Reactive state management using observables |
| HTTP Client | Angular HttpClient | RESTful API communication with interceptors |
| Backend Framework | Spring Boot 4.5.5 | RESTful API server with dependency injection |
| Java Version | 21 (LTS) | Long-term support Java runtime |
| ORM | JPA/Hibernate | Object-relational mapping for database operations |
| Database | MySQL | Relational database for persistent storage |
| Connection Pool | HikariCP | High-performance JDBC connection pooling |
| Build Tool - Backend | Maven 3.x | Dependency management and build automation |
| Build Tool - Frontend | Angular CLI | Development server, build, and deployment tooling |
| Monitoring | Spring Boot Actuator | Health checks and application metrics |
βββββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββ
β β HTTP β β JDBC β β
β Angular UI β βββββββΊ β Spring Boot API β βββββββΊ β Database β
β (Port 4200) β REST β (Port 8080) β β MySQL/PG β
β β β β β β
βββββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββ
β β
β β
Browser JWT Auth
RxJS/Forms JPA/Hibernate
Routing Service Layer
Shortify/
βββ Server/ # Spring Boot Backend
β βββ src/
β β βββ main/
β β β βββ java/com/urlshortener/urlshortener/
β β β β βββ controller/ # REST API Controllers
β β β β βββ service/ # Business Logic
β β β β βββ repository/ # Data Access Layer
β β β β βββ entity/ # JPA Entities
β β β β βββ models/ # DTOs and Request/Response Models
β β β β βββ enums/ # Enumerations
β β β βββ resources/
β β β βββ application.properties # Main Configuration
β β β βββ application-dev.properties # Development Profile
β β β βββ application-prod.properties # Production Profile
β β βββ test/ # Test Suite
β βββ pom.xml # Maven Dependencies
β βββ mvnw # Maven Wrapper
β
βββ Client/ # Angular Frontend
β βββ src/
β β βββ app/
β β β βββ core/ # Core Module (Services, Guards, Interceptors)
β β β β βββ services/ # HTTP Services (Auth, URL, User)
β β β β βββ guards/ # Route Guards (Auth Guard)
β β β β βββ interceptors/ # HTTP Interceptors (JWT, Error)
β β β β βββ models/ # TypeScript Interfaces & Models
β β β βββ features/ # Feature Modules
β β β β βββ auth/ # Authentication Module
β β β β β βββ login/ # Login Component
β β β β β βββ register/ # Registration Component
β β β β β βββ auth.module.ts
β β β β βββ dashboard/ # Dashboard Module
β β β β β βββ url-list/ # URL List Component
β β β β β βββ url-create/ # Create URL Component
β β β β β βββ analytics/ # Analytics Component
β β β β β βββ dashboard.module.ts
β β β β βββ profile/ # User Profile Module
β β β β βββ profile-view/ # View Profile
β β β β βββ profile-edit/ # Edit Profile
β β β β βββ profile.module.ts
β β β βββ shared/ # Shared Module
β β β β βββ components/ # Reusable Components
β β β β βββ directives/ # Custom Directives
β β β β βββ pipes/ # Custom Pipes
β β β β βββ shared.module.ts
β β β βββ app-routing.module.ts # Root Routing Configuration
β β β βββ app.module.ts # Root Module
β β β βββ app.component.ts # Root Component
β β βββ environments/
β β β βββ environment.ts # Development Environment
β β β βββ environment.prod.ts # Production Environment
β β βββ assets/ # Static Assets (Images, Icons)
β β βββ styles.scss # Global Styles
β β βββ index.html # Main HTML File
β βββ angular.json # Angular CLI Configuration
β βββ package.json # Node Dependencies
β βββ tsconfig.json # TypeScript Configuration
β
βββ README.md # This File
The Shortify frontend is built with Angular 21, providing a modern, responsive, and user-friendly interface for URL management.
Login Component
- Secure user authentication with JWT tokens
- Form validation using Angular Reactive Forms
- Email and password authentication
- "Remember Me" functionality
- Error handling with user-friendly messages
- Automatic redirection to dashboard after successful login
Registration Component
- New user account creation
- Password strength validation
- Email format validation
- Username uniqueness check
- Terms and conditions acceptance
- Automatic login after registration
Technical Implementation:
// AuthService handles all authentication operations
- login(credentials): Observable<AuthResponse>
- register(userData): Observable<User>
- logout(): void
- isAuthenticated(): boolean
- getToken(): string
- getCurrentUser(): Observable<User>Authentication Flow:
- User submits login credentials
- Angular HttpClient sends POST request to
/api/auth/login - Backend validates credentials and returns JWT token
- Token is stored in localStorage/sessionStorage
- HTTP Interceptor adds token to all subsequent API requests
- Auth Guard protects dashboard and protected routes
- User is redirected to dashboard upon successful authentication
The dashboard is the heart of the application, providing a personalized URL management interface for each authenticated user.
Dashboard Features:
URL List View
- Displays all URLs created by the logged-in user
- Paginated table view with sorting capabilities
- Columns: Short URL, Original URL, Created Date, Expiration Date, Click Count, Status
- Quick copy-to-clipboard functionality for short URLs
- Visual indicators for expired/active URLs
- Real-time click count updates
URL Creation Panel
- Quick URL shortening form
- Input validation for URL format
- Optional custom short code field
- Expiration date picker
- Success/error notifications
- Instant addition to URL list
URL Management Actions
- Edit: Modify expiration date and custom settings
- Delete: Remove URLs with confirmation dialog
- Toggle Status: Activate/deactivate URLs
- View Details: See detailed analytics
- Share: Quick share options (Email, Social Media)
- QR Code: Generate QR code for mobile sharing
Search & Filter Panel
- Search by original URL or short code
- Filter by status (Active, Expired, All)
- Filter by date range
- Sort by: Date Created, Click Count, Expiration Date
Technical Implementation:
// URLService manages all URL operations
- getUserUrls(userId): Observable<ShortUrl[]>
- createShortUrl(urlData): Observable<ShortUrl>
- updateUrl(id, data): Observable<ShortUrl>
- deleteUrl(id): Observable<void>
- getUrlAnalytics(id): Observable<Analytics>
- toggleUrlStatus(id): Observable<ShortUrl>User-Specific Mapping:
- Each URL is linked to the creating user via
user_idforeign key - Dashboard only displays URLs belonging to the authenticated user
- Users can only modify/delete their own URLs
- Admin users can view all URLs (with appropriate permissions)
Dashboard Layout:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Shortify Dashboard [User Profile βΌ] β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β [β Create New Short URL] β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Long URL: [..............................] [Shorten]β
β β Custom Code (optional): [.........] Expires: [π
] β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β π My URLs (23) π [Search...] [Filter βΌ] β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Short URL β Original URL β Clicks β Created β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β /abc123 π β example.com/..β 45 β 2h ago ββ β
β β /custom-link β mysite.org/...β 128 β 1d ago ββ β
β β /xyz789 β longurl.co/...β 7 β 3d ago ββ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β [1] 2 3 ... β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Real-time Analytics Dashboard
- Total URLs created by user
- Total clicks across all URLs
- Top performing URLs (by clicks)
- Recent activity timeline
- Geographic distribution of clicks (planned)
- Device type analytics (Desktop, Mobile, Tablet)
- Browser statistics
- Time-based click trends (hourly, daily, weekly)
URL-Specific Analytics
- Individual URL performance metrics
- Click history graph
- Referrer information
- Geographic heat map
- Peak usage times
Profile View
- Display user information (Username, Email, Role)
- Account creation date
- Premium status indicator
- Total URLs created
- Account activity statistics
Profile Edit
- Update username
- Change email address
- Update password (with current password verification)
- Profile picture upload (planned)
- Notification preferences
Reusable UI Components:
- Navbar: Top navigation with user menu and logout
- Sidebar: Quick navigation to Dashboard, Analytics, Profile
- URL Card: Displays URL information in card format
- Toast Notifications: Success, error, warning, and info messages
- Loading Spinner: Shown during API calls
- Confirmation Dialog: For destructive actions (delete, deactivate)
- Copy Button: One-click copy-to-clipboard
- Date Picker: For setting expiration dates
- Pagination: Reusable pagination component
1. AuthService (src/app/core/services/auth.service.ts)
- Handles user authentication and authorization
- Manages JWT tokens
- Provides user session information
- Implements logout functionality
2. URLService (src/app/core/services/url.service.ts)
- CRUD operations for shortened URLs
- Fetches user-specific URLs
- Handles URL analytics data
- Manages URL status updates
3. UserService (src/app/core/services/user.service.ts)
- User profile management
- Account settings updates
- User statistics and metrics
4. NotificationService (src/app/core/services/notification.service.ts)
- Toast notification management
- Success, error, and info messages
- Auto-dismiss functionality
AuthGuard (src/app/core/guards/auth.guard.ts)
- Protects authenticated routes
- Redirects unauthenticated users to login
- Checks token validity
GuestGuard (src/app/core/guards/guest.guard.ts)
- Prevents authenticated users from accessing login/register pages
- Redirects to dashboard if already logged in
JwtInterceptor (src/app/core/interceptors/jwt.interceptor.ts)
- Automatically adds JWT token to HTTP request headers
- Ensures all API calls are authenticated
ErrorInterceptor (src/app/core/interceptors/error.interceptor.ts)
- Global error handling
- HTTP error status code handling (401, 403, 500, etc.)
- Token expiration detection and automatic logout
- User-friendly error messages
const routes: Routes = [
{ path: '', redirectTo: '/login', pathMatch: 'full' },
// Public routes
{
path: 'login',
component: LoginComponent,
canActivate: [GuestGuard]
},
{
path: 'register',
component: RegisterComponent,
canActivate: [GuestGuard]
},
// Protected routes (require authentication)
{
path: 'dashboard',
component: DashboardComponent,
canActivate: [AuthGuard],
children: [
{ path: '', component: UrlListComponent },
{ path: 'create', component: UrlCreateComponent },
{ path: 'analytics', component: AnalyticsComponent },
{ path: 'analytics/:id', component: UrlAnalyticsComponent }
]
},
{
path: 'profile',
component: ProfileComponent,
canActivate: [AuthGuard]
},
// Wildcard route
{ path: '**', redirectTo: '/dashboard' }
];The application uses RxJS Observables for reactive state management:
Benefits:
- Real-time data updates
- Efficient change detection
- Asynchronous data handling
- Clean separation of concerns
Implementation Pattern:
// Component subscribes to data streams
this.urlService.getUserUrls(userId).subscribe(
urls => this.urls = urls,
error => this.notificationService.error('Failed to load URLs')
);
// Real-time updates via Subject/BehaviorSubject
private urlsSubject = new BehaviorSubject<ShortUrl[]>([]);
public urls$ = this.urlsSubject.asObservable();Reactive Forms are used throughout the application for:
- Type-safe form handling
- Built-in validation
- Dynamic form controls
- Better testing support
Example - Login Form:
loginForm = this.fb.group({
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(8)]],
rememberMe: [false]
});
onSubmit() {
if (this.loginForm.valid) {
this.authService.login(this.loginForm.value).subscribe(
response => this.router.navigate(['/dashboard']),
error => this.handleError(error)
);
}
}SCSS Architecture:
- Component-scoped styles for encapsulation
- Global styles for common patterns
- SCSS variables for theming
- Responsive design with CSS Grid and Flexbox
- Mobile-first approach
Responsive Breakpoints:
// Mobile: < 768px
// Tablet: 768px - 1024px
// Desktop: > 1024pxAll Angular services communicate with the Spring Boot backend via HTTP:
Base API URL Configuration:
// environment.ts
export const environment = {
production: false,
apiUrl: 'http://localhost:8080/api'
};
// environment.prod.ts
export const environment = {
production: true,
apiUrl: 'https://api.shortify.com/api'
};HTTP Communication Example:
@Injectable({ providedIn: 'root' })
export class URLService {
private apiUrl = `${environment.apiUrl}/shortUrl`;
constructor(private http: HttpClient) {}
getUserUrls(userId: number): Observable<ShortUrl[]> {
return this.http.get<ApiResponse<ShortUrl[]>>(
`${this.apiUrl}/user/${userId}`
).pipe(
map(response => response.data),
catchError(this.handleError)
);
}
}Before you begin, ensure you have the following installed:
Backend Requirements:
- Java 17 or higher (Download)
- Maven 3.6+ (Download)
- MySQL 8.0+ or PostgreSQL 12+ (MySQL | PostgreSQL)
Frontend Requirements:
- Node.js 14+ and npm 6+ (Download)
- Angular CLI 12.2+ (Install:
npm install -g @angular/cli)
General:
- Git (for cloning the repository)
git clone https://github.com/Sohith-reddy/Shortify.git
cd ShortifyCREATE DATABASE urlshortener;
CREATE USER 'urlshortener_user'@'localhost' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON urlshortener.* TO 'urlshortener_user'@'localhost';
FLUSH PRIVILEGES;CREATE DATABASE urlshortener;
CREATE USER urlshortener_user WITH PASSWORD 'your_password';
GRANT ALL PRIVILEGES ON DATABASE urlshortener TO urlshortener_user;Set the following environment variables:
export DB_URL_DEV="jdbc:mysql://localhost:3306/urlshortener"
export DB_USERNAME="urlshortener_user"
export DB_PASSWORD="your_password"export DB_URL_PROD="jdbc:mysql://your-production-host:3306/urlshortener"
export DB_USERNAME="urlshortener_user"
export DB_PASSWORD="your_secure_password"cd Server
./mvnw clean installOr if you have Maven installed globally:
mvn clean install./mvnw spring-boot:runexport SPRING_PROFILES_ACTIVE=prod
./mvnw spring-boot:runOr run the JAR directly:
java -jar target/urlshortener-0.0.1-SNAPSHOT.jarThe backend API will start on http://localhost:8080
cd Client
npm installThis will install all required Angular dependencies including:
- Angular Core modules (12.2.0)
- Angular Router
- Angular Forms
- RxJS
- TypeScript
- Development tools
Update the environment files if your backend is running on a different host/port:
Development (src/environments/environment.ts):
export const environment = {
production: false,
apiUrl: 'http://localhost:8080/api'
};Production (src/environments/environment.prod.ts):
export const environment = {
production: true,
apiUrl: 'https://your-production-api.com/api'
};npm start
# or
ng serveThe Angular application will be available at http://localhost:4200
Default Settings:
- Development server runs on port 4200
- Auto-reload enabled (watches for file changes)
- Source maps enabled for debugging
- Proxy configuration for API calls (if needed)
npm run build
# or
ng build --configuration productionProduction build output will be in Client/dist/client/
To run both backend and frontend simultaneously:
Terminal 1 - Backend:
cd Server
./mvnw spring-boot:runTerminal 2 - Frontend:
cd Client
npm startThen open your browser and navigate to:
- Frontend UI:
http://localhost:4200 - Backend API:
http://localhost:8080/api
After starting the application, you can:
- Register a new account via the UI at
http://localhost:4200/register - Or use the API directly:
curl -X POST http://localhost:8080/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"username": "admin",
"email": "admin@example.com",
"password": "SecurePassword123",
"role": "ADMIN"
}'Then login with your credentials at http://localhost:4200/login
Shortify supports multiple environment profiles:
- Auto-creates/updates database schema
- SQL logging enabled
- Smaller connection pool (2-10 connections)
- Detailed error messages
- Schema validation only (no auto-updates)
- SQL logging disabled
- Larger connection pool (10-30 connections)
- Connection timeout: 30 seconds
- Idle timeout: 10 minutes
- Max connection lifetime: 30 minutes
Edit the appropriate properties file:
- Development:
src/main/resources/application-dev.properties - Production:
src/main/resources/application-prod.properties
Key configuration options:
# Database
spring.datasource.url=${DB_URL}
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}
# Connection Pool
spring.datasource.hikari.maximum-pool-size=30
spring.datasource.hikari.minimum-idle=10
# Server
server.port=8080http://localhost:8080/api
Endpoint: POST /api/shortUrl/shorten
Description: Shorten a long URL
Request Parameters:
longUrl(String, required) - The URL to be shortened
Example Request:
curl -X POST "http://localhost:8080/api/shortUrl/shorten?longUrl=https://www.example.com/very/long/url/path"Example Response:
{
"status": true,
"message": "URL shortened successfully",
"data": "http://localhost:8080/abc123",
"statusCode": 200
}All API responses follow this structure:
{
"status": boolean,
"message": "string",
"data": object,
"statusCode": number,
"token": "string (optional)",
"expiresInSec": number (optional)
}| Column | Type | Constraints | Description |
|---|---|---|---|
| id | BIGINT | PRIMARY KEY, AUTO_INCREMENT | Unique identifier |
| short_url | VARCHAR(255) | UNIQUE, NOT NULL | Short URL code |
| original_url | TEXT | NOT NULL | Original long URL |
| created_at | TIMESTAMP | NULL | Creation timestamp |
| expiration_time | TIMESTAMP | NULL | Expiration timestamp |
| user_id | BIGINT | FOREIGN KEY | Reference to users table |
| is_active | INT | NULL | Active status (1=active, 0=inactive) |
| click_count | BIGINT | NULL | Number of clicks/redirects |
| Column | Type | Constraints | Description |
|---|---|---|---|
| user_id | BIGINT | PRIMARY KEY, AUTO_INCREMENT | Unique user identifier |
| user_name | VARCHAR(255) | UNIQUE, NOT NULL | Username |
| VARCHAR(255) | UNIQUE, NOT NULL | Email address | |
| password | VARCHAR(255) | NOT NULL | Encrypted password |
| role | VARCHAR(50) | NOT NULL | User role (USER, ADMIN) |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | Account creation time |
| updated_at | TIMESTAMP | NULL | Last update timestamp |
| is_active | INT | NULL | Account status |
| is_premium | INT | NULL | Premium subscription status |
- User β ShortUrl: One-to-Many (One user can create many short URLs)
- Cascade delete: Deleting a user deletes all their short URLs
- Lazy loading: Short URLs are loaded only when accessed
cd Server
./mvnw test./mvnw test -Dtest=UrlshortenerApplicationTestsThe backend includes test dependencies for:
- Unit testing with JUnit 5
- Integration testing with Spring Boot Test
- Repository testing with Data JPA Test
- Controller testing with WebMvc Test
- Validation testing
cd Client
npm test
# or
ng testThis runs unit tests using Karma test runner with Jasmine framework.
ng test --watch=false --browsers=ChromeHeadlessng test --code-coverageCoverage report will be generated in Client/coverage/
ng e2eAngular tests are located alongside their components:
*.spec.ts- Unit test files- Tests for components, services, guards, and interceptors
- Mocking HTTP requests with HttpClientTestingModule
- Testing routing with RouterTestingModule
Example Test:
describe('LoginComponent', () => {
it('should validate email format', () => {
const component = fixture.componentInstance;
component.loginForm.controls['email'].setValue('invalid-email');
expect(component.loginForm.controls['email'].valid).toBeFalsy();
});
});curl http://localhost:8080/actuator/healthResponse:
{
"status": "UP"
}/actuator/health- Application health status/actuator/info- Application information/actuator/metrics- Application metrics
- Set the production profile:
export SPRING_PROFILES_ACTIVE=prod- Build the JAR:
cd Server
./mvnw clean package -DskipTests- The executable JAR will be in
Server/target/urlshortener-0.0.1-SNAPSHOT.jar
Create a Dockerfile in the Server directory:
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/urlshortener-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8080
ENV SPRING_PROFILES_ACTIVE=prod
ENTRYPOINT ["java", "-jar", "app.jar"]Build and run:
docker build -t shortify-backend:latest .
docker run -p 8080:8080 \
-e DB_URL_PROD="jdbc:mysql://host:3306/urlshortener" \
-e DB_USERNAME="user" \
-e DB_PASSWORD="password" \
shortify-backend:latestcd Client
npm run build
# or
ng build --configuration productionThis creates an optimized production build in Client/dist/client/ with:
- Minified JavaScript bundles
- Tree-shaking for smaller bundle size
- Ahead-of-Time (AOT) compilation
- Production environment configuration
- Optimized images and assets
1. Nginx Server
Create nginx.conf:
server {
listen 80;
server_name your-domain.com;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://backend:8080/api;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}Dockerfile for Angular:
# Build stage
FROM node:14-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM nginx:alpine
COPY --from=builder /app/dist/client /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]Build and run:
docker build -t shortify-frontend:latest .
docker run -p 80:80 shortify-frontend:latest2. Apache Server
Configure .htaccess for Angular routing:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>3. Cloud Hosting Platforms
Deploy Angular app to various platforms:
-
Netlify:
npm install -g netlify-cli netlify deploy --prod --dir=dist/client
-
Vercel:
npm install -g vercel vercel --prod
-
AWS S3 + CloudFront:
aws s3 sync dist/client/ s3://your-bucket-name aws cloudfront create-invalidation --distribution-id YOUR_DIST_ID --paths "/*" -
Firebase Hosting:
npm install -g firebase-tools firebase init hosting firebase deploy
-
Azure Static Web Apps: Deployable directly via GitHub Actions or Azure CLI
-
Google Cloud Storage:
gsutil -m rsync -r dist/client gs://your-bucket-name
Create docker-compose.yml in the root directory:
version: '3.8'
services:
database:
image: mysql:8.0
environment:
MYSQL_DATABASE: urlshortener
MYSQL_USER: urlshortener_user
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
networks:
- shortify-network
backend:
build: ./Server
ports:
- "8080:8080"
environment:
SPRING_PROFILES_ACTIVE: prod
DB_URL_PROD: jdbc:mysql://database:3306/urlshortener
DB_USERNAME: urlshortener_user
DB_PASSWORD: ${DB_PASSWORD}
depends_on:
- database
networks:
- shortify-network
frontend:
build: ./Client
ports:
- "80:80"
depends_on:
- backend
networks:
- shortify-network
volumes:
mysql-data:
networks:
shortify-network:
driver: bridgeRun the entire stack:
docker-compose up -dAccess the application:
- Frontend: http://localhost
- Backend API: http://localhost:8080/api
Shortify can be deployed on:
Backend:
- AWS (Elastic Beanstalk, ECS, EC2, Lambda with API Gateway)
- Google Cloud Platform (App Engine, Cloud Run, GKE)
- Azure (App Service, AKS, Container Instances)
- Heroku (with PostgreSQL addon)
- DigitalOcean App Platform
Frontend:
- Netlify (Recommended for Angular)
- Vercel
- AWS S3 + CloudFront
- Firebase Hosting
- Azure Static Web Apps
- GitHub Pages
- Google Cloud Storage
- Set
SPRING_PROFILES_ACTIVE=prod - Configure secure database credentials
- Use environment variables for sensitive data
- Enable HTTPS/SSL for both frontend and backend
- Configure firewall rules
- Set up database backups
- Configure logging and monitoring
- Set up alerts for health check failures
- Implement rate limiting (recommended)
- Enable Spring Security (currently disabled)
- Configure CORS for production (restrict allowed origins)
- Set up CDN for frontend assets
- Enable gzip compression for API responses
- Configure proper caching headers
- Set up automated backups
- Implement monitoring and logging (ELK stack, CloudWatch, etc.)
- Configure Angular production environment variables
- Enable service worker for PWA features (optional)
- Set up analytics tracking (Google Analytics, etc.)
- CORS enabled for all origins (configure for production)
- Health check details hidden
- Password fields should be encrypted before storage
- Enable Spring Security (currently commented out in pom.xml)
- Add authentication - JWT tokens or session-based
- Implement rate limiting - Prevent abuse
- Use HTTPS - Encrypt data in transit
- Input validation - Validate and sanitize URLs
- SQL injection prevention - Use parameterized queries (already implemented via JPA)
- CORS configuration - Restrict allowed origins in production
This project uses:
- Lombok for reducing boilerplate code
- JPA conventions for database operations
- RESTful API design principles
- Create/update entities in
entity/package - Define repository methods in
repository/package - Implement business logic in
service/package - Expose endpoints in
controller/package - Create DTOs in
models/package if needed - Write tests for new functionality
cd Server
./mvnw spring-boot:run -Dspring-boot.run.profiles=devEnable auto-reload for faster development.
cd Client
npm start
# or
ng serveThe dev server will:
- Start on
http://localhost:4200 - Auto-reload on file changes
- Provide source maps for debugging
- Enable detailed error messages
Angular CLI provides scaffolding commands:
Generate a new component:
ng generate component features/dashboard/url-list
# or shorthand
ng g c features/dashboard/url-listGenerate a new service:
ng generate service core/services/url
# or shorthand
ng g s core/services/urlGenerate a new module:
ng generate module features/dashboard --routingGenerate a guard:
ng generate guard core/guards/authGenerate an interceptor:
ng generate interceptor core/interceptors/jwtFollow this modular architecture:
src/app/
βββ core/ # Singleton services, guards, interceptors
βββ features/ # Feature modules (lazy-loaded)
βββ shared/ # Shared components, directives, pipes
βββ app-routing.module.ts
TypeScript:
- Use strict TypeScript (
strict: truein tsconfig.json) - Prefer interfaces over classes for data models
- Use async/await with observables where appropriate
- Follow Angular style guide
Components:
- Keep components small and focused
- Use OnPush change detection for performance
- Unsubscribe from observables in ngOnDestroy
- Use async pipe in templates when possible
Services:
- Keep business logic in services, not components
- Use dependency injection
- Return observables from HTTP calls
- Handle errors appropriately
Example Service Pattern:
@Injectable({ providedIn: 'root' })
export class URLService {
private apiUrl = `${environment.apiUrl}/shortUrl`;
constructor(
private http: HttpClient,
private notificationService: NotificationService
) {}
getUserUrls(userId: number): Observable<ShortUrl[]> {
return this.http.get<ApiResponse<ShortUrl[]>>(
`${this.apiUrl}/user/${userId}`
).pipe(
map(response => response.data),
catchError(error => {
this.notificationService.error('Failed to load URLs');
return throwError(() => error);
})
);
}
}For even faster development, enable HMR:
ng serve --hmrRun ESLint to check code quality:
ng lintUse Prettier for consistent code formatting (if configured):
npm run format- Run Spring Boot with debug enabled:
./mvnw spring-boot:run -Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"- Attach your IDE debugger to port 5005
Chrome DevTools:
- Open Chrome DevTools (F12)
- Use breakpoints in Sources tab
- Angular DevTools extension for component inspection
VS Code Debugging:
Create .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Angular Debug",
"url": "http://localhost:4200",
"webRoot": "${workspaceFolder}/Client/src"
}
]
}- Use database connection pooling (HikariCP)
- Implement caching (Redis recommended)
- Add database indexes
- Use pagination for large datasets
- Optimize SQL queries
- Lazy load feature modules
- Use OnPush change detection strategy
- Implement virtual scrolling for large lists
- Optimize bundle size with tree-shaking
- Use trackBy with *ngFor
- Implement service workers for caching
# Navigate to Server directory
cd Server
# Install dependencies and build
./mvnw clean install
# Run in development mode
./mvnw spring-boot:run
# Run in production mode
SPRING_PROFILES_ACTIVE=prod ./mvnw spring-boot:run
# Run tests
./mvnw test
# Build production JAR
./mvnw clean package -DskipTests# Navigate to Client directory
cd Client
# Install dependencies
npm install
# Start development server (http://localhost:4200)
npm start
# Build for production
npm run build
# Run tests
npm test
# Run tests with coverage
ng test --code-coverage
# Generate a component
ng generate component features/my-component
# Generate a service
ng generate service core/services/my-service
# Lint code
ng lint# Run full stack with Docker Compose
docker-compose up -d
# Stop all services
docker-compose down
# View logs
docker-compose logs -f
# Rebuild and restart
docker-compose up -d --buildWe welcome contributions! To contribute:
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
- Follow Java naming conventions
- Write unit tests for new features
- Update documentation as needed
- Ensure all tests pass before submitting PR
- URL redirection endpoint
- Custom short URL codes
- URL expiration automation
- Advanced analytics API endpoints
- QR code generation API
- API rate limiting
- User authentication and authorization (JWT)
- OAuth2 integration (Google, GitHub)
- Admin dashboard API
- Bulk URL shortening API
- API key management
- Redis caching layer
- URL validation and sanitization
- WebSocket support for real-time updates
- GraphQL API (optional)
- Complete authentication flow (Login, Register, Forgot Password)
- User-specific URL dashboard with CRUD operations
- Advanced analytics dashboard with charts (Chart.js or ngx-charts)
- QR code generation and display
- Bulk URL shortening interface
- URL categorization and tagging system
- Search and filter functionality
- Sorting capabilities (by date, clicks, etc.)
- Export URLs to CSV/Excel
- Dark mode / Light mode toggle
- Multiple language support (i18n)
- Progressive Web App (PWA) features
- Push notifications
- Social media sharing integration
- Custom domain support UI
- URL preview with link thumbnails
- Keyboard shortcuts for power users
- Drag-and-drop URL organization
- Advanced user profile with avatar upload
- Two-factor authentication (2FA) setup
- Activity log and audit trail
- Custom themes and branding
- Responsive mobile app experience
- Accessibility improvements (WCAG 2.1 AA compliance)
- CI/CD pipeline (GitHub Actions)
- Automated testing (unit, integration, e2e)
- Docker containerization (completed)
- Kubernetes deployment configuration
- Monitoring and alerting setup
- ELK stack for logging
- Performance monitoring (New Relic, Datadog)
- Automated backups
- Blue-green deployment strategy
- Load balancing configuration
This project is licensed under the MIT License - see the LICENSE file for details.
Sohith Reddy
- GitHub: @Sohith-reddy
- Repository: Shortify
- Spring Boot team for the excellent framework
- HikariCP for high-performance connection pooling
- The open-source community
For support, please:
- Open an issue on GitHub
- Check existing documentation
- Review closed issues for solutions
Built with β€οΈ using Spring Boot
Shortify - Making URLs shorter, one link at a time.