Project Overview
The Activity Monitoring Dashboard System provides a centralized platform to ingest, store and visualize user activity events. It replaces ad-hoc scripts and spreadsheets with a consistent, role-based dashboard and API, enabling real-time insights and automated reporting across your organization.
Purpose
- Consolidate disparate activity logs (web, mobile, external systems)
- Offer role-based access: School Admins, Human Reviewers, Monitor Companies
- Generate alerts and reports for compliance, performance tracking, anomaly detection
Key Capabilities
- RESTful API for event ingestion and retrieval
- JWT-based authentication with extended claims (
role
,institute
,monitor_comp
) - Role-specific dashboards and data filters
- Extensible data models for new event types
- Pluggable notification channels (email, webhooks)
Architecture
The project follows Django’s “two-tier” structure: a core project module and feature apps.
monitoring_system (core project)
settings.py
: global configuration, middleware, installed appsurls.py
: root URL routingwsgi.py
/asgi.py
: deployment entry points
accounts (feature app)
- Custom
User
model withrole
,institute
,monitor_comp
fields - JWT token generation via
User.tokens()
- Registration, login and profile endpoints
- Custom
Directory Structure
Activity_Monitoring_Dashboard_System/
├── manage.py
├── monitoring_system/
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ ├── wsgi.py
│ └── asgi.py
├── accounts/
│ ├── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── views.py
│ └── urls.py
├── requirements.txt
└── README.md
Quick Start
- Clone the repo and install dependencies
git clone https://github.com/MrRoy2246/Activity_Monitoring_Dashboard_System.git cd Activity_Monitoring_Dashboard_System pip install -r requirements.txt
- Configure environment
cp .env.example .env # Edit .env: SECRET_KEY, DATABASE_URL, EMAIL_BACKEND, etc.
- Apply migrations and create a superuser
python manage.py migrate python manage.py createsuperuser
- Run the development server
python manage.py runserver
Core Settings Snippet
# monitoring_system/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
# ...
'rest_framework',
'accounts',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
}
# Load secrets from environment
from decouple import config
SECRET_KEY = config('SECRET_KEY')
DATABASES = {'default': config('DATABASE_URL', cast=db_url)}
For detailed usage patterns and API references, see README.md.
Getting Started
This guide walks you through setting up a local development instance of the Activity Monitoring Dashboard System.
Prerequisites
• Python 3.8 or higher
• PostgreSQL 12+
• Git
• Virtualenv (optional but recommended)
1. Clone the Repository
git clone https://github.com/MrRoy2246/Activity_Monitoring_Dashboard_System.git
cd Activity_Monitoring_Dashboard_System
2. Create & Activate Virtual Environment
python3 -m venv venv
source venv/bin/activate # macOS/Linux
venv\Scripts\activate.bat # Windows
3. Install Dependencies
pip install --upgrade pip
pip install -r requirements.txt
4. Configure Environment Variables
Create a file named .env
in the project root (ensure you add .env
to .gitignore
):
# Django settings
DJANGO_SECRET_KEY=replace-with-your-secret-key
DJANGO_DEBUG=True
# Database
DB_ENGINE=django.db.backends.postgresql
DB_NAME=activity_monitor
DB_USER=monitor_user
DB_PASSWORD=secure_password
DB_HOST=localhost
DB_PORT=5432
# Email (for account notifications)
EMAIL_HOST=smtp.example.com
EMAIL_PORT=587
EMAIL_HOST_USER=you@example.com
EMAIL_HOST_PASSWORD=your-email-password
EMAIL_USE_TLS=True
# JWT
JWT_SECRET_KEY=replace-with-jwt-secret
In monitoring_system/settings.py
, these load via os.environ[...]
.
5. Initialize the Database
Start PostgreSQL shell:
psql -U postgres
Create database and user:
CREATE DATABASE activity_monitor; CREATE USER monitor_user WITH PASSWORD 'secure_password'; GRANT ALL PRIVILEGES ON DATABASE activity_monitor TO monitor_user; \q
6. Apply Migrations
python manage.py migrate
This applies the accounts
app’s initial schema (models Institute, MonitorCompanies, User, MonitorCompaniesWithInstitute) and all other apps.
7. Create a Superuser
python manage.py createsuperuser \
--username admin \
--email admin@example.com
Follow the prompts to set a password.
8. Run the Development Server
python manage.py runserver
Open your browser at http://127.0.0.1:8000/ and log in with your superuser credentials.
You now have a full local instance. From here you can explore the Django admin, customize settings in monitoring_system/settings.py
, or begin developing new features.
Configuration & Environment Variables
Centralize all configurable settings in monitoring_system/settings.py
. Load values from environment to customize behavior across development, staging, and production.
Environment Variables Loading
Load .env
early in settings:
# settings.py
import os
from pathlib import Path
from datetime import timedelta
from dotenv import load_dotenv
BASE_DIR = Path(__file__).resolve().parent.parent
load_dotenv(BASE_DIR / ".env")
Debug, Secret Key & Allowed Hosts
Control core Django options:
SECRET_KEY = os.getenv("SECRET_KEY")
DEBUG = os.getenv("DEBUG", "False") == "True"
ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS", "").split(",")
.env example:
SECRET_KEY=supersecret
DEBUG=True
ALLOWED_HOSTS=localhost,127.0.0.1,yourdomain.com
Database Configuration
Override default database via vars:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.getenv("DB_NAME", "monitoring_db"),
"USER": os.getenv("DB_USER"),
"PASSWORD": os.getenv("DB_PASSWORD"),
"HOST": os.getenv("DB_HOST", "localhost"),
"PORT": os.getenv("DB_PORT", "5432"),
}
}
.env example:
DB_NAME=monitoring
DB_USER=monitor_user
DB_PASSWORD=secretpass
DB_HOST=db.example.com
DB_PORT=5432
CORS Settings
Allow front-end origins via comma-separated list:
INSTALLED_APPS += ["corsheaders"]
MIDDLEWARE.insert(0, "corsheaders.middleware.CorsMiddleware")
CORS_ALLOWED_ORIGINS = os.getenv("CORS_ALLOWED_ORIGINS", "").split(",")
.env example:
CORS_ALLOWED_ORIGINS=https://app.example.com,http://localhost:3000
JWT (Simple JWT) Settings
Customize token lifetimes and algorithm:
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=int(os.getenv("ACCESS_TOKEN_LIFETIME", "60"))),
"REFRESH_TOKEN_LIFETIME": timedelta(minutes=int(os.getenv("REFRESH_TOKEN_LIFETIME", "1440"))),
"ALGORITHM": os.getenv("JWT_ALGORITHM", "HS256"),
"AUTH_HEADER_TYPES": tuple(os.getenv("JWT_AUTH_HEADER_TYPES", "Bearer").split(",")),
}
REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"] = [
"rest_framework_simplejwt.authentication.JWTAuthentication",
]
.env example:
ACCESS_TOKEN_LIFETIME=120
REFRESH_TOKEN_LIFETIME=2880
JWT_ALGORITHM=HS256
JWT_AUTH_HEADER_TYPES=Bearer
Email Backend Configuration
Configure SMTP settings for all outgoing mail:
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = os.getenv("EMAIL_HOST", "smtp.gmail.com")
EMAIL_PORT = int(os.getenv("EMAIL_PORT", "587"))
EMAIL_USE_TLS = os.getenv("EMAIL_USE_TLS", "True") == "True"
EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER")
EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD")
DEFAULT_FROM_EMAIL = os.getenv("DEFAULT_FROM_EMAIL", EMAIL_HOST_USER)
.env example:
EMAIL_HOST=smtp.sendgrid.net
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_HOST_USER=apikey
EMAIL_HOST_PASSWORD=SG.xxxxxx
DEFAULT_FROM_EMAIL=no-reply@example.com
Logging Configuration
Set global log level via LOG_LEVEL
:
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"console": {
"class": "logging.StreamHandler",
"formatter": "verbose",
},
},
"formatters": {
"verbose": {
"format": "[{levelname}] {asctime} {name}: {message}",
"style": "{",
},
},
"root": {
"handlers": ["console"],
"level": LOG_LEVEL,
},
}
.env example:
LOG_LEVEL=DEBUG
Third-Party API Keys & Security
Pull in external keys and tighten security:
# Third-party
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
PAYSTACK_SECRET_KEY = os.getenv("PAYSTACK_SECRET_KEY")
# Security
CSRF_TRUSTED_ORIGINS = os.getenv("CSRF_TRUSTED_ORIGINS", "").split(",")
SECURE_SSL_REDIRECT = os.getenv("SECURE_SSL_REDIRECT", "True") == "True"
SESSION_COOKIE_SECURE = os.getenv("SESSION_COOKIE_SECURE", "True") == "True"
.env example:
GOOGLE_API_KEY=AIzaSy...
PAYSTACK_SECRET_KEY=sk_test_xxx
CSRF_TRUSTED_ORIGINS=https://app.example.com
SECURE_SSL_REDIRECT=True
SESSION_COOKIE_SECURE=True
Feature Flags
Toggle features without code changes:
FEATURE_X_ENABLED = os.getenv("FEATURE_X_ENABLED", "False") == "True"
FEATURE_Y_ENABLED = os.getenv("FEATURE_Y_ENABLED", "False") == "True"
Use flags in code:
from django.conf import settings
if settings.FEATURE_X_ENABLED:
# activate new workflow
...
.env example:
FEATURE_X_ENABLED=True
FEATURE_Y_ENABLED=False
Tailor each environment variable in your .env
file to match your deployment requirements. Restart the application after any change to ensure settings reload.
Authentication & Permissions
This section covers how the system authenticates users via JWTs, defines roles, and protects API endpoints using custom DRF permission classes.
JWT Token Generation with Custom Claims
Every user instance exposes a .tokens()
method that returns an access/refresh pair enriched with user-specific data.
# accounts/models.py
from rest_framework_simplejwt.tokens import RefreshToken
import jwt
from django.conf import settings
class User(AbstractBaseUser, PermissionsMixin):
# … fields: id, username, email, role, institute, monitor_comp …
def tokens(self):
# 1. Create base tokens
refresh = RefreshToken.for_user(self)
access = refresh.access_token
# 2. Decode and inject custom claims
decoded = jwt.decode(str(access), settings.SECRET_KEY, algorithms=["HS256"])
decoded.update({
"id": str(self.id),
"name": self.username,
"email": self.email,
"role": self.role
})
if self.role in (3, 4, 5):
if self.institute:
decoded["institute"] = str(self.institute.id)
elif self.monitor_comp:
decoded["monitor_comp"] = str(self.monitor_comp.id)
# 3. Re-encode access token
access_token = jwt.encode(decoded, settings.SECRET_KEY, algorithm="HS256")
# 4. Mirror claims in refresh token
decoded_refresh = jwt.decode(str(refresh), settings.SECRET_KEY, algorithms=["HS256"])
decoded_refresh.update(decoded)
refresh_token = jwt.encode(decoded_refresh, settings.SECRET_KEY, algorithm="HS256")
return {"access": access_token, "refresh": refresh_token}
Practical Usage
# accounts/views.py (Login endpoint snippet)
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from django.contrib.auth import authenticate
from accounts.serializers import UserSerializer
class LoginView(APIView):
def post(self, request):
user = authenticate(
username=request.data["username"],
password=request.data["password"]
)
if not user:
return Response({"detail": "Invalid credentials"}, status=status.HTTP_401_UNAUTHORIZED)
tokens = user.tokens()
return Response({
"user": UserSerializer(user).data,
"access": tokens["access"],
"refresh": tokens["refresh"]
})
Tips & Gotchas
- Ensure
settings.SECRET_KEY
matches SimpleJWT’s signing key. - Keep custom claims minimal to limit token size.
Role-Based Permission Classes
The repository defines these DRF permission classes in accounts/permissions.py
:
- SystemAdminPermission
Allows only users withrole == ROLE_SYSTEM_ADMIN
. - SchoolAdminPermission
Allows only users withrole == ROLE_SCHOOL_ADMIN
and an associated institute. - HumanReviewerPermission
Allows only users withrole == ROLE_HUMAN_REVIEWER
. - UserPermission
Allows only authenticated end-users (role == ROLE_USER
). - HasValidSecretKey
Checks for a secret header (X-SECRET-KEY
) matchingsettings.SECRET_KEY
. - AnyOfPermissions
Combines multiple classes with OR logic: grants access if any sub-permission allows it.
Basic View Protection
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from accounts.permissions import SystemAdminPermission, HasValidSecretKey
class InstituteListView(APIView):
authentication_classes = [JWTAuthentication]
permission_classes = [AnyOfPermissions(SystemAdminPermission, HasValidSecretKey)]
def get(self, request):
institutes = Institute.objects.all()
serializer = InstituteSerializer(institutes, many=True)
return Response(serializer.data)
Combining Permissions: AnyOfPermissions
Use AnyOfPermissions
to avoid deep nesting when multiple roles or mechanisms may grant access.
# accounts/permissions.py (simplified)
from rest_framework.permissions import BasePermission
class AnyOfPermissions(BasePermission):
def __init__(self, *perms):
self.perms = perms
def has_permission(self, request, view):
return any(perm().has_permission(request, view) for perm in self.perms)
Example: Reports Endpoint
from rest_framework.views import APIView
from accounts.permissions import (
AnyOfPermissions, HasValidSecretKey,
SystemAdminPermission, HumanReviewerPermission
)
class ReportsView(APIView):
permission_classes = [
AnyOfPermissions(
HasValidSecretKey,
SystemAdminPermission,
HumanReviewerPermission
)
]
def get(self, request):
data = generate_reports()
return Response(data)
Protecting CRUD Endpoints
User Management
from rest_framework.viewsets import ModelViewSet
from accounts.models import User
from accounts.serializers import UserSerializer
from accounts.permissions import AnyOfPermissions, SystemAdminPermission, SchoolAdminPermission
class UserViewSet(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [
AnyOfPermissions(SystemAdminPermission, SchoolAdminPermission)
]
Institute & MonitorCompany Management
from rest_framework.viewsets import ModelViewSet
from accounts.models import Institute, MonitorCompanies
from accounts.serializers import InstituteSerializer, MonitorCompanySerializer
from accounts.permissions import SystemAdminPermission
class InstituteViewSet(ModelViewSet):
queryset = Institute.objects.all()
serializer_class = InstituteSerializer
permission_classes = [SystemAdminPermission]
class MonitorCompanyViewSet(ModelViewSet):
queryset = MonitorCompanies.objects.all()
serializer_class = MonitorCompanySerializer
permission_classes = [SystemAdminPermission]
Summary
- Use
User.tokens()
to generate JWTs with embedded user, role, and scope claims. - Protect endpoints with role-specific permissions and
HasValidSecretKey
. - Combine OR logic with
AnyOfPermissions
for flexible access control. - Apply
permission_classes
on views/viewsets to enforce these rules consistently.
Accounts API Reference
Practical guide to all publicly available REST endpoints in the accounts
app. Endpoints are grouped by function, show example requests/responses and list required permissions.
1. Authentication
1.1 Obtain JWT Tokens
POST /accounts/token/
Permissions: Public
Request
POST /accounts/token/ HTTP/1.1
Content-Type: application/json
{
"email": "alice@example.com",
"password": "Secret123!"
}
Response (200)
{
"refresh": "<refresh_token>",
"access": "<access_token>",
"email": "alice@example.com",
"id": 42,
"status": "success"
}
1.2 Refresh Access Token
POST /accounts/token/refresh/
Permissions: Public
Request
{ "refresh": "<your_refresh_token>" }
Response (200)
{ "access": "<new_access_token>" }
1.3 Verify Token
POST /accounts/token/verify/
Permissions: Public
Request
{ "token": "<any_jwt_token>" }
Response:
- 200 OK (valid)
- 401 Unauthorized / 400 Bad Request (invalid/expired)
1.4 Login (Alternate)
POST /accounts/login/
Permissions: Public
Returns user info plus tokens.
Request
{ "email": "alice@example.com", "password": "Secret123!" }
Response (200)
{
"access": "<access_token>",
"refresh": "<refresh_token>",
"user": {
"id": 42,
"username": "alice",
"email": "alice@example.com",
"role": 2
}
}
1.5 Logout
POST /accounts/logout/
Permissions: Authenticated
Headers:Authorization: Bearer <access_token>
Response (200)
{ "detail": "Successfully logged out." }
2. Registration & Email Verification
2.1 Register a New User
POST /accounts/register/
Permissions: Public
Request
{
"username": "jdoe",
"email": "jdoe@example.com",
"password": "StrongP@ssw0rd",
"role": 3,
"phone_number": "555-1234"
}
Response (201)
{
"id": 99,
"username": "jdoe",
"email": "jdoe@example.com",
"role": 3,
"phone_number": "555-1234",
"is_verified": false
}
Notes
• A verification email contains GET /accounts/verify-email/?token=<JWT>
.
• Frontend should redirect user to login on success.
2.2 Verify Email
GET /accounts/verify-email/?token=
Permissions: Public
Response: HTTP 302 redirect to settings.REDIRECT_URL_LOGIN
if token valid; 400 if invalid.
3. User Management (CRUD)
All under /accounts/users/
via DRF router.
Method | Path | Description | Permissions |
---|---|---|---|
GET | /accounts/users/ | List all users | System Admin, Tools Admin |
POST | /accounts/users/ | Create new user | System Admin, Tools Admin |
GET | /accounts/users/{id}/ | Retrieve specific user | System Admin, Tools Admin |
PUT | /accounts/users/{id}/ | Update user fields | System Admin, Tools Admin, Institute Admin (own institute) |
DELETE | /accounts/users/{id}/ | Delete a user | System Admin |
Example: Update a user's role
curl -X PUT https://api.example.com/accounts/users/99/ \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"role": 2}'
Response (200)
{
"id": 99,
"username": "jdoe",
"email": "jdoe@example.com",
"role": 2,
"is_verified": true
}
4. Institute & Monitor Management
4.1 Institutes
Endpoints under /accounts/institutes/
(DRF router).
Method | Path | Permissions |
---|---|---|
GET | /accounts/institutes/ | System Admin, Tools Admin |
POST | /accounts/institutes/ | System Admin, Tools Admin |
GET | /accounts/institutes/{id}/ | System Admin, Tools Admin |
PUT | /accounts/institutes/{id}/ | System Admin, Tools Admin |
DELETE | /accounts/institutes/{id}/ | System Admin |
Example: Create an institute
curl -X POST https://api.example.com/accounts/institutes/ \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{ "name": "Health Center A", "address": "123 Main St" }'
4.2 Monitors (Partners)
Endpoints under /accounts/monitors/
.
Method | Path | Permissions |
---|---|---|
GET | /accounts/monitors/ | Institute Admin, Tools Admin |
POST | /accounts/monitors/ | Institute Admin, Tools Admin |
GET | /accounts/monitors/{id}/ | Institute Admin, Tools Admin |
PUT | /accounts/monitors/{id}/ | Institute Admin, Tools Admin |
DELETE | /accounts/monitors/{id}/ | Institute Admin, Tools Admin |
5. Password Reset & Change
5.1 Request Password Reset
POST /accounts/password-reset/
Permissions: Public
Request
{ "email": "jdoe@example.com" }
Response (200)
{ "detail": "Password reset link sent." }
5.2 Confirm Password Reset
POST /accounts/password-reset/confirm/
Permissions: Public
Request
{
"token": "<reset_token>",
"password": "NewStrongP@ss1"
}
Response (200)
{ "detail": "Password has been reset." }
5.3 Change Password
POST /accounts/password-change/
Permissions: Authenticated
Headers:Authorization: Bearer <access_token>
Request
{
"old_password": "OldP@ssw0rd",
"new_password": "NewStrongP@ss1"
}
Response (200)
{ "detail": "Password updated successfully." }
Usage Patterns
- Signup & Verify
POST /accounts/register/
→ user clicks emailed link →GET /accounts/verify-email/
.
- Authenticate
POST /accounts/token/
→ store tokens → useAuthorization: Bearer <access>
.
- Maintain Session
POST /accounts/token/refresh/
before expiry.
- Manage Users & Orgs
- Use CRUD endpoints under
/accounts/users/
,/accounts/institutes/
,/accounts/monitors/
.
- Use CRUD endpoints under
- Password Workflows
- Initiate reset if forgotten, or change via authenticated endpoint.
Deployment
This section guides you through deploying the Activity Monitoring Dashboard System in production. It covers WSGI vs ASGI, environment hardening, static/media handling, and common deployment recipes (Docker, Gunicorn, Daphne).
Choosing WSGI vs ASGI
WSGI (Synchronous)
Use WSGI for standard HTTP endpoints and minimal async requirements.
Entry point: monitoring_system/wsgi.py
Basic Gunicorn command:
gunicorn monitoring_system.wsgi:application \
--bind 0.0.0.0:8000 \
--workers 3 \
--log-level info
ASGI (Asynchronous)
Use ASGI if you leverage async views, WebSockets or Django Channels.
Entry point: monitoring_system/asgi.py
Basic Daphne command:
daphne \
-b 0.0.0.0 -p 8000 \
monitoring_system.asgi:application
Environment Variables & Security Hardening
Store secrets and runtime settings in environment variables. Example .env
:
SECRET_KEY=your-secret-key
DEBUG=False
ALLOWED_HOSTS=dashboard.example.com
DATABASE_URL=postgres://user:pass@db:5432/monitoring
EMAIL_HOST=smtp.mailgun.org
EMAIL_HOST_USER=postmaster@mg.example.com
EMAIL_HOST_PASSWORD=mailgun-password
Key production settings in settings.py
:
DEBUG = os.getenv("DEBUG") == "True"
SECRET_KEY = os.getenv("SECRET_KEY")
ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS", "").split(",")
# Security hardening
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
X_FRAME_OPTIONS = "DENY"
Static & Media Handling
In settings.py
:
STATIC_URL = "/static/"
STATIC_ROOT = BASE_DIR / "staticfiles"
MEDIA_URL = "/media/"
MEDIA_ROOT = BASE_DIR / "mediafiles"
# Use WhiteNoise for simple static serving
MIDDLEWARE.insert(1, "whitenoise.middleware.WhiteNoiseMiddleware")
Before starting your server, run:
python manage.py collectstatic --noinput
Serve static/media via:
- WhiteNoise (built-in)
- Nginx (recommended for high scale)
- Cloud storage (S3, GCS) using django-storages
Deployment Recipes
Docker + Gunicorn
Dockerfile:
FROM python:3.11-slim
ENV PYTHONUNBUFFERED=1
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN python manage.py collectstatic --noinput
EXPOSE 8000
CMD ["gunicorn", "monitoring_system.wsgi:application", \
"--bind", "0.0.0.0:8000", \
"--workers", "4", \
"--log-level", "info"]
docker-compose.yml:
version: "3.8"
services:
web:
build: .
env_file: .env
ports:
- "8000:8000"
depends_on:
- db
db:
image: postgres:15
environment:
POSTGRES_DB: monitoring
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
Docker + Daphne (for ASGI)
Dockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN python manage.py collectstatic --noinput
EXPOSE 8000
CMD ["daphne", "-b", "0.0.0.0", "-p", "8000", "monitoring_system.asgi:application"]
Direct Server Commands
Gunicorn (sync):
export $(cat .env | xargs)
python manage.py migrate
python manage.py collectstatic --noinput
gunicorn monitoring_system.wsgi:application \
--bind 0.0.0.0:8000 \
--workers 4
Daphne (async):
export $(cat .env | xargs)
python manage.py migrate
python manage.py collectstatic --noinput
daphne -b 0.0.0.0 -p 8000 monitoring_system.asgi:application
Nginx Reverse Proxy (example)
server {
listen 80;
server_name dashboard.example.com;
location /static/ {
alias /app/staticfiles/;
}
location /media/ {
alias /app/mediafiles/;
}
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
}
}
With these recipes, you can deploy the Activity Monitoring Dashboard System robustly and securely in your production environment.