Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MerNote

A production-grade notes application built with the MERN stack — containerized with Docker, served behind Nginx with SSL, and deployed on a DigitalOcean droplet.

Create, organize, and manage your personal notes with a clean, responsive interface. Fully authenticated with JWT, rate-limited via Upstash Redis, and ready for real-world use.

Live at: mernote.sandaliranahewa.dev


Features

  • User Authentication — Register, login, password reset via email (Resend), JWT-based sessions
  • Full CRUD Notes — Create, read, update, and delete notes with ease
  • Real-time Search — Find notes instantly as you type
  • Modern UI — TailwindCSS + DaisyUI with dark/light themes (forest & lemonade)
  • Rate Limiting — API protection using Upstash Redis + sliding window algorithm
  • Fully Responsive — Works beautifully on desktop, tablet, and mobile
  • Profile Management — Update username, email, password, and avatar
  • Dockerized — Multi-stage Docker build for small production images
  • Production-ready — Nginx reverse proxy + Let's Encrypt SSL on DigitalOcean

Tech Stack

Frontend

Technology Purpose
React 19 UI library
Vite 8 Build tool & dev server
TailwindCSS 3 Utility-first CSS
DaisyUI 4 TailwindCSS component library
React Router 7 Client-side routing
Axios HTTP client for API calls
Lucide React Icon set
react-hot-toast Toast notifications

Backend

Technology Purpose
Node.js 20 JavaScript runtime
Express 4 Web framework
MongoDB / Mongoose 8 NoSQL database & ODM
JWT Authentication tokens
bcrypt Password hashing
Upstash Redis + Ratelimit Serverless rate limiting
Resend Transactional emails (password reset)
Nodemon Dev auto-restart

Infrastructure & DevOps

Technology Purpose
Docker Containerization
Docker Compose Multi-service orchestration
Nginx Reverse proxy (production)
Let's Encrypt / Certbot Free SSL certificates
DigitalOcean Cloud hosting
name.com Domain & DNS management

Architecture

flowchart LR
    A["User Browser"] -->|"HTTPS (443)"| B["Nginx Reverse Proxy"]
    B -->|"HTTP (5001)"| C["Docker Container<br/>(mern-app)"]
    C --> D["Express API Server"]
    D --> E["MongoDB Atlas"]
    D --> F["Upstash Redis"]
    
    G["name.com DNS"] -->|"A Record"| H["DigitalOcean Droplet"]
    H --> B

    subgraph "DigitalOcean Droplet"
        B
        C
    end

    style A fill:#4a9eff,stroke:#333,color:#fff
    style B fill:#009639,stroke:#333,color:#fff
    style C fill:#2496ed,stroke:#333,color:#fff
    style D fill:#68a063,stroke:#333,color:#fff
    style E fill:#4DB33D,stroke:#333,color:#fff
    style F fill:#000000,stroke:#333,color:#fff
    style G fill:#ff6600,stroke:#333,color:#fff
    style H fill:#0060ff,stroke:#333,color:#fff
Loading

Request flow:

  1. User visits https://mernote.sandaliranahewa.dev
  2. DNS (name.com) resolves to the DigitalOcean droplet IP
  3. Nginx terminates SSL and proxies requests to the Docker container on port 5001
  4. Express serves the React SPA (built static files) or handles API routes (/api/*)
  5. API server reads/writes to MongoDB Atlas (notes, users) and Upstash Redis (rate limiting)

Prerequisites

  • Node.js v18+ (for local development)
  • npm or yarn
  • MongoDB Atlas cluster (free tier works)
  • Upstash Redis database (free tier works)
  • Docker (for containerized deployment)
  • Domain (for production — name.com or any registrar)

Quick Start — Local Development

1. Clone & Install

git clone https://github.com/sandaliz/MerNote.git
cd MerNote

# Install all dependencies (root + frontend + backend)
npm install
npm install --prefix frontend
npm install --prefix backend

2. Environment Variables

Copy the example env file and fill in your values:

cp .env.example .env

.env (root):

# MongoDB (required)
MONGO_URI=mongodb+srv://<username>:<password>@cluster0.xxxxx.mongodb.net/mern-1st?retryWrites=true&w=majority

# JWT Secret (required — generate with: openssl rand -base64 32)
JWT_SECRET=your-very-long-random-secret-here

# Upstash Redis (required for rate limiting)
UPSTASH_REDIS_REST_URL=https://<your-id>.upstash.io
UPSTASH_REDIS_REST_TOKEN=your-upstash-token

# Port (optional, defaults to 5001)
PORT=5001

# Resend API Key (required for password reset emails)
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxxxxxx

Never commit .env to Git. It's already in .gitignore.

3. Run the App

# Start both frontend & backend concurrently (recommended)
npm run dev

This uses concurrently to run:

  • Backendhttp://localhost:5001 (with nodemon hot-reload)
  • Frontendhttp://localhost:5173 (with Vite HMR, proxies /api to backend)

Or run them in separate terminals:

# Terminal 1 — Backend
cd backend && npm run dev

# Terminal 2 — Frontend
cd frontend && npm run dev

Docker Setup

Build & Run Locally

# Build the Docker image
docker compose build

# Start the container in detached mode
docker compose up -d

# View logs
docker compose logs -f

# Visit: http://localhost:5001

The multi-stage Dockerfile:

  1. Stage 1 — Builds the React frontend with Vite
  2. Stage 2 — Installs production backend dependencies
  3. Final stage — Copies both into a minimal node:20-alpine image

To stop:

docker compose down

Production Deployment

The app is live at https://mernote.sandaliranahewa.dev — deployed with Docker on a DigitalOcean droplet with Nginx as a reverse proxy and Let's Encrypt SSL.

  1. Create a DigitalOcean Droplet (Ubuntu 22.04/24.04)
  2. Install Docker on the droplet
  3. Clone the repo and create a .env with production values
  4. Run with Docker Compose: docker compose up -d
  5. Install Nginx as a reverse proxy
  6. Set up SSL with Certbot / Let's Encrypt
  7. Configure DNS (A record → droplet IP)
  8. Verify at https://mernote.sandaliranahewa.dev

The app is served over HTTPS only — HTTP redirects automatically.

Project Structure

MerNote/
├── backend/
│   ├── src/
│   │   ├── config/
│   │   │   └── db.js              # MongoDB connection
│   │   ├── controllers/
│   │   │   ├── authController.js  # Auth logic (register, login, forgot/reset password)
│   │   │   ├── notesController.js # CRUD operations for notes
│   │   │   └── profileController.js # Profile management
│   │   ├── middleware/
│   │   │   ├── authMiddleware.js   # JWT verification
│   │   │   ├── rateLimiter.js      # Upstash Redis rate limiting
│   │   │   └── validate.js         # Request validation
│   │   ├── models/
│   │   │   ├── userModel.js        # User schema
│   │   │   └── noteModel.js        # Note schema
│   │   ├── routes/
│   │   │   ├── authRoutes.js       # /api/auth/*
│   │   │   ├── notesRoutes.js      # /api/notes/*
│   │   │   └── profileRoutes.js    # /api/profile/*
│   │   └── server.js               # Express entry point
│   └── package.json
│
├── frontend/
│   ├── src/
│   │   ├── components/
│   │   │   ├── AuthForm.jsx        # Reusable form wrapper
│   │   │   ├── AuthHeader.jsx      # Auth page header
│   │   │   ├── Footer.jsx          # App footer
│   │   │   ├── Navbar.jsx          # Navigation bar
│   │   │   ├── NoteCard.jsx        # Single note card
│   │   │   ├── NotesNotFound.jsx   # Empty state
│   │   │   └── RateLimitedUI.jsx   # Rate limit error UI
│   │   ├── lib/
│   │   │   ├── axios.js            # Axios instance with interceptors
│   │   │   ├── colorConfig.js      # Theme helpers
│   │   │   └── utils.js            # Utility functions
│   │   ├── pages/
│   │   │   ├── LandingPage.jsx     # Public landing page
│   │   │   ├── LoginPage.jsx       # Login
│   │   │   ├── SignupPage.jsx      # Signup
│   │   │   ├── HomePage.jsx        # Notes dashboard
│   │   │   ├── CreatePage.jsx      # Create note
│   │   │   ├── NoteDetailPage.jsx  # Note detail/edit
│   │   │   ├── ProfilePage.jsx     # Profile settings
│   │   │   ├── ForgotPasswordPage.jsx  # Forgot password
│   │   │   └── ResetPasswordPage.jsx   # Reset password
│   │   ├── App.jsx                 # Root component with routes
│   │   ├── main.jsx                # Vite entry point
│   │   └── index.css               # TailwindCSS imports
│   ├── index.html
│   ├── vite.config.js              # Vite config + API proxy
│   └── tailwind.config.js          # TailwindCSS + DaisyUI themes
│
├── Dockerfile                      # Multi-stage build
├── docker-compose.yml              # Production container config
├── .env.example                    # Environment variable template
└── README.md                       # This file

API Endpoints

Authentication (/api/auth)

Method Endpoint Description
POST /auth/register Create a new account
POST /auth/login Log in and receive JWT
POST /auth/forgot-password Send password reset email
POST /auth/reset-password Reset password with token

Notes (/api/notes)

Method Endpoint Description
GET /notes Get all notes for logged-in user
POST /notes Create a new note
GET /notes/:id Get a single note
PUT /notes/:id Update a note
DELETE /notes/:id Delete a note

Profile (/api/profile)

Method Endpoint Description
GET /profile Get user profile
PUT /profile Update username, email, avatar
PUT /profile/password Change password

Environment Variables

Variable Required Description
MONGO_URI Yes MongoDB connection string (Atlas recommended)
JWT_SECRET Yes Strong random string for token signing
UPSTASH_REDIS_REST_URL Yes Upstash Redis REST endpoint
UPSTASH_REDIS_REST_TOKEN Yes Upstash Redis auth token
PORT No App port (defaults to 5001)
RESEND_API_KEY Yes (for password reset) Resend API key for transactional emails

Security

  • Helmet-style protections via Nginx hardening in production
  • Rate limiting on all API routes via Upstash Redis sliding window
  • Password hashing with bcrypt (cost factor 10+)
  • JWT tokens with expiration and secure HTTP-only handling
  • CORS restricted to known origins in development
  • Docker non-root user for container security
  • DigitalOcean cloud firewall — only ports 22, 80, and 443 open
  • Let's Encrypt SSL — automatic HTTPS with auto-renewal

About

Production-grade notes app with JWT auth, Redis rate limiting, Docker, Nginx, and cloud deployment.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages