{"id":25874498,"url":"https://github.com/apfirebolt/miniurl_mevn","last_synced_at":"2026-04-10T11:02:51.597Z","repository":{"id":280122566,"uuid":"941042762","full_name":"Apfirebolt/miniurl_mevn","owner":"Apfirebolt","description":"A URL shortener created using Node, Vue, MongoDB and Express 🔥","archived":false,"fork":false,"pushed_at":"2025-03-19T18:04:44.000Z","size":879,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-19T19:23:18.144Z","etag":null,"topics":["docker","docker-compose","expressjs","headlessui","mevn-stack","mongodb","mongoose","nginx","tailwindcss","url-shortener","vue3"],"latest_commit_sha":null,"homepage":"","language":"Vue","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Apfirebolt.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-03-01T10:48:52.000Z","updated_at":"2025-03-19T18:04:48.000Z","dependencies_parsed_at":"2025-03-01T12:31:44.650Z","dependency_job_id":null,"html_url":"https://github.com/Apfirebolt/miniurl_mevn","commit_stats":null,"previous_names":["apfirebolt/miniurl_mevn"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Apfirebolt/miniurl_mevn","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Apfirebolt%2Fminiurl_mevn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Apfirebolt%2Fminiurl_mevn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Apfirebolt%2Fminiurl_mevn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Apfirebolt%2Fminiurl_mevn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Apfirebolt","download_url":"https://codeload.github.com/Apfirebolt/miniurl_mevn/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Apfirebolt%2Fminiurl_mevn/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31639524,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T07:40:12.752Z","status":"ssl_error","status_checked_at":"2026-04-10T07:40:11.664Z","response_time":98,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","docker-compose","expressjs","headlessui","mevn-stack","mongodb","mongoose","nginx","tailwindcss","url-shortener","vue3"],"created_at":"2025-03-02T09:28:09.304Z","updated_at":"2026-04-10T11:02:51.592Z","avatar_url":"https://github.com/Apfirebolt.png","language":"Vue","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MEVN URL Shortener with Authentication\n\n![Vue](https://img.shields.io/badge/Vue-green)\n![Express](https://img.shields.io/badge/Express-blue)\n![Docker](https://img.shields.io/badge/Docker-blue)\n![Tailwind CSS](https://img.shields.io/badge/Tailwind_CSS-38B2AC)\n![Headless UI](https://img.shields.io/badge/Headless_UI-4B5563)\n![Docker Compose](https://img.shields.io/badge/Docker_Compose-2496ED)\n![MongoDB](https://img.shields.io/badge/MongoDB-green)\n![Mongoose](https://img.shields.io/badge/Mongoose-red)\n\nThis is a url shortener app for a MEVN stack application with authentication. This is for a SPA (Single Page Application) workflow that uses the [Vite](https://vite.dev) Build tool. This uses cookie based approach for authentication.\n\n## What are URL shortner services?\n\nURL shortener services are tools that take long URLs and convert them into shorter, more manageable links. These services are particularly useful for sharing links on social media, in emails, or in any context where space is limited. Shortened URLs are easier to remember, type, and share. Additionally, many URL shortener services provide analytics to track the number of clicks, geographic location of the clicks, and other useful data.\n\nPopular URL shortener services include Bitly, TinyURL, and Google's now-defunct goo.gl. These services often offer additional features such as custom short links, link expiration, and password protection. URL shorteners can also help in branding by allowing businesses to create custom short domains that reflect their brand identity.\n\nIt includes the following:\n\n- Backend API with Express \u0026 MongoDB\n- Routes for auth, logout, register, profile, update profile\n- JWT authentication stored in HTTP-only cookie\n- Protected routes and endpoints\n- Custom middleware to check JSON web token and store in cookie\n- Custom error middleware\n- Vue frontend to register, login, logout, view profile, and update profile\n- Charts for the links visited using charts.js\n\n## Screenshots\n\nPlease find some of the screenshots of the application. First 2 pages show the dashboard and the charts showing number of clicks.\n\n![Screenshot 1](screenshots/1.png)\n![Screenshot 2](screenshots/2.png)\n![Screenshot 3](screenshots/3.png)\n\nRegister page design\n\n![Screenshot 4](screenshots/4.png)\n\n## Usage\n\n- Create a MongoDB database and obtain your `MongoDB URI` - [MongoDB Atlas](https://www.mongodb.com/cloud/atlas/register)\n\n### Env Variables\n\nRename the `.env.example` file to `.env` and add the following\n\n```\nNODE_ENV = development\nPORT = 5000\nMONGO_URI = your mongodb uri\nJWT_SECRET = 'abc123'\n```\n\nChange the JWT_SECRET to what you want\n\n### Install Dependencies (frontend \u0026 backend)\n\n```\nnpm install\ncd client\nnpm install\n```\n\n### Run\n\n```\n\n# Run frontend (:3000) \u0026 backend (:5000)\nnpm run dev\n\n# Run backend only\nnpm run server\n```\n\n## Build \u0026 Deploy\n\n```\n# Create frontend prod build\ncd frontend\nnpm run build\n```\n\n## Adding Cron Jobs\n\n```\nnpm install node-cron\n```\n\nWrite the script to show all the users of the database connected every minute and run this script inside tha server.js file every minute using node-cron.\n\n```\n// index.js (with ES modules)\nimport dotenv from 'dotenv';\nimport mongoose from 'mongoose';\nimport User from '../models/userModel.js'; // Import the User model\n\ndotenv.config();\n\nasync function connectAndShowUsers() {\n  try {\n    await mongoose.connect(\"mongodb://localhost:27017/mevn_url_shortener\");\n    console.log('MongoDB Connected');\n\n    // Fetch all users\n    const users = await User.find({});\n    console.log('Users:', users);\n\n    // Optionally, process the users:\n    if (users \u0026\u0026 users.length \u003e 0) {\n      users.forEach(user =\u003e {\n        console.log(`Username: ${user.username}, Email: ${user.email}`);\n      });\n    } else {\n        console.log(\"No users found\");\n    }\n\n    // Close the connection (optional, but good practice):\n    await mongoose.disconnect();\n    console.log('MongoDB Disconnected');\n\n  } catch (error) {\n    console.error('Error:', error);\n  }\n}\n\nconnectAndShowUsers();\n\nexport default connectAndShowUsers;\n```\n\nInside the server.js import and use it like this \n\n```\nimport cron from 'node-cron';\nimport connectAndShowUsers from './data/showUsers.js';\n\ncron.schedule('* * * * *', () =\u003e {\n  console.log('Running a task every minute');\n  // This would connect to MongoDb and show all users every minute\n  // connectAndShowUsers();\n});\n```\nThat's it, it should now display all user data every minute on console. This runs independently of the main node server. \n\n## Docker deployment\n\nThe application can be easily deployed using Docker containers. The application uses the following docker compose script to spawn 3 containers, one each for MongoDB, Express and Nginx\n\n```\nversion: '3.8'\nservices:\n  express:\n    build:\n      context: .\n      dockerfile: Dockerfile\n    container_name: express_miniurl\n    ports:\n      - 5000:5000\n    depends_on:\n      - mongo\n\n  mongo:\n    image: mongo\n    container_name: mongo_miniurl\n    restart: unless-stopped\n    volumes:\n      - ./mongo_data:/data/db\n    ports:\n      - '27017:27017'\n\n  nginx:\n    image: nginx\n    container_name: nginx_miniurl\n    restart: unless-stopped\n    ports:\n      - '80:80'\n    volumes:\n      - ./nginx/nginx.conf:/etc/nginx/nginx.conf\n    depends_on:\n      - express\n\nvolumes:\n  mongo_data:\n    external: true\n```\n\nNginx is optional, we use it to proxy all requests coming to port 80 or 443 to port 5000. Using Nginx we can directly deploy the application on a server with Docker installed on it with one single magical command\n\n```\ndocker-compose up\n```\n\nWe use volumes for data persistance if the mongoDB containers are destroyed for some reason.\n\nThat's it for now, if you liked this project consider giving it a star ⭐","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapfirebolt%2Fminiurl_mevn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapfirebolt%2Fminiurl_mevn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapfirebolt%2Fminiurl_mevn/lists"}