A full‑stack music app: Spring Boot backend + two React frontends (Admin and User).
- Backend: Spring Boot 3 (Java 21), MongoDB, JWT, Cloudinary
- Admin app: React + Vite (manage albums/songs with uploads)
- User app: React + Vite (browse, search, play)
Repo layout:
backend/ # Spring Boot API
frontend-admin/ # Admin dashboard
frontend-user/ # User-facing app- User registration/login with JWT
- Browse albums and songs, search, and playback UI
- Admin CRUD for albums and songs (image/audio uploads to Cloudinary)
- MongoDB persistence, secure routes with role-based access
- CORS preconfigured for local dev
Backend
cd ./backend
$env:CLOUDINARY_API_KEY="<your_key>"
$env:CLOUDINARY_API_SECRET="<your_secret>"
$env:CLOUDINARY_CLOUD_NAME="<your_cloud>"
$env:JWT_SECRET="change-me"
./mvnw.cmd spring-boot:runAdmin frontend
cd ./frontend-admin
npm install
npm run devUser frontend
cd ./frontend-user
npm install
npm run devDefaults
- API: http://localhost:8080
- Admin: http://localhost:5173
- User: http://localhost:5174
First-run admin user (for testing)
- Email: [email protected]
- Password: admin123
You can provide secrets either via environment variables or via backend/src/main/resources/application.properties.
Option A — environment variables
PowerShell (Windows):
$env:CLOUDINARY_API_KEY = "<your_key>"
$env:CLOUDINARY_API_SECRET = "<your_secret>"
$env:CLOUDINARY_CLOUD_NAME = "<your_cloud>"
$env:JWT_SECRET = "change-me"Option B — application.properties (no quotes around values)
# Cloudinary
cloudinary.api-key=<your_key>
cloudinary.api-secret=<your_secret>
cloudinary.cloud-name=<your_cloud>
# JWT
jwt.secret=change-me
# MongoDB
spring.data.mongodb.uri=mongodb://localhost:27017/notspotifyIf you change the API host, also update:
frontend-admin/src/services/apiService.jsfrontend-user/src/context/AuthContext.jsx
Dev CORS allows:
Note: Vite picks 5173 for the first dev server; if it’s taken, it increments (5174, 5175, …). The backend allows 5173 and 5174 by default—if you use a different port, either run Vite on one of those ports (e.g., npm run dev -- --port 5174) or update SecurityConfig allowed origins.
If you deploy to another host, update the allowed origins in backend security config and the API base URLs in both frontends.
Base URL: http://localhost:8080
| Area | Method | Path | Auth | Notes |
|---|---|---|---|---|
| Health | GET | /api/health | None | Health check |
| Auth | POST | /api/auth/register | None | Body: { email, password } |
| Auth | POST | /api/auth/login | None | Returns { token, email, role } |
| Albums | GET | /api/albums | Bearer (USER/ADMIN) | List albums |
| Albums | POST | /api/albums | Bearer (ADMIN) | Multipart: request (JSON), file (image) |
| Albums | DELETE | /api/albums/{albumId} | Bearer (ADMIN) | Delete album |
| Songs | GET | /api/songs | Bearer (USER/ADMIN) | List songs |
| Songs | POST | /api/songs | Bearer (ADMIN) | Multipart: request (JSON), image (image), audio (audio) |
| Songs | DELETE | /api/songs/{songId} | Bearer (ADMIN) | Delete song |
Build frontends
cd ./frontend-admin
npm run build
cd ../frontend-user
npm run buildBuild backend JAR (skips tests) and run
cd ./backend
./mvnw.cmd -DskipTests package
java -jar ./target/*.jar- Requires: Java 21, Maven 3.9+, Node 18+, MongoDB, Cloudinary account
- CORS in dev allows http://localhost:5173 and http://localhost:5174
- Auth uses JWT; send
Authorization: Bearer YOUR_TOKEN
- MongoDB connection refused: ensure MongoDB is running and
spring.data.mongodb.uriis correct. - 401 on admin routes: login as an admin; a test admin is seeded on first run.
- Upload errors (413/validation): check field names and multipart limits in
application.properties. - Cloudinary errors: verify all three Cloudinary env vars and account settings.



