Django backend for MusiquePeulh a free and open source fulani music streaming web app.
# MusiquePeulh (Backend)
Backend for **MusiquePeulh** — a free, open-source music streaming service for
discovering and listening to Fulani music across West Africa and the Sahel.
Built with **Django REST Framework**, this project was developed entirely by me
without ai, to demonstrate my backend engineering skills and showcase a production-style
implementation with JWT authentication, user and role management, secure media
upload/streaming, and playlist APIs that power the
frontend client.
**Live API:**
api.musiquepeulh.com · Interactive docs at `/api/docs/` (Swagger) — schema via drf-spectacular.
---
## ✨ What this project demonstrates (backend focus)
- **Secure JWT auth** with access/refresh rotation, token blacklisting on logout, and custom token claims.
- **Private media pipeline** — files are uploaded to object storage and served only through **short-lived pre-signed URLs**, never from a public bucket.
- **Ownership-scoped authorization** on every user-owned resource (a resource you don't own returns `404`, so existence isn't leaked).
- **Per-endpoint rate limiting** with scoped throttle classes.
- **Modular, scalable app layout** — views and serializers split one-per-endpoint instead of monolithic files.
- **Environment-separated, security-hardened production config** and full OpenAPI documentation.
---
## 🚀 Features
### 🔐 Authentication & Users
- Custom user model (email as the login identifier), login by email **or** username
- JWT auth via **SimpleJWT** — access/refresh tokens, refresh rotation, and token **blacklisting** on logout
- Custom `TokenObtainPair` serializer embedding `username`/`email` claims
- Email verification with 6-digit codes, resend flow, and password reset — delivered via **Brevo**
- Admin user management: list users, promote to admin, delete
- Input validation with clean, field-name-free error messages
### 🎵 Songs & Streaming
- Upload songs (`.mp3`) + cover art to **Cloudflare R2** (S3-compatible, private bucket)
- A …