the_inventory

Deployment Guide

This guide covers deploying The Inventory backend API to production environments.


Table of Contents


Pre-Deployment Checklist

Before deploying to production, ensure:


Docker Deployment

Build the Docker Image

docker build -t the_inventory:latest .

Run Locally

docker run -p 8000:8000 \
  -e SECRET_KEY="your-secret-key" \
  -e ALLOWED_HOSTS="localhost,127.0.0.1" \
  -e DATABASE_URL="postgresql://user:pass@db:5432/inventory" \
  the_inventory:latest

Push to Registry

# Tag image
docker tag the_inventory:latest your-registry/the_inventory:latest

# Push to registry
docker push your-registry/the_inventory:latest

Docker Compose Example

Create docker-compose.yml:

version: '3.8'

services:
  db:
    image: postgres:15
    environment:
      POSTGRES_DB: inventory
      POSTGRES_USER: inventory_user
      POSTGRES_PASSWORD: secure_password
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

  redis:
    image: redis:7
    ports:
      - "6379:6379"

  web:
    build: .
    command: gunicorn the_inventory.wsgi:application --bind 0.0.0.0:8000
    environment:
      DEBUG: "False"
      SECRET_KEY: "your-secret-key"
      ALLOWED_HOSTS: "localhost,127.0.0.1"
      DATABASE_URL: "postgresql://inventory_user:secure_password@db:5432/inventory"
      REDIS_URL: "redis://redis:6379/0"
    ports:
      - "8000:8000"
    depends_on:
      - db
      - redis
    volumes:
      - ./src:/app/src

volumes:
  postgres_data:

Run with:

docker-compose up -d

Render Deployment

1. Connect Repository

  1. Go to Render Dashboard
  2. Click “New +” → “Web Service”
  3. Connect your GitHub repository
  4. Select the the_inventory repository

2. Configure Service

Basic Settings:

3. Set Environment Variables

In Render dashboard, add these environment variables:

Required Variables:

DEBUG=False
DJANGO_SETTINGS_MODULE=the_inventory.settings.production
SECRET_KEY=<generate-and-paste>
ALLOWED_HOSTS=your-service.onrender.com
DATABASE_URL=<PostgreSQL-connection-string>

Critical for JWT Authentication (MUST SET - prevents 401 errors):

CORS_ALLOWED_ORIGINS=https://your-frontend.vercel.app
FRONTEND_URL=https://your-frontend.vercel.app
CSRF_TRUSTED_ORIGINS=https://your-frontend.vercel.app

JWT Cookie Configuration:

JWT_COOKIE_SECURE=true
JWT_COOKIE_SAMESITE=Lax
JWT_COOKIE_DOMAIN=

Optional but Recommended:

REDIS_URL=<Redis-connection-string>
DJANGO_LOG_LEVEL=INFO
AUTO_SEED_DATABASE=false

⚠️ Important: If you skip the “Critical for JWT Authentication” variables, users will get 401 Unauthorized errors after login. See Troubleshooting Guide for details.

4. Create PostgreSQL Database

  1. In Render dashboard, create a new PostgreSQL database
  2. Copy the connection string
  3. Paste into DATABASE_URL environment variable

5. Create Redis Cache

  1. In Render dashboard, create a new Redis instance
  2. Copy the connection string
  3. Paste into REDIS_URL environment variable

6. Deploy

Click “Create Web Service” — Render will automatically deploy.

7. Run Migrations

After first deployment, run migrations:

# Via Render Shell
python src/manage.py migrate
python src/manage.py createsuperuser

Kubernetes Deployment

Create ConfigMap for Environment Variables

apiVersion: v1
kind: ConfigMap
metadata:
  name: inventory-config
data:
  DEBUG: "False"
  DJANGO_SETTINGS_MODULE: "the_inventory.settings.production"
  ALLOWED_HOSTS: "api.example.com"
  FRONTEND_URL: "https://app.example.com"
  CORS_ALLOWED_ORIGINS: "https://app.example.com"

Create Secret for Sensitive Data

apiVersion: v1
kind: Secret
metadata:
  name: inventory-secrets
type: Opaque
stringData:
  SECRET_KEY: "your-secret-key"
  DATABASE_URL: "postgresql://user:pass@db:5432/inventory"
  REDIS_URL: "redis://redis:6379/0"

Create Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: inventory-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: inventory-api
  template:
    metadata:
      labels:
        app: inventory-api
    spec:
      containers:
      - name: api
        image: your-registry/the_inventory:latest
        ports:
        - containerPort: 8000
        envFrom:
        - configMapRef:
            name: inventory-config
        - secretRef:
            name: inventory-secrets
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /api/v1/
            port: 8000
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /api/v1/
            port: 8000
          initialDelaySeconds: 10
          periodSeconds: 5

Create Service

apiVersion: v1
kind: Service
metadata:
  name: inventory-api-service
spec:
  selector:
    app: inventory-api
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8000
  type: LoadBalancer

Deploy to Kubernetes

kubectl apply -f configmap.yaml
kubectl apply -f secret.yaml
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

Environment Configuration

Required Variables

Variable Example Description
SECRET_KEY django-insecure-... Django secret key (generate new)
ALLOWED_HOSTS api.example.com Allowed hostnames
DATABASE_URL postgresql://user:pass@host/db PostgreSQL connection
DEBUG False Disable debug mode in production
Variable Example Description
REDIS_URL redis://host:6379/0 Redis cache connection
FRONTEND_URL https://app.example.com Frontend URL for redirects
CORS_ALLOWED_ORIGINS https://app.example.com Frontend CORS origin
EMAIL_HOST smtp.gmail.com SMTP server
EMAIL_HOST_USER noreply@example.com SMTP username
EMAIL_HOST_PASSWORD app-password SMTP password

See Environment Variables for complete reference.


Database Setup

PostgreSQL Installation

On Ubuntu/Debian:

sudo apt-get install postgresql postgresql-contrib

On macOS:

brew install postgresql

Create Database and User

sudo -u postgres psql

CREATE DATABASE inventory;
CREATE USER inventory_user WITH PASSWORD 'secure_password';
ALTER ROLE inventory_user SET client_encoding TO 'utf8';
ALTER ROLE inventory_user SET default_transaction_isolation TO 'read committed';
ALTER ROLE inventory_user SET default_transaction_deferrable TO on;
ALTER ROLE inventory_user SET timezone TO 'UTC';
GRANT ALL PRIVILEGES ON DATABASE inventory TO inventory_user;
\q

Connection String

postgresql://inventory_user:secure_password@localhost:5432/inventory

Run Migrations

cd src
python manage.py migrate

Create Superuser

python manage.py createsuperuser

Monitoring & Logging

Application Logs

View logs from your deployment platform:

Render:

# Via Render dashboard → Logs tab

Kubernetes:

kubectl logs -f deployment/inventory-api

Database Monitoring

Monitor PostgreSQL performance:

# Connect to database
psql postgresql://user:pass@host/inventory

# Check active connections
SELECT * FROM pg_stat_activity;

# Check slow queries
SELECT query, calls, mean_time FROM pg_stat_statements ORDER BY mean_time DESC;

Application Monitoring

Set up monitoring for:

Alerting

Configure alerts for:


Backup & Restore

Automated Backups

PostgreSQL Backups:

# Daily backup script
#!/bin/bash
BACKUP_DIR="/backups/inventory"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
pg_dump postgresql://user:pass@host/inventory > $BACKUP_DIR/inventory_$TIMESTAMP.sql
gzip $BACKUP_DIR/inventory_$TIMESTAMP.sql

Schedule with cron:

0 2 * * * /path/to/backup-script.sh

Manual Backup

pg_dump postgresql://user:pass@host/inventory > inventory_backup.sql

Restore from Backup

psql postgresql://user:pass@host/inventory < inventory_backup.sql

Cloud Backups

Use your cloud provider’s backup service:


SSL/TLS Configuration

Render (Automatic)

Render automatically provides SSL certificates. Your service is accessible at:

https://your-service.onrender.com

Self-Hosted (Let’s Encrypt)

Use Certbot to get free SSL certificates:

sudo apt-get install certbot python3-certbot-nginx
sudo certbot certonly --standalone -d api.example.com

Configure Nginx to use the certificate:

server {
    listen 443 ssl;
    server_name api.example.com;

    ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:8000;
    }
}

Troubleshooting

Database Connection Error

Error: could not connect to server

Solution:

  1. Verify DATABASE_URL is correct
  2. Check database is running
  3. Verify firewall allows connection

Static Files Not Loading

404 Not Found for /static/...

Solution:

python src/manage.py collectstatic --noinput

Secret Key Error

Error: SECRET_KEY is not set

Solution: Generate and set SECRET_KEY:

python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"

Next Steps

See Troubleshooting Guide for more help.

Configure Gunicorn Workers

The Gunicorn worker count can be configured using the GUNICORN_WORKERS environment variable.

By default, the application uses 4 workers.

Example:

GUNICORN_WORKERS=4

For smaller deployments, use fewer workers:

GUNICORN_WORKERS=1

For larger deployments, increase the worker count based on CPU and memory:

GUNICORN_WORKERS=8