System Design Document: URL Shortener Microservice
## 1. Overview
This document outlines the system design for a full-stack URL shortener application. The system
consists of a backend microservice responsible for URL shortening, redirection, and analytics, and a
frontend single-page application (SPA) for user interaction. The design prioritizes modularity,
adherence to specified constraints, and maintainability.
## 2. System Architecture
The application is built on a Client-Server architecture following a microservice pattern. The three
primary components are:
1. Frontend Client: A React-based web application that serves as the user interface. It is
responsible for rendering the UI and communicating with the backend.
2. Backend Microservice: A stateless Node.js service that exposes a RESTful API to handle all
business logic, including link creation, redirection, and statistics aggregation.
3. External Logging Service: A predefined endpoint that receives structured log data from both
the frontend and backend via a custom logging middleware, decoupling logging from the
application's core responsibilities.
Communication between the frontend and backend occurs over HTTP via RESTful API calls.
## 3. Technology Stack
Component Technology Justification
The asynchronous, non-blocking I/O model of Node.js is highly efficient
Node.js &
Backend for handling numerous concurrent requests, making it ideal for a
Express.js
redirection and API service.
Enforces static typing, which significantly improves code quality,
TypeScript reduces runtime errors, and enhances maintainability, especially as an
application scales.
The component-based architecture promotes reusable and
Frontend React (Vite) maintainable UI code. Vite was chosen for its superior development
experience and performance.
A comprehensive component library that accelerates development and
Material UI ensures a professional, consistent UI, as stipulated by the project
requirements.
A robust, promise-based HTTP client that simplifies making API requests
Axios
and handling responses on the frontend.
Export to Sheets
## 4. Data Modeling and Persistence
Data Models
Two primary data models were designed:
UrlData: Represents a shortened link.
o shortcode (string, Primary Key): The unique generated identifier.
o originalUrl (string): The destination URL.
o creationDate (Date): Timestamp of creation.
o expiryDate (Date): Timestamp when the link becomes invalid.
ClickData: Represents a single redirection event.
o timestamp (Date): The time of the click.
o source (string): The HTTP referrer, indicating where the click came from.
o location (string): A placeholder for coarse-grained geographical data (simulated using
the request IP).
Persistence Strategy
In-Memory Storage: For the scope of this evaluation, an in-memory persistence strategy
using JavaScript Map objects was chosen.
Justification: This approach provides extremely high performance for reads and writes and
avoids the setup complexity of an external database, making it ideal for a time-constrained
assessment.
Scalability Note: In a production environment, this would be replaced with a distributed,
persistent key-value store like Redis to ensure data durability, handle high throughput, and
support a horizontally scaled, multi-instance deployment.
## 5. Code Design and Key Decisions
Backend: Separation of Concerns: The backend code is structured with distinct layers for
routing (routes) and business logic (controllers). This makes the application easier to
understand, test, and maintain.
Frontend: Centralized API Logic: All backend API calls are managed in a dedicated service file
(api/shortenerApi.ts). This decouples the UI components from the data-fetching logic,
preventing code duplication and simplifying future modifications.
Shortcode Generation: The nanoid library was selected to generate unique shortcodes. It is
URL-friendly, provides high collision resistance, and is more secure than simple incremental
IDs.
Logging Integration: A custom logging function was used exclusively for all event logging, as
per the core requirement. This ensures all logs are standardized and sent to the external
service, providing centralized observability.
## 6. Assumptions
Statelessness and No Authentication: The backend was designed as a public, stateless
service, assuming all users are pre-authorized as per the project brief.
Data Ephemerality: It was assumed that data did not need to persist between server
restarts.
Single-Instance Deployment: The in-memory data storage strategy assumes the backend is
running as a single instance.
Geo-location Simulation: It was assumed that an external IP-to-location lookup service was
out of scope, and using the request IP address as a placeholder for "location" was sufficient.