A comprehensive backend system for managing advertising budgets and campaigns at an ad agency. The system automatically tracks spending, enforces budget limits, handles dayparting schedules, and manages campaign activation based on multiple constraints.
- Budget Tracking: Real-time daily and monthly spend tracking per brand
- Automatic Campaign Control: Campaigns are automatically paused when budgets are exceeded
- Dayparting Support: Campaign scheduling based on time windows
- Daily/Monthly Resets: Automatic budget resets and campaign reactivation
- Static Typing: Full type annotations with MyPy support
- Admin Interface: Django admin for easy management
- Celery Integration: Background tasks for real-time monitoring
- Docker Support: Complete containerized deployment
- Docker Desktop installed and running
- Git (to clone the repository)
# Clone the repository
git clone https://github.com/yourusername/budget-system.git
cd budget-system
# Windows PowerShell
.\start.ps1
# Or Linux/macOS
./start.sh
# Or manual Docker Compose
docker-compose up --buildThat's it. The entire system will be running with:
- Django Admin: http://localhost:8000/admin/
- Celery Monitor: http://localhost:5555/
- Redis: localhost:6379
- Auto-scheduled tasks: Budget enforcement, dayparting, daily resets
- Database migrations: Automatically applied on startup
docker-compose exec web python manage.py createsuperuserdocker-compose restart web- Python 3.9+
- Redis (for Celery broker)
# Clone the repository
git clone https://github.com/yourusername/budget-system.git
cd budget-system
# Create and activate virtual environment
python -m venv venv
# On Windows:
venv\Scripts\activate
# On macOS/Linux:
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Apply database migrations
python manage.py makemigrations
python manage.py migrate
# Create superuser for admin access
python manage.py createsuperuser
# Run the Django development server
python manage.py runserverIn separate terminal windows:
# Terminal 1: Start Celery worker
celery -A budget_system worker --loglevel=info
# Terminal 2: Start Celery beat scheduler
celery -A budget_system beat --loglevel=infoThe Docker setup includes these services:
- web: Django application server (port 8000) - Automatically runs migrations on startup
- redis: Redis database for Celery (port 6379)
- celery-worker: Background task processor
- celery-beat: Scheduled task executor
- celery-flower: Celery monitoring UI (port 5555)
redis (base service)
↓
web (depends on redis)
↓
celery-worker (depends on redis, web)
celery-beat (depends on redis, web)
celery-flower (depends on redis, celery-worker)
# Start all services
docker-compose up --build
# Start in background
docker-compose up --build -d
# Stop all services
docker-compose down
# View all logs
docker-compose logs -f
# Restart specific service
docker-compose restart web# Django application logs
docker-compose logs -f web
# Celery worker logs
docker-compose logs -f celery-worker
# Celery beat scheduler logs
docker-compose logs -f celery-beat
# Redis logs
docker-compose logs -f redis
# Flower monitoring logs
docker-compose logs -f celery-flower# Access Django shell
docker-compose exec web python manage.py shell
# Create superuser
docker-compose exec web python manage.py createsuperuser
# Run migrations
docker-compose exec web python manage.py migrate
# Collect static files
docker-compose exec web python manage.py collectstatic
# Reset budgets manually
docker-compose exec web python manage.py reset_budgets# Rebuild specific service
docker-compose build web
# View running containers
docker-compose ps
# Access container shell
docker-compose exec web bash
# View container resource usage
docker stats- Represents an advertising brand/client
- Contains daily and monthly budget limits
- Tracks current spend totals
- Relationships: One-to-many with Campaigns
- Individual advertising campaigns belonging to a brand
- Has active/inactive status
- Relationships: Belongs to Brand, has many SpendLogs, optionally has DaypartingSchedule
- Records individual spending transactions
- Automatically updates brand totals via database signals
- Relationships: Belongs to Campaign
- Defines time windows when campaigns should be active
- Supports overnight schedules (e.g., 22:00 - 06:00)
- Relationships: One-to-one with Campaign
-
00:00 (Midnight):
- Reset daily spends for all brands
- Reset monthly spends (1st of month only)
- Reactivate eligible campaigns
-
Continuous Operations:
- Record spend logs as transactions occur
- Auto-update brand totals via database signals
-
Every Minute:
- Check dayparting windows
- Activate/deactivate campaigns based on time constraints
-
Every 5 Minutes:
- Enforce budget limits
- Pause campaigns exceeding budgets
A campaign is active only when ALL conditions are met:
- Brand's daily budget not exceeded
- Brand's monthly budget not exceeded
- Current time within dayparting window (if schedule exists)
# Docker environment
docker-compose exec web python manage.py reset_budgets
# Local environment
python manage.py reset_budgets
# Check system status with Django shell
python manage.py shell
>>> from ads.services import BudgetService, CampaignService
>>> # Use service methods for analysisThe Docker setup automatically configures:
CELERY_BROKER_URL=redis://redis:6379/0CELERY_RESULT_BACKEND=redis://redis:6379/0DEBUG=1(development mode)
Defined in settings.py:
enforce_budgets: Every 5 minutesenforce_dayparting: Every minutereset_daily_monthly_spends: Daily at midnight
To modify settings, update budget_system/settings.py or use environment variables in docker-compose.yml.
from ads.models import Campaign
from ads.services import BudgetService
from decimal import Decimal
campaign = Campaign.objects.get(name="Summer Sale")
BudgetService.record_spend(campaign, Decimal("100.50"), "Google Ads click")from ads.services import CampaignService
should_be_active, reasons = CampaignService.should_campaign_be_active(campaign)
if not should_be_active:
print(f"Campaign blocked: {', '.join(reasons)}")from ads.models import Brand
from ads.services import BudgetService
brand = Brand.objects.get(name="Acme Corp")
summary = BudgetService.get_brand_summary(brand)
print(f"Daily remaining: ${summary['daily_remaining']}")Access http://localhost:5555/ to view:
- Active/completed tasks
- Task execution times
- Worker status
- Task failure details
- Broker statistics
# Check if all containers are running
docker-compose ps
# Check Redis connection
docker-compose exec redis redis-cli ping
# Check Django health
curl http://localhost:8000/admin/
# Check Celery worker status
docker-compose exec web celery -A budget_system inspect active# View container resource usage
docker stats
# Check container disk space
docker system df
# Clean up unused Docker resources
docker system prune
# Rebuild everything from scratch
docker-compose down -v
docker-compose build --no-cache
docker-compose upThe project uses MyPy for static type checking:
# Docker environment
docker-compose exec web mypy .
# Local environment
mypy .
# Should show: Success: no issues foundConfiguration is in mypy.ini with strict mode enabled.
# Docker environment
docker-compose exec web python manage.py test
# Local environment
python manage.py test
# Run with coverage
pip install coverage
coverage run manage.py test
coverage report- Decimal Precision: Using
DecimalFieldfor financial calculations to avoid floating-point errors - UTC Timezone: All times stored in UTC; dayparting uses server timezone
- Signal-Based Updates: Brand totals updated automatically via Django signals
- Budget Priority: Budget constraints take priority over dayparting
- Automatic Reactivation: Campaigns auto-reactivate when constraints clear
- One Schedule Per Campaign: Each campaign can have at most one dayparting schedule
- Real-time Monitoring: Celery tasks provide near real-time budget enforcement
- Admin Interface: Full Django admin integration for manual management
- Containerization: Docker ensures consistent environment across development/production
- Django secret key should be changed for production
- Database credentials should be environment variables
- Redis should be secured in production
- Admin interface should be properly secured
- Docker containers should run with non-root users in production
- Update
docker-compose.prod.ymlwith production settings - Use environment variables for secrets
- Configure proper logging and monitoring
- Set up SSL/TLS termination
- Use production-grade database (PostgreSQL)
- Configure Redis persistence and clustering
- Multiple Celery workers can be added
- Redis can be clustered for high availability
- Django can run multiple instances behind a load balancer
- Database can be separated into its own service
budget_system/
├── ads/ # Django app
│ ├── models.py # Data models
│ ├── tasks.py # Celery tasks
│ ├── services.py # Business logic
│ ├── admin.py # Admin interface
│ └── management/commands/ # Management commands
├── budget_system/ # Django project
│ ├── settings.py # Configuration
│ ├── celery.py # Celery setup
│ └── urls.py # URL routing
├── docker-compose.yml # Docker services
├── Dockerfile # Docker image definition
├── start.ps1 # Windows startup script
├── start.sh # Linux/macOS startup script
├── requirements.txt # Python dependencies
├── mypy.ini # Type checking config
├── PSEUDOCODE.md # System documentation
└── README.md # This file
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure MyPy passes with no errors
- Test with Docker:
docker-compose up --build - Submit a pull request
This project is licensed under the MIT License.