- Overview
- Features
- Tech Stack
- Architecture
- Getting Started
- Environment Variables
- Deployment
- API Routes
- Database Schema
- Project Structure
- Contributing
Assignment Portal is a full-stack web application built for university environments. It enables a structured workflow between Admins, Class Representatives (CRs), and Students β covering assignment creation, file submission, deadline management, and real-time class communication.
Built as a first production project, deployed at assignmentportal.live on DigitalOcean with Docker, Nginx, and Let's Encrypt SSL.
- Email-based OTP verification before account activation
- Role-based access control (
ROLE_ADMIN,ROLE_CR,ROLE_STUDENT) PENDING β ACTIVEaccount approval workflow- Forgot password via OTP with 1-minute expiry
- Spring Security session management with CSRF protection
- Async OTP email delivery for zero-latency redirects
- Approve / reject / delete CR registration requests
- View all CRs with expandable student lists per section
- Dashboard stats β total CRs, students, pending requests
- Email-based actions (no userId exposure)
- Register with OTP verification β admin approval flow
- Create assignments with subject code, type (LAB/THEORY), and deadline
- Track submission progress per assignment with progress bar
- Download all student submissions as ZIP
- Extend assignment deadlines
- Edit profile β section/semester changes cascade to all linked students
- Real-time class chat via WebSocket
- View active assignments from their CR
- Submit assignments (file upload to Supabase Storage)
- Track submission status per assignment
- Real-time class chat with classmates
- WebSocket (STOMP over SockJS)
- Auto-scoped chat rooms:
{admission}-{program}-{section}-{semester} - Messages persisted to PostgreSQL
- Loads last 50 messages on panel open
- Unread message badge when panel is closed
- Isolated β only classmates in the same room
| Layer | Technology |
|---|---|
| Language | Java 17 |
| Framework | Spring Boot 3.5.6 |
| Security | Spring Security 6 |
| ORM | Spring Data JPA + Hibernate 6 |
| Database | PostgreSQL 15 |
| File Storage | Supabase Storage |
| Real-time | WebSocket (STOMP + SockJS) |
| Templating | Thymeleaf |
| Spring Mail (Gmail SMTP, async) | |
| Frontend | Bootstrap 5.3, Bootstrap Icons |
| Containerization | Docker + Docker Compose |
| Reverse Proxy | Nginx |
| SSL | Let's Encrypt (Certbot) |
| Hosting | DigitalOcean Droplet |
| Build | Maven |
βββββββββββββββββββββββββββββββββββββββββββββββ
β Internet β
ββββββββββββββββββββ¬βββββββββββββββββββββββββββ
β HTTPS :443
ββββββββββββββββββββΌβββββββββββββββββββββββββββ
β Nginx (Reverse Proxy) β
β SSL Termination + WS Proxy β
ββββββββββββββββββββ¬βββββββββββββββββββββββββββ
β HTTP :8080
ββββββββββββββββββββΌβββββββββββββββββββββββββββ
β Spring Boot Application β
β βββββββββββββββ ββββββββββββββββββββββββ β
β β MVC Layer β β WebSocket (STOMP) β β
β β Thymeleaf β β /topic/chat/{room} β β
β ββββββββ¬βββββββ ββββββββββββ¬ββββββββββββ β
β β β β
β ββββββββΌβββββββββββββββββββββΌββββββββββββ β
β β Service + Repository Layer β β
β ββββββββββββββββββββ¬βββββββββββββββββββββ β
βββββββββββββββββββββββΌββββββββββββββββββββββββ
β
ββββββββββββββββ΄βββββββββββββββ
β β
βββββββββΌβββββββββ βββββββββββΌβββββββββββ
β PostgreSQL 15 β β Supabase Storage β
β (Docker) β β (File Uploads) β
ββββββββββββββββββ ββββββββββββββββββββββ
- Java 17+
- Maven 3.8+
- Docker + Docker Compose
- PostgreSQL 15 (or use Docker)
1. Clone the repository
git clone https://github.com/Junaid-Ashraf-56/Submission_portal.git
cd Submission_portal2. Create src/main/resources/application.properties
spring.application.name=submission_portal
spring.datasource.url=${SPRING_DATASOURCE_URL}
spring.datasource.username=${SPRING_DATASOURCE_USERNAME}
spring.datasource.password=${SPRING_DATASOURCE_PASSWORD}
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.open-in-view=false
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
supabase.url=${SUPABASE_URL}
supabase.key=${SUPABASE_KEY}
supabase.bucket.name=${SUPABASE_BUCKET_NAME}
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.http.client.HttpClientAutoConfiguration
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=${MAIL_USERNAME}
spring.mail.password=${MAIL_PASSWORD}
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
otp.expiry.minutes=13. Create docker-compose.yml with your environment variables (see Environment Variables)
4. Build and run
mvn clean package -DskipTests
docker compose up --build5. Open http://localhost:8080
| Variable | Description |
|---|---|
SPRING_DATASOURCE_URL |
jdbc:postgresql://db:5432/submission_portal |
SPRING_DATASOURCE_USERNAME |
PostgreSQL username |
SPRING_DATASOURCE_PASSWORD |
PostgreSQL password |
SUPABASE_URL |
Supabase project storage URL |
SUPABASE_KEY |
Supabase service role key |
SUPABASE_BUCKET_NAME |
Storage bucket name |
MAIL_USERNAME |
Gmail address for OTP emails |
MAIL_PASSWORD |
Gmail app password (not account password) |
β οΈ Never commitapplication.propertiesordocker-compose.ymlwith real credentials. Both are in.gitignore.
This project is deployed on DigitalOcean using Docker + Nginx + Let's Encrypt.
assignmentportal.live
β DNS (Namecheap A Record)
DigitalOcean Droplet (Ubuntu 22.04)
β Nginx (port 443 β 8080, WebSocket proxy)
Docker Compose
βββ submission_portal_app (Spring Boot)
βββ submission_portal_db (PostgreSQL 15)
# SSH into server
ssh root@YOUR_DROPLET_IP
# Pull latest code
cd /opt/Submission_portal
git pull origin main
# Rebuild and restart
mvn clean package -DskipTests
docker compose down
docker compose up --build -d| Method | Route | Role | Description |
|---|---|---|---|
| GET | / |
Public | Landing page |
| GET/POST | /auth/login |
Public | Login |
| GET/POST | /auth/register |
Public | CR registration |
| GET/POST | /auth/verify-otp |
Public | OTP verification |
| GET | /cr/dashboard |
CR | CR dashboard |
| GET | /cr/manage-students |
CR | Student management |
| POST | /cr/create-assignment |
CR | Create assignment |
| GET | /cr/assignments/{id}/submissions |
CR | View submissions |
| GET | /cr/assignments/{id}/download-all |
CR | Download ZIP |
| GET | /student/dashboard |
Student | Student dashboard |
| POST | /student/assignments/{id}/submit |
Student | Submit assignment |
| GET | /admin/panel |
Admin | Admin dashboard |
| POST | /admin/cr/approve |
Admin | Approve CR |
| POST | /admin/cr/reject |
Admin | Reject CR |
| GET | /chat/{roomId}/history |
Authenticated | Load chat history |
| WS | /ws |
Authenticated | WebSocket endpoint |
users
βββ id (PK)
βββ email (unique)
βββ password (BCrypt)
βββ role (ROLE_ADMIN / ROLE_CR / ROLE_STUDENT)
βββ status (PENDING / ACTIVE)
students
βββ id (PK)
βββ user_id (FK β users)
βββ name, roll_no, gender, phone_number
βββ section, program, semester, admission
βββ university
assignments
βββ assignment_id (PK)
βββ created_by (FK β students)
βββ subject_title, subject_code
βββ assignment_type (LAB / THEORY)
βββ description
βββ end_time
submissions
βββ id (PK)
βββ assignment_id (FK β assignments)
βββ student_id (FK β students)
βββ file_url (Supabase)
βββ submitted_at
chat_messages
βββ id (PK)
βββ room_id (admission-program-section-semester)
βββ sender_name
βββ content
βββ sent_at
src/main/java/com/web/submission_portal/
βββ config/
β βββ SecurityConfig.java
β βββ WebSocketConfig.java
βββ controller/
β βββ AdminController.java
β βββ AuthController.java
β βββ ChatController.java
β βββ CRController.java
β βββ RegistrationController.java
β βββ StudentController.java
βββ entity/
β βββ Assignment.java
β βββ ChatMessage.java
β βββ Student.java
β βββ Submission.java
β βββ User.java
βββ repository/
β βββ ChatMessageRepository.java
β βββ StudentRepository.java
β βββ SubmissionRepository.java
β βββ UserRepository.java
βββ service/
βββ EmailService.java β @Async OTP delivery
βββ OTPGeneratorService.java
βββ PasswordResetService.java
βββ StudentService.java
src/main/resources/
βββ templates/
β βββ admin/, auth/, cr/, student/
βββ static/
βββ css/ (theme.css, cr-dashboard.css, student-dashboard.css)
βββ js/ (cr-chat.js, student-chat.js)
- Fork the repository
- Create a feature branch (
git checkout -b feature/your-feature) - Commit your changes (
git commit -m 'Add some feature') - Push to the branch (
git push origin feature/your-feature) - Open a Pull Request
Junaid Ashraf
- GitHub: @Junaid-Ashraf-56
- Live Project: assignmentportal.live
β Star this repo if you found it helpful!