A robust, serverless pastebin application built with Next.js 15 and MongoDB. This application allows users to create text pastes that automatically expire based on time (TTL) or view counts.
🔗 Live Demo: https://aganitha-pastebin-lite-seven.vercel.app/
- Create Pastes: Store arbitrary text content securely.
- Time-to-Live (TTL): Optional expiration time (in seconds). Pastes are automatically invalidated after the specified duration.
- View Limits: Optional maximum view count. The paste becomes completely unavailable (404) once the limit is reached.
- Atomic View Counting: Uses MongoDB atomic operators to strictly enforce view limits, preventing race conditions under concurrent load.
- Deterministic Testing: Supports the
x-test-now-msheader (in Test Mode) to simulate time travel for automated grading.
- Framework: Next.js 15 (App Router)
- Language: TypeScript
- Database: MongoDB (via Mongoose ODM)
- Styling: Tailwind CSS
- Deployment: Vercel (Recommended)
Follow these instructions to run the project locally.
- Node.js 18+ installed.
- A MongoDB connection string (Local or Atlas).
-
Clone the repository:
git clone [https://github.com/YOUR_GITHUB_USERNAME/pastebin-lite.git](https://github.com/YOUR_GITHUB_USERNAME/pastebin-lite.git) cd pastebin-lite -
Install dependencies:
npm install
-
Configure Environment Variables: Create a
.env.localfile in the root directory and add your MongoDB credentials:# MongoDB Connection String MONGODB_URI="mongodb+srv://<username>:<password>@cluster0.mongodb.net/pastebin-lite" # Set to "1" to enable deterministic time testing via headers TEST_MODE="1"
-
Run the Development Server:
npm run dev
-
Access the App: Open http://localhost:3000 in your browser.
Choice: MongoDB (Mongoose)
I selected MongoDB for this project for two primary reasons:
- Document Model: The data structure for a paste (content, metadata, flexible expiration settings) maps perfectly to a JSON-like document model.
- Atomic Operations: To satisfy the strict "Max Views" requirement, I utilized MongoDB's
findOneAndUpdatewith the$incoperator. This ensures that checking the view count and incrementing it happens in a single atomic transaction. This guarantees that even if two users request the paste at the exact same millisecond, the database will never serve the paste more times than allowed.
- Next.js 15 & Promise Handling: This project uses the latest Next.js 15. As per the new architecture, dynamic route parameters (
params) are treated as Promises. The code explicitly awaits these params in both API routes and UI components to ensure stable rendering. - Server-Side Logic: All sensitive logic (checking expiry, incrementing views) is handled securely on the server (API Routes) before returning data to the client.
- Time Travel Logic: A custom helper (
lib/time.ts) injects thex-test-now-mstime into the expiry check only whenTEST_MODE=1is set. This separates test logic from production logic while meeting the assignment's grading requirements.
- GET
/api/healthz - Returns:
200 OK{ "ok": true }if the database is connected.
- POST
/api/pastes - Body:
{ "content": "Hello World", "ttl_seconds": 60, // Optional "max_views": 5 // Optional } - Returns:
{ "id": "...", "url": "..." }
- GET
/api/pastes/:id - Returns: Paste content and metadata.
- Errors: Returns
404if the paste is expired or the view limit is exceeded.
├── app/
│ ├── api/ # Backend API Routes
│ ├── p/[id]/ # View Paste Page (Dynamic Route)
│ └── page.tsx # Create Paste Page (Home)
├── lib/
│ ├── db.ts # MongoDB Connection Helper
│ └── time.ts # Deterministic Time Helper
├── models/
│ └── Paste.ts # Mongoose Data Schema
└── public/