{"id":50960613,"url":"https://github.com/deepakdnayak/peer-awards-backend","last_synced_at":"2026-06-18T13:32:37.842Z","repository":{"id":351095976,"uuid":"1184487990","full_name":"deepakdnayak/peer-awards-backend","owner":"deepakdnayak","description":"A three-phase backend for a CS \u0026 Design farewell awards platform managing title crowdsourcing, voting, and winner announcements for 62 students.","archived":false,"fork":false,"pushed_at":"2026-04-13T15:09:52.000Z","size":74,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-13T16:32:13.450Z","etag":null,"topics":["express-js","git","github","mongodb","mongoose","nodejs","postman-api"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/deepakdnayak.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-17T16:27:42.000Z","updated_at":"2026-04-13T15:09:56.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/deepakdnayak/peer-awards-backend","commit_stats":null,"previous_names":["deepakdnayak/peer-awards-backend"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/deepakdnayak/peer-awards-backend","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepakdnayak%2Fpeer-awards-backend","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepakdnayak%2Fpeer-awards-backend/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepakdnayak%2Fpeer-awards-backend/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepakdnayak%2Fpeer-awards-backend/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/deepakdnayak","download_url":"https://codeload.github.com/deepakdnayak/peer-awards-backend/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepakdnayak%2Fpeer-awards-backend/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34493361,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-18T02:00:06.871Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["express-js","git","github","mongodb","mongoose","nodejs","postman-api"],"created_at":"2026-06-18T13:32:37.719Z","updated_at":"2026-06-18T13:32:37.820Z","avatar_url":"https://github.com/deepakdnayak.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🏆 CSD Peer Awards 2026 — Backend\n\n\u003e A production-grade peer voting and awards system built for the Computer Science \u0026 Design department's farewell batch of 2026. This backend powers a three-phase class awards platform — from title crowdsourcing to final winner announcement — for approximately 62 students.\n\n---\n\n## 📌 Table of Contents\n\n- [Overview](#overview)\n- [User Roles](#user-roles)\n- [System Phases](#system-phases)\n- [Tech Stack](#tech-stack)\n- [Tools \u0026 Platforms](#tools--platforms)\n- [Project Structure](#project-structure)\n- [Database Collections](#database-collections)\n- [Authentication Flow](#authentication-flow)\n- [API Endpoints](#api-endpoints)\n- [Health Check](#health-check)\n- [Getting Started](#getting-started)\n- [Environment Variables](#environment-variables)\n- [Scripts](#scripts)\n\n---\n\n## Overview\n\n**CSD Peer Awards 2026** is a full-stack web application designed to let a graduating engineering class crowdsource award titles, nominate classmates, and vote for winners — all in a controlled, authenticated environment. The backend is built with **Node.js**, **Express.js**, and **TypeScript**, connected to a **MongoDB Atlas** cloud database.\n\nThe system is designed for exactly **~62 users** and is not intended for public access. All users are pre-seeded by the admin via a CSV upload — no public registration is permitted.\n\n---\n\n## 👥 User Roles\n\nThe system has two distinct user types:\n\n### 🎓 Student\n- Authenticated via USN + OTP (sent to official college email)\n- Can suggest award titles\n- Can upvote or downvote suggested titles (once per title)\n- Can nominate one classmate per title (including self-nomination)\n- Can update their nomination for a title\n- Can vote for one finalist per title during final voting\n\n### 🛡️ Admin (You)\n- Full control over the system\n- Seeds users via CSV upload\n- Approves or rejects suggested titles\n- Creates, edits, and soft-deletes titles manually\n- Views all nominations and top nominees per title\n- Freezes/finalises nominees before final voting begins\n- Manages system phase (controls which phase is active)\n- Has access to a dedicated admin dashboard API\n\n---\n\n## 🔄 System Phases\n\nThe application operates in **three sequential phases**, controlled by the admin via the `system_config` collection:\n\n### Phase 1 — Title Creation 🏷️\n\u003e Students suggest award categories. Other students upvote or downvote submissions. The admin reviews and approves titles before they go live.\n\n- Students submit title suggestions (e.g., *\"Funniest Person\"*, *\"Silent Killer\"*, *\"Most Likely to be CEO\"*)\n- Duplicate titles (case-insensitive) are rejected at the API level\n- Titles remain in `pending` status until admin approves them\n- Only `approved` + `isActive: true` titles appear on the public listing\n- Admin can reject, update, or soft-delete any title at any time\n\n### Phase 2 — Nominations 🗳️\n\u003e Students nominate one classmate per approved title. The system aggregates nominations and the admin can view the top 6 nominees per title.\n\n- One nomination per user per title (enforced by unique DB index)\n- Self-nomination is allowed\n- Users can update their nominee for a title at any time during this phase\n- Admin can view a fully populated leaderboard of top 6 nominees per title\n- Admin finalises nominees to lock the phase and prepare for final voting\n\n### Phase 3 — Final Voting 🏅\n\u003e Students vote for one finalist per title. After the deadline, the admin reveals results.\n\n- Only the top 6 shortlisted nominees per title are eligible\n- One vote per user per title (enforced by unique DB index)\n- Votes are locked after submission (no editing)\n- After voting closes, the admin triggers result announcement\n\n### Phase 4 — Results Announcement 🎉\n\u003e Winners are publicly displayed with vote counts and rankings.\n\n---\n\n## 🛠️ Tech Stack\n\n| Layer | Technology |\n|---|---|\n| Runtime | Node.js |\n| Framework | Express.js |\n| Language | TypeScript |\n| Database | MongoDB Atlas |\n| ODM | Mongoose |\n| Authentication | JWT (JSON Web Tokens) |\n| OTP Delivery | Nodemailer + Gmail SMTP |\n| File Uploads | Multer |\n| CSV Parsing | csv-parser |\n\n---\n\n## 🧰 Tools \u0026 Platforms\n\n| Tool | Purpose |\n|---|---|\n| **Visual Studio Code** | Primary code editor |\n| **Postman** | API testing and documentation |\n| **MongoDB Atlas** | Cloud-hosted database |\n| **Git** | Version control |\n| **GitHub** | Remote repository and code storage |\n| **Railway / Render** | Backend hosting (free tier) |\n| **Vercel** | Frontend hosting (Next.js) |\n\n---\n\n## 📁 Project Structure\n\n```\nbackend/\n│\n├── src/\n│   ├── config/\n│   │   └── db.ts                    # MongoDB connection setup\n│   │\n│   ├── modules/\n│   │   ├── auth/\n│   │   │   ├── auth.controller.ts   # OTP send/verify, get current user\n│   │   │   ├── auth.service.ts      # Core auth logic\n│   │   │   └── auth.routes.ts       # Auth route definitions\n│   │   │\n│   │   ├── final/\n│   │   │   ├── finalNominee.model.ts # Final Nominee schema\n│   │   │   ├── result.model.ts       # Final Result schema\n│   │   │   ├── vote.model.ts         # Vote schema\n│   │   │   ├── final.service.ts      # Final Service logic\n│   │   │   ├── final.controller.ts   # Final Route handler\n│   │   │   └── final.routes.ts       # Final routes\n│   │   ├── user/\n│   │   │   ├── user.model.ts        # Mongoose user schema\n│   │   │   ├── user.service.ts      # CSV processing logic\n│   │   │   ├── user.controller.ts   # CSV upload handler\n│   │   │   └── user.routes.ts       # Admin user routes\n│   │   │\n│   │   ├── title/\n│   │   │   ├── title.model.ts       # Title schema\n│   │   │   ├── titleVote.model.ts   # Upvote/downvote schema\n│   │   │   ├── title.service.ts     # Title business logic\n│   │   │   ├── title.controller.ts  # Title request handlers\n│   │   │   └── title.routes.ts      # Title routes (student + admin)\n│   │   │\n│   │   └── nomination/\n│   │       ├── nomination.model.ts  # Nomination schema\n│   │       ├── nomination.service.ts# Nomination logic + aggregation\n│   │       ├── nomination.controller.ts\n│   │       └── nomination.routes.ts\n│   │\n│   ├── models/\n│   │   └── otp.model.ts             # OTP session schema\n│   │\n│   ├── middlewares/\n│   │   ├── auth.middleware.ts        # JWT verification\n│   │   └── admin.middleware.ts       # Role-based access guard\n│   │\n│   ├── utils/\n│   │   ├── otp.ts                   # OTP generator (6-digit)\n│   │   └── mailer.ts                # Nodemailer + Gmail SMTP\n│   │\n│   ├── app.ts                        # Express app + route mounting\n│   └── server.ts                     # Entry point, DB connect, listen\n│\n├── uploads/                          # Temporary CSV storage (multer)\n├── .env                              # Environment variables (not committed)\n├── .gitignore\n├── package.json\n└── tsconfig.json\n```\n\n---\n\n## 🗄️ Database Collections\n\n| Collection | Purpose |\n|---|---|\n| `users` | All students and admin (pre-seeded) |\n| `otps` | Temporary OTP sessions with expiry |\n| `titles` | Award category suggestions |\n| `titlevotes` | Upvote / downvote records per title |\n| `nominations` | Nomination records (1 per user per title) |\n| `finalvotes` | Final voting records (Phase 3) |\n| `system_config` | Current phase and global app settings |\n\n---\n\n## 🔐 Authentication Flow\n\nThis system uses **OTP-based authentication** — no passwords, no registration.\n\n```\nStep 1: Student enters their University Seat Number (USN)\n         ↓\nStep 2: Backend finds the user in the pre-seeded database\n         ↓\nStep 3: A 6-digit OTP is generated and emailed to their official college email\n         ↓ (Email is partially masked in the response, e.g. \"deepa***@college.edu\")\nStep 4: Student enters the OTP\n         ↓\nStep 5: Backend validates OTP (5-minute expiry window)\n         ↓\nStep 6: JWT token issued → used for all subsequent authenticated requests\n```\n\n\u003e **Why this approach?** It prevents impersonation (no one can guess another's OTP), eliminates password management, and leverages the college's official email infrastructure for identity verification.\n\n---\n\n## 📡 API Endpoints\n\nFew endpoints prefixed with `/api`.\n\n---\n\n### 🏥 Health Check — `/`\n\n| Method | Endpoint | Auth | Description |\n|---|---|---|---|\n| `GET` | `/` | ❌ Public | Server health status and system information |\n\n**Response:**\n```json\n{\n  \"status\": \"healthy\",\n  \"timestamp\": \"2026-04-13T20:23:12.000Z\",\n  \"uptime\": 123.456,\n  \"server\": {\n    \"nodeVersion\": \"v18.17.0\",\n    \"platform\": \"win32\",\n    \"architecture\": \"x64\",\n    \"memoryUsage\": {\n      \"rss\": \"45 MB\",\n      \"heapTotal\": \"32 MB\",\n      \"heapUsed\": \"28 MB\"\n    }\n  },\n  \"database\": {\n    \"status\": \"connected\",\n    \"collections\": [\"users\", \"titles\", \"nominations\", \"votes\", \"results\", \"otps\", \"systemconfigs\"]\n  },\n  \"system\": {\n    \"currentPhase\": \"final_voting\",\n    \"isVotingOpen\": true\n  },\n  \"api\": {\n    \"version\": \"1.0.0\",\n    \"baseUrl\": \"/api\",\n    \"endpoints\": [\"/api/auth\", \"/api/user\", \"/api/titles\", \"/api/nominations\", \"/api/final\"]\n  }\n}\n```\n\n---\n\n### 🔐 Auth — `/api/auth`\n\n| Method | Endpoint | Auth | Description |\n|---|---|---|---|\n| `POST` | `/auth/send-otp` | ❌ Public | Enter USN → receive OTP on official email |\n| `POST` | `/auth/verify-otp` | ❌ Public | Submit OTP → receive JWT token |\n| `GET` | `/auth/me` | ✅ Student | Get current logged-in user details |\n\n**Example — Send OTP:**\n```json\nPOST /api/auth/send-otp\n{\n  \"usn\": \"4XX21CS001\"\n}\n```\n\n**Example — Verify OTP:**\n```json\nPOST /api/auth/verify-otp\n{\n  \"usn\": \"4XX21CS001\",\n  \"otp\": \"482910\"\n}\n```\n\n---\n\n### 👤 Users (Admin) — `/api/admin`\n\n| Method | Endpoint | Auth | Description |\n|---|---|---|---|\n| `POST` | `/admin/upload-users` | ✅ Admin | Upload CSV to seed or add new students |\n\n**CSV Format:**\n```csv\nname,usn,email\nDeepak Nayak,4XX21CS001,deepak@college.edu\nKarthik Rao,4XX21CS002,karthik@college.edu\nAnanya Shetty,4XX21CS003,ananya@college.edu\n```\n\n\u003e Re-uploading a CSV will **only add new users**. Existing users (matched by USN) are skipped. No data is lost. Permanent deletion is a separate admin action.\n\n---\n\n### 🏷️ Titles — `/api/titles`\n\n| Method | Endpoint | Auth | Description |\n|---|---|---|---|\n| `POST` | `/titles` | ✅ Student | Suggest a new award title |\n| `GET` | `/titles` | ❌ Public | Get all approved + active titles |\n| `POST` | `/titles/vote` | ✅ Student | Upvote or downvote a title |\n| `GET` | `/titles/admin/all` | ✅ Admin | Get all titles (pending, approved, rejected) |\n| `PATCH` | `/titles/admin/approve/:id` | ✅ Admin | Approve a pending title |\n| `PUT` | `/titles/admin/:id` | ✅ Admin | Update title name or description |\n| `DELETE` | `/titles/admin/:id` | ✅ Admin | Soft-delete a title (sets `isActive: false`) |\n\n**Example — Create Title:**\n```json\nPOST /api/titles\nAuthorization: Bearer \u003ctoken\u003e\n{\n  \"titleName\": \"Funniest Person\",\n  \"description\": \"The one who keeps the whole class laughing\"\n}\n```\n\n**Example — Vote:**\n```json\nPOST /api/titles/vote\nAuthorization: Bearer \u003ctoken\u003e\n{\n  \"titleId\": \"665f3abc...\",\n  \"voteType\": \"upvote\"\n}\n```\n\n\u003e Duplicate title names are rejected (case-insensitive, whitespace-trimmed). Users can change their vote type (upvote ↔ downvote) but cannot vote twice.\n\n---\n\n### 🗳️ Nominations — `/api/nominations`\n\n| Method | Endpoint | Auth | Description |\n|---|---|---|---|\n| `POST` | `/nominations` | ✅ Student | Nominate a classmate for an approved title |\n| `PUT` | `/nominations` | ✅ Student | Update your existing nomination for a title |\n| `GET` | `/nominations/me` | ✅ Student | View all your nominations (populated) |\n| `GET` | `/nominations/admin/top` | ✅ Admin | View top 6 nominees per title (populated) |\n\n**Example — Nominate:**\n```json\nPOST /api/nominations\nAuthorization: Bearer \u003ctoken\u003e\n{\n  \"titleId\": \"665f3abc...\",\n  \"nomineeId\": \"665f1xyz...\"\n}\n```\n\n**Example — Admin Top Nominees Response:**\n```json\n[\n  {\n    \"titleId\": \"665f3abc...\",\n    \"title\": { \"titleName\": \"Funniest Person\" },\n    \"topNominees\": [\n      { \"count\": 18, \"user\": { \"name\": \"Deepak Nayak\", \"usn\": \"4XX21CS001\" } },\n      { \"count\": 15, \"user\": { \"name\": \"Karthik Rao\", \"usn\": \"4XX21CS002\" } }\n    ]\n  }\n]\n```\n\n---\n\n## 🏥 Health Check\n\nThe root endpoint (`/`) provides comprehensive server health information including:\n\n- **Server Status**: Node.js version, platform, memory usage\n- **Database Status**: MongoDB connection and available collections\n- **System State**: Current phase and voting status\n- **API Information**: Version and available endpoints\n\n**Usage:**\n```bash\ncurl http://localhost:5000/\n```\n\n**Response (Healthy):**\n```json\n{\n  \"status\": \"healthy\",\n  \"timestamp\": \"2026-04-13T20:23:12.000Z\",\n  \"uptime\": 123.456,\n  \"server\": {\n    \"nodeVersion\": \"v18.17.0\",\n    \"platform\": \"win32\",\n    \"architecture\": \"x64\",\n    \"memoryUsage\": {\n      \"rss\": \"45 MB\",\n      \"heapTotal\": \"32 MB\",\n      \"heapUsed\": \"28 MB\"\n    }\n  },\n  \"database\": {\n    \"status\": \"connected\",\n    \"collections\": [\"users\", \"titles\", \"nominations\", \"votes\", \"results\", \"otps\", \"systemconfigs\"]\n  },\n  \"system\": {\n    \"currentPhase\": \"final_voting\",\n    \"isVotingOpen\": true\n  },\n  \"api\": {\n    \"version\": \"1.0.0\",\n    \"baseUrl\": \"/api\",\n    \"endpoints\": [\"/api/auth\", \"/api/user\", \"/api/titles\", \"/api/nominations\", \"/api/final\"]\n  }\n}\n```\n\n**Response (Unhealthy - Database Issue):**\n```json\n{\n  \"status\": \"unhealthy\",\n  \"timestamp\": \"2026-04-13T20:23:12.000Z\",\n  \"error\": \"Database connection failed\",\n  \"uptime\": 123.456\n}\n```\n\n---\n\n## 🚀 Getting Started\n\n### Prerequisites\n- Node.js v18+\n- npm\n- A MongoDB Atlas cluster\n- A Gmail account with [App Password](https://myaccount.google.com/apppasswords) enabled\n\n### Installation\n\n```bash\n# Clone the repository\ngit clone https://github.com/your-username/csd-peer-awards-2026-backend.git\ncd csd-peer-awards-2026-backend\n\n# Install dependencies\nnpm install\n\n# Create your environment file\ncp .env.example .env\n# Fill in values (see Environment Variables section)\n\n# Start development server\nnpm run dev\n```\n\n---\n\n## 🔑 Environment Variables\n\nCreate a `.env` file in the root directory:\n\n```env\nPORT=5000\nMONGO_URI=mongodb+srv://\u003cusername\u003e:\u003cpassword\u003e@cluster0.mongodb.net/csd-awards\nJWT_SECRET=your_super_secret_key_here\n\n# Email Configuration (for OTP sending)\nEMAIL_SERVICE=gmail\nEMAIL_USER=your_email@gmail.com\nEMAIL_PASSWORD=your_app_specific_password\n```\n\n### Email Setup Instructions\n\n**For Gmail:**\n1. Enable 2-Step Verification on your Google Account\n2. Generate an **App Password** at https://myaccount.google.com/apppasswords\n3. Use the generated 16-character password as `EMAIL_PASSWORD`\n4. Set `EMAIL_SERVICE=gmail`\n\n**For other email providers:**\n- Set `EMAIL_SERVICE` to your provider (e.g., `outlook`, `yahoo`, `sendgrid`)\n- Or configure custom SMTP in `src/utils/mailer.ts`\n\n\u003e ⚠️ **Never commit your `.env` file.** It is listed in `.gitignore`.\n\n---\n\n## 📜 Scripts\n\n```bash\n# Start development server with hot reload\nnpm run dev\n\n# Build TypeScript to JavaScript\nnpm run build\n\n# Start production server\nnpm start\n```\n\n---\n\n## 📬 Testing with Postman\n\n1. Import all endpoints into a Postman Collection\n2. Set a collection variable: `BASE_URL = http://localhost:5000`\n3. After login, set: `TOKEN = \u003cjwt from verify-otp response\u003e`\n4. Use `Authorization: Bearer {{TOKEN}}` header on protected routes\n\n\u003e Recommended test order: Upload CSV → Send OTP → Verify OTP → Create Title → Admin Approve → Vote → Nominate → Admin view Top Nominees\n\n---\n\n## 🔒 Security Notes\n\n- **OTP Security**: OTPs are hashed using bcrypt before storage and never stored in plain text\n- **OTP Expiration**: OTPs expire after **5 minutes** and are automatically deleted after verification\n- **JWT Security**: JWTs expire after **1 day**\n- **Admin Protection**: All admin routes are protected by both `authMiddleware` and `adminMiddleware`\n- **Vote/Nomination Integrity**: Duplicate votes and nominations are prevented at both application and database index level\n- **Data Auditability**: Titles are soft-deleted (not permanently removed) to preserve audit integrity\n- **Email Validation**: OTPs are sent only to registered user emails via secure SMTP\n\n---\n\n## 🗂️ Version Control\n\n- **Git** is used for local version control\n- **GitHub** is used as the remote repository\n- Recommended branch strategy: `main` (production) + `dev` (active development)\n\n```bash\ngit add .\ngit commit -m \"feat: add nomination phase APIs\"\ngit push origin dev\n```\n\n---\n\n## 👨‍💻 Author\n\nBuilt with ❤️ for the CSD Batch of 2026 Farewell  \nDepartment of Computer Science \u0026 Design  \n\n---\n\n*This project is private and intended for internal use by ~62 registered users only.*","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeepakdnayak%2Fpeer-awards-backend","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdeepakdnayak%2Fpeer-awards-backend","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeepakdnayak%2Fpeer-awards-backend/lists"}