Backend API for the Videoflix frontend.
Videoflix is an educational video streaming project with user authentication, email-based account activation, password reset flow, protected video endpoints, asynchronous video processing, and HLS streaming.
- Tech Stack
- Key Concepts
- API Base URL
- Authentication
- Endpoints
- Video Processing Flow
- Data Model
- Project Structure
- Environment Variables
- Setup with Docker Compose
- Production Deployment Notes
- Useful Commands
- Frontend Integration
- Security Notes
- Project Status
- License
License Project Status Security Notes Frontend Integration Useful Commands
- Python
- Django
- Django REST Framework (DRF)
- Simple JWT
- Cookie-based authentication with HTTP-only cookies
- PostgreSQL
- Redis
- Django RQ
- FFmpeg
- Gunicorn
- Nginx
- django-cors-headers
- Pillow
- python-dotenv
- Custom user model using email as the login identifier
- Account registration with email activation
- Login via JWT access and refresh tokens stored in HTTP-only cookies
- Password reset via email token link
- Protected API endpoints for authenticated users
- Video upload through the Django admin
- Automatic background processing after video upload
- FFmpeg-based thumbnail generation
- HLS video generation in multiple resolutions:
- 480p
- 720p
- 1080p
- Master playlist generation for adaptive streaming
- Redis-backed Django RQ worker for long-running video processing jobs
- PostgreSQL database for production-ready persistence
Local development:
http://127.0.0.1:8000/api/
Production example:
https://api.videoflix.saschaheinze.de/api/
This project uses JWT authentication with HTTP-only cookies.
After a successful login, the backend sets:
access_token
refresh_token
Protected endpoints read the access token from the cookie. The frontend does not need to store tokens in localStorage or sessionStorage.
Creates a new inactive user account and sends an activation email.
Request:
{
"email": "user@example.com",
"password": "your_password",
"confirmed_password": "your_password"
}Response:
{
"user": {
"id": 1,
"email": "user@example.com"
},
"token": "activation_token"
}Notes:
- The user is inactive until the account is activated.
- The activation link is sent via email.
- If email delivery fails, the registration is rolled back.
Activates a registered user account.
Success response:
{
"message": "Account successfully activated."
}Logs in an activated user and sets authentication cookies.
Request:
{
"email": "user@example.com",
"password": "your_password"
}Response:
{
"detail": "Login successful",
"user": {
"id": 1,
"username": "user@example.com"
}
}Logs out the user, deletes authentication cookies and invalidates the refresh token.
Response:
{
"detail": "Logout successful! All tokens will be deleted. Refresh token is now invalid."
}Refreshes the access token by using the refresh token cookie.
Response:
{
"detail": "Token refreshed",
"access": "new_access_token"
}Sends a password reset email if the email address belongs to an existing user.
Request:
{
"email": "user@example.com"
}Response:
{
"detail": "An email has been sent to reset your password."
}Note: The response is intentionally the same whether the email exists or not.
Sets a new password after a valid password reset request.
Request:
{
"new_password": "new_password",
"confirm_password": "new_password"
}Response:
{
"detail": "Your Password has been successfully reset."
}Returns all processed videos that are ready for streaming.
Auth required.
Response:
[
{
"id": 1,
"created_at": "2026-05-06T14:00:00Z",
"title": "Example Video",
"description": "Example description",
"thumbnail_url": "https://api.example.com/media/thumbnails/video_1.jpg",
"category": "Drama"
}
]Notes:
- Only videos with
processing_status = readyare returned. - Videos that are still processing or failed are hidden from the public list.
Returns the HLS master playlist for a video.
Auth required.
Content-Type:
application/vnd.apple.mpegurl
Returns the HLS playlist for one specific resolution.
Auth required.
Example:
/api/video/1/720p/index.m3u8
Content-Type:
application/vnd.apple.mpegurl
Returns a single HLS video segment.
Auth required.
Example:
/api/video/1/720p/segment_000.ts/
Content-Type:
video/MP2T
1. Admin uploads a video file
2. Django saves the Video object with status pending
3. A post_save signal enqueues a background job
4. Django RQ worker starts processing the video
5. FFmpeg creates a thumbnail
6. FFmpeg creates HLS streams for 480p, 720p and 1080p
7. A master.m3u8 playlist is generated
8. The video status is set to ready
9. The video becomes available via /api/video/
If processing fails, the video status is set to failed and the error is stored in processing_error.
- Email-based custom user model
- Uses email as
USERNAME_FIELD - Supports inactive users before activation
- Supports Django permissions and admin access
- Title
- Description
- Category
- Source file
- Thumbnail
- Processing status
- Processing error
- Created timestamp
- Updated timestamp
Processing statuses:
pending
processing
ready
failed
videoflix-backend/
├─ authentication/ Custom user model and authentication API
│ ├─ api/
│ │ ├─ serializers.py Register, login and password serializers
│ │ ├─ urls.py Auth endpoint routes
│ │ ├─ utils.py Token and email helper functions
│ │ └─ views.py Auth API views
│ ├─ tests/
│ │ ├─ __init__.py
│ │ ├─ test_happy.py
│ │ └─ test_unhappy.py
│ ├─ authentication.py Cookie JWT authentication class
│ ├─ admin.py
│ ├─ apps.py
│ └─ models.py Custom User and UserManager
│
├─ content/ Video domain and streaming API
│ ├─ api/
│ │ ├─ serializers.py Video response serializer
│ │ ├─ urls.py Video and HLS routes
│ │ └─ views.py Video list and HLS file responses
│ ├─ tests/
│ │ ├─ __init__.py
│ │ ├─ test_happy.py
│ │ └─ test_unhappy.py
│ ├─ admin.py Video admin configuration
│ ├─ apps.py
│ ├─ models.py Video model
│ ├─ signals.py Starts video processing jobs
│ └─ tasks.py FFmpeg thumbnail and HLS processing
│
├─ core/ Django project configuration
│ ├─ settings.py
│ ├─ urls.py
│ ├─ asgi.py
│ └─ wsgi.py
│
├─ backend.Dockerfile
├─ backend.entrypoint.sh
├─ docker-compose.yml
├─ manage.py
├─ requirements.txt
├─ .env.template
├─ .gitignore
└─ README.md
Create a .env file based on .env.template.
Example for production-like deployment:
SECRET_KEY=your_secret_key
DEBUG=False
ALLOWED_HOSTS=api.videoflix.example.com,localhost,127.0.0.1
CORS_ALLOWED_ORIGINS=https://videoflix.example.com
CSRF_TRUSTED_ORIGINS=https://videoflix.example.com,https://api.videoflix.example.com
FRONTEND_URL=https://videoflix.example.com
AUTH_COOKIE_SECURE=True
DB_NAME=videoflix
DB_USER=videoflix_user
DB_PASSWORD=your_database_password
DB_HOST=localhost
DB_PORT=5432
REDIS_HOST=localhost
REDIS_PORT=6379
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_HOST_USER=your_email@example.com
EMAIL_HOST_PASSWORD=your_email_app_password
DEFAULT_FROM_EMAIL=your_email@example.comDo not commit real secrets to Git.
git clone https://github.com/codebySaschaHeinze/videoflix-backend.git
cd videoflix-backendcp .env.template .envAdjust the values in .env.
docker compose up --buildThe backend will be available at:
http://127.0.0.1:8000/api/
docker compose exec web python manage.py testWindows PowerShell:
python -m venv .venv
.\.venv\Scripts\Activate.ps1macOS/Linux:
python3 -m venv .venv
source .venv/bin/activatepip install --upgrade pip
pip install -r requirements.txtFFmpeg and Redis are required for video processing.
Ubuntu/Debian:
sudo apt update
sudo apt install ffmpeg redis-server postgresql postgresql-contribpython manage.py migratepython manage.py createsuperuserpython manage.py runserverIn a second terminal:
python manage.py rqworker defaultpython manage.py testCurrent test coverage includes happy and unhappy path tests for authentication and content endpoints.
This project can be deployed with:
- Gunicorn as WSGI server
- Nginx as reverse proxy
- PostgreSQL as database
- Redis as message broker
- Django RQ worker as a separate systemd service
- Nginx serving
/static/and/media/ - HTTPS via Certbot
Example service layout:
Nginx
→ Gunicorn on 127.0.0.1:8003
→ Django backend
→ PostgreSQL
→ Redis
→ RQ worker
→ FFmpeg processing
Important production settings:
DEBUG=False
AUTH_COOKIE_SECURE=True
HTTPS enabled
static files collected
media directory writable by the Django/RQ process
Run migrations:
python manage.py migrateCollect static files:
python manage.py collectstatic --noinputRun tests:
python manage.py testStart RQ worker manually:
python manage.py rqworker defaultCheck generated media files:
find media -maxdepth 5 -type fCheck production service logs:
sudo journalctl -u videoflix -n 50 --no-pager
sudo journalctl -u videoflix-rqworker -n 50 --no-pagerThe frontend should point to the backend API base URL:
const API_BASE_URL = "https://api.videoflix.example.com/api/";For cookie-based authentication, frontend requests to protected endpoints must include credentials:
fetch(url, {
credentials: "include",
});- JWT tokens are stored in HTTP-only cookies.
- Access to video endpoints requires authentication.
- Passwords are stored hashed by Django.
- Password reset responses do not reveal whether an email exists.
- Production cookies should use
Secure. - Real secrets must never be committed to the repository.
Implemented:
- Email-based registration
- Account activation by email
- Login and logout with HTTP-only JWT cookies
- Refresh token flow
- Password reset and password confirmation
- Protected video list endpoint
- Protected HLS playlist and segment endpoints
- Video upload through Django admin
- Asynchronous video processing with Django RQ
- FFmpeg thumbnail generation
- FFmpeg HLS generation for 480p, 720p and 1080p
- Master playlist generation
- Happy and unhappy path tests
Educational project. Adjust the license information as needed before publishing or reusing this project.