Spring Boot REST API for the Smart University Companion (L3 Individual Project, University of Moratuwa). Provides auth, Lost & Found, Financial Aid, Notifications, Emergency alerts, Achievements, an AI chatbot (Google Gemini), weather chat, Stripe payments, and AWS S3 image/file storage.
- Live API:
https://athena001-535225bb557e.herokuapp.com - Frontend: https://athena.rothila.com (Netlify)
| Area | Technology |
|---|---|
| Language / Framework | Java 17, Spring Boot 3.2, Maven |
| Security | Spring Security 6, JWT (io.jsonwebtoken 0.11.5), BCrypt |
| Database | PostgreSQL 15+, Spring Data JPA / Hibernate 6, HikariCP |
| Storage | AWS S3 (AWS SDK) |
| Realtime | Spring WebSocket + STOMP (in-memory broker) |
| AI Chatbot | Google Gemini (generateContent), default gemini-3.5-flash |
| Other | Stripe (payments), Spring Mail (Brevo SMTP), Apache PDFBox, SpringDoc/OpenAPI 3 |
All protected routes require Authorization: Bearer <jwt>. userId is derived from the JWT, not request bodies.
| Method | Path | Notes |
|---|---|---|
| POST | /signin |
{ email, password } β { token, type, id, email } |
| POST | /signup |
{ email, password, ... } β email verification sent |
| POST | /verify-email |
{ email, code } |
| POST | /resend-verification |
{ email } |
| POST | /oauth/register |
Google OAuth register/login bridge |
| POST | /forgot-password / /reset-password |
OTP-based reset |
| Method | Path | Notes |
|---|---|---|
| GET | /items |
Filters: type, category, location, search, status |
| GET | /items/{id} |
Single item |
| POST | /items |
Create (body below) |
| PUT | /items/{id} |
Update |
| DELETE | /items/{id} |
Delete |
| PUT | /items/{id}/status?status=RESOLVED |
Status change |
| GET | /items/user/{userId} |
A user's items |
| GET | /stats |
Counts, categories, locations |
| Method | Path | Notes |
|---|---|---|
| POST | /image |
multipart/form-data file β { imageUrl } |
| GET | /image/serve?url=<s3Url> |
Backend proxy β binary image |
| DELETE | /image?imageUrl=<s3Url> |
Delete from S3 |
GET /dashboard/stats Β· GET /users?page&size Β· GET|PUT|DELETE /users/{id} Β· PATCH /users/{id}/toggle-status Β· PATCH /users/{id}/reset-password Β· POST /users/bulk-action
GET /applications?status&type Β· GET /applications/{id} Β· GET /applications/user/{userId} Β· POST /applications Β· PUT /applications/{id} Β· DELETE /applications/{id} Β· GET /stats Β· GET /donations (public)
Admin: POST /admin/financial-aid/applications/{id}/review Β· GET /admin/financial-aid/applications?page&size
GET /user/{userId}?page&size Β· GET /user/{userId}/unread/count Β· PUT /{id}/read Β· PUT /user/{userId}/read-all Β· DELETE /{id} Β· DELETE /user/{userId}/read Β· POST / (admin)
GET /approved (public feed) Β· GET /pending/{adminId} Β· GET /student/{studentId} Β· POST / Β· PUT /{id}/approve/{adminId} Β· PUT /{id}/reject/{adminId} Β· POST /{id}/like Β· DELETE /{id}/unlike
| Method | Path | Notes |
|---|---|---|
| GET | / |
List all study zones with real-time computed consensus occupancy |
| POST | /{id}/vote |
Report crowd occupancy (EMPTY, MODERATE, CROWDED) |
| POST | /admin/study-spaces |
Admin: Add a new study zone |
| DELETE | /admin/study-spaces/{id} |
Admin: Delete an existing study zone |
| Method | Path | Notes |
|---|---|---|
| POST | /chat |
{ message, imageUrls?, pdfUrls? } β text + vision + PDF, JWT required |
| POST | /uploads |
Track a chatbot file upload |
| GET | /health |
Public health check |
POST / β { message } (Gemini answer with current weather context).
GET /api/users/profile, GET|PUT|DELETE /api/users/{id} Β· Payments via PaymentController (Stripe) Β· POST /api/setup/init (bootstrap admin) Β· GET /api/health Β· WebSocket: CONNECT /ws, SUBSCRIBE /topic/notifications/{userId}, SEND /app/notifications.
Prerequisites: Java 17+, Maven 3.6+ (or the bundled wrapper), PostgreSQL 12+, AWS account (S3, optional for local).
git clone <repository-url>
cd university-companion-backend
# Run (uses src/main/resources/application.properties; copy from the .template)
./mvnw spring-boot:run # or: mvnw.cmd spring-boot:run (Windows)
# Build / run jar
./mvnw clean package
java -jar target/smart-university-backend-1.0.0.jar
# Verify
curl http://localhost:8080/api/health # {"status":"UP", ...}Local DB with Docker:
docker run --name postgres-university -e POSTGRES_DB=smart_university_db \
-e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=<password> -p 5433:5432 -d postgres:15application.properties and application-local.properties are gitignored (hold secrets). Every value reads from an env var with a sensible default β ${VAR:default}. Key settings:
server.port=8080
spring.datasource.url=${DATABASE_URL:jdbc:postgresql://localhost:5432/smart_campus_db}
spring.datasource.username=${DB_USERNAME:postgres}
spring.datasource.password=${DB_PASSWORD:postgres}
spring.jpa.hibernate.ddl-auto=validate # local profile overrides to "update"
jwt.secret=${JWT_SECRET:} # must be >= 256 bits (HS256)
jwt.expiration=${JWT_EXPIRATION:86400}
aws.access-key-id=${AWS_ACCESS_KEY_ID:}
aws.secret-access-key=${AWS_SECRET_ACCESS_KEY:}
aws.region=${AWS_REGION:us-east-1}
aws.s3.bucket-name=${AWS_S3_BUCKET:thirdyearproject}
# AI chatbot (active provider = Gemini)
gemini.api.key=${GEMINI_API_KEY:}
gemini.api.model=${GEMINI_API_MODEL:gemini-3.5-flash}
gemini.api.base-url=${GEMINI_API_BASE_URL:https://generativelanguage.googleapis.com/v1beta}
gemini.api.thinking-budget=${GEMINI_THINKING_BUDGET:0} # 0 = no thinking (flash); -1 = model decides (pro)
# Kimi/Moonshot config remains but is legacy/unwired
weather.api.key=${WEATHER_API_KEY:}
stripe.secret-key=${STRIPE_SECRET_KEY:}
stripe.webhook-secret=${STRIPE_WEBHOOK_SECRET:}
spring.mail.* (Brevo SMTP) app.mail.from=${MAIL_FROM:noreply@athena.rothila.com}Profiles: default (base application.properties), local (Neon Postgres + ddl-auto=update), heroku (production).
src/main/java/com/smartuniversity/
βββ SmartUniversityApplication.java
βββ config/ # SecurityConfig (JWT, CORS), PaymentConfig (Stripe), ...
βββ controller/ # Auth, Admin, LostFound, ImageUpload, FinancialAid(+Admin),
β # Notification, Emergency, Achievement, GeneralChatbot,
β # WeatherChat, ChatbotUpload, Payment, User, Setup, Health
βββ dto/ # Request/response payloads
βββ model/ # JPA entities (User, LostFoundItem, FinancialAid, Notification,
β # StudentAchievement, ChatbotUpload, TokenTransaction, ...)
βββ repository/ # Spring Data JPA repositories
βββ security/ # JwtUtils, JwtAuthenticationFilter
βββ service/ # GeminiChatService (active), KimiChatService (legacy), S3Service,
β # TokenService, WeatherService, PaymentService, ...
βββ util/ # AuthUtils (current user from JWT)
src/main/resources/ # application[-local|-heroku].properties (+ .template)
Production runs with SPRING_PROFILES_ACTIVE=heroku. Build is auto-detected (Java/Maven).
- Procfile:
web: java -Dserver.port=$PORT -Dspring.profiles.active=heroku -jar target/*.jar - system.properties:
java.runtime.version=17 - Required config vars:
DATABASE_URL,JWT_SECRET,CORS_ALLOWED_ORIGINS,AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_REGION,AWS_S3_BUCKET,GEMINI_API_KEY,WEATHER_API_KEY,STRIPE_SECRET_KEY,MAIL_FROM, SMTP creds,SPRING_PROFILES_ACTIVE=heroku.
heroku logs --tail --app athena001
curl https://athena001-535225bb557e.herokuapp.com/api/health- Won't start / port 8080 busy:
netstat -ano | findstr :8080thentaskkill /PID <pid> /F(Win) Β·lsof -ti:8080 | xargs kill -9(Unix). - JWT errors:
JWT_SECRETmust be set and β₯ 256 bits, orKeys.hmacShaKeyForthrows. - DB connection:
psql -h localhost -p 5433 -U postgres -d smart_university_db; check the URL/credentials match your profile. - S3 upload fails: verify AWS keys and bucket;
aws s3 ls s3://<bucket>. - CORS: ensure the frontend origin is in
CORS_ALLOWED_ORIGINS.
Developed for academic coursework at the University of Moratuwa. π