A comprehensive Django-based analytics platform for managing and visualizing accounts receivable (AR) data with real-time insights, interactive dashboards, and advanced filtering capabilities.
- Features
- System Architecture
- Tech Stack
- Prerequisites
- Installation
- Configuration
- Running Locally
- API Endpoints
- Deployment
- Dashboard Features
- Troubleshooting
- Real-time AR Analytics: Live data sync from QuickBooks via Unified.to API
- Interactive Dashboards: Multiple dashboard views with customizable widgets
- Advanced Filtering: Filter by aging buckets, amount ranges, customer names
- Data Export: Export to CSV and PDF formats
- Pipeline Monitoring: Real-time Dagster ETL pipeline status tracking
- Responsive Design: Works on desktop, tablet, and mobile devices
- Aging Analysis: Industry-standard aging report with time bucket breakdown
- Customer Insights: Detailed customer-level AR analysis with risk scoring
- Print-Ready Reports: Optimized layouts for printing and stakeholder sharing
┌─────────────────────────────────────────────────────────────┐
│ Frontend Layer │
├─────────────────────────────────────────────────────────────┤
│ • Django Templates (HTML/CSS) │
│ • ECharts (Data Visualization) │
│ • HTML2PDF (Report Generation) │
│ • Responsive Bootstrap Grid │
└──────────────────────┬──────────────────────────────────────┘
│
┌──────────────────────▼──────────────────────────────────────┐
│ Django Application Layer │
├─────────────────────────────────────────────────────────────┤
│ • ar_dashboard (Main App) │
│ ├── views.py (Request Handlers) │
│ ├── models.py (Data Models) │
│ ├── urls.py (Routing) │
│ ├── serializers.py (JSON API) │
│ └── dagster_utils.py (Pipeline Integration) │
└──────────────────────┬──────────────────────────────────────┘
│
┌──────────────────────┼──────────────────────────────────────┐
│ Data Processing & ETL Layer (Dagster) │
├──────────────────────┼──────────────────────────────────────┤
│ • Asset Definitions │
│ • Job Orchestration │
│ • Scheduled Runs (Daily 6 AM, 4-Hour Intervals) │
│ • Data Transformation & Validation │
└──────────────────────┬──────────────────────────────────────┘
│
┌──────────────────────┼──────────────────────────────────────┐
│ Data Integration Layer (Unified.to) │
├──────────────────────┼──────────────────────────────────────┤
│ • QuickBooks Integration │
│ • Unified.to API Connector │
│ • OAuth2 Authentication │
│ • Real-time & Scheduled Sync │
└──────────────────────┬──────────────────────────────────────┘
│
┌──────────────────────▼──────────────────────────────────────┐
│ Database Layer │
├─────────────────────────────────────────────────────────────┤
│ PostgreSQL │
│ ├── ar_summary (Aging buckets by customer) │
│ ├── ar_invoice (Individual invoice details) │
│ ├── ar_customer (Customer master data) │
│ └── ar_sync_log (ETL execution logs) │
└──────────────────────┬──────────────────────────────────────┘
│
┌──────────────────────▼──────────────────────────────────────┐
│ External Data Sources │
├─────────────────────────────────────────────────────────────┤
│ • QuickBooks Cloud │
│ • Unified.to API │
│ • Dagster Cloud (Optional) │
└─────────────────────────────────────────────────────────────┘- Framework: Django 4.2+
- Python: 3.10+
- Database: PostgreSQL 12+
- ETL: Dagster
- API Integration: Unified.to, QuickBooks
- Templates: Django Jinja2
- Charts: ECharts 5.4+
- Styling: CSS3, Tailwind utilities
- Export: html2pdf.js
- Server: Gunicorn + Nginx
- Container: Docker
- Orchestration: Docker Compose
- Hosting: AWS/DigitalOcean/Self-hosted
- Python 3.10 or higher
- PostgreSQL 12 or higher
- Docker & Docker Compose (for containerized deployment)
- Git
- Node.js 16+ (optional, for frontend tooling)
git clone https://github.com/yourusername/ar-dashboard.git
cd ar-dashboardpython -m venv venv
# On Windows
venv\Scripts\activate
# On macOS/Linux
source venv/bin/activatepip install -r requirements.txtCreate a .env file in the project root:
# Django
DEBUG=False
SECRET_KEY=your-secret-key-here-change-in-production
ALLOWED_HOSTS=localhost,127.0.0.1,yourdomain.com
ENVIRONMENT=production
# Database
DB_ENGINE=django.db.backends.postgresql
DB_NAME=awour-db-name
DB_USER=postgres
DB_PASSWORD=secure-password-here
DB_HOST=localhost
DB_PORT=5432
# Unified.to / QuickBooks
UNIFIED_API_KEY=your-unified-api-key
QB_REALM_ID=your-quickbooks-realm-id
QB_CLIENT_ID=your-client-id
QB_CLIENT_SECRET=your-client-secret
# Dagster
DAGSTER_URL=http://localhost:3000
DAGSTER_API_KEY=your-dagster-api-key
# Email Configuration
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-password
# AWS/S3 (Optional)
USE_S3=False
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_STORAGE_BUCKET_NAME=createdb ar_dashboardpython manage.py migratepython manage.py createsuperuserEdit your_project/settings.py:
# Add to INSTALLED_APPS
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'corsheaders',
'ar_dashboard',
]
# CORS Settings
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000",
"http://localhost:8000",
"https://yourdomain.com",
]
# Database
DATABASES = {
'default': {
'ENGINE': os.getenv('DB_ENGINE'),
'NAME': os.getenv('DB_NAME'),
'USER': os.getenv('DB_USER'),
'PASSWORD': os.getenv('DB_PASSWORD'),
'HOST': os.getenv('DB_HOST'),
'PORT': os.getenv('DB_PORT'),
}
}
# Static & Media Files
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# REST Framework
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 100
}# If using Docker
docker run -d --name postgres -e POSTGRES_PASSWORD=password -p 5432:5432 postgres:15
# Or use local installation
brew services start postgresql # macOSdagster dev -f dagster_project/repository.py
# Accessible at http://localhost:3000python manage.py runserver 0.0.0.0:8000- Dashboard: http://localhost:8000/ar/
- Admin: http://localhost:8000/admin/
- API: http://localhost:8000/ar/api/
GET /ar/api/summary-stats/
Response: {
"total_customers": 8,
"total_ar": 24566.0,
"total_overdue": 24566.0,
"overdue_percentage": 100.0,
"total_invoices": 29,
"avg_days_overdue": 993.21,
"at_risk_customers": 8
}GET /ar/api/aging-distribution/
Response: {
"distribution": {
"Current": 0.0,
"1-30": 630.0,
"31-60": 0.0,
"61-90": 0.0,
"91-120": 0.0,
"120+": 23936.0
},
"total": 24566.0
}GET /ar/api/customer-breakdown/
Response: {
"customers": [
{
"id": 6,
"customer": "Misael Anderson",
"total_outstanding": 7210.0,
"overdue": 7210.0,
"invoice_count": 1
}
]
}GET /ar/api/invoice-details/<customer_id>/
Response: {
"invoices": [
{
"invoice_number": "INV-001",
"invoice_date": "2024-01-15",
"due_date": "2024-02-15",
"amount_due": 1500.0,
"days_overdue": 30,
"status": "OVERDUE",
"aging_bucket": "31-60"
}
]
}GET /ar/api/dagster-status/
Response: {
"status": "success",
"message": "Last run: SUCCESS",
"jobName": "ar_data_pipeline",
"runs": [...]
}FROM python:3.10-slim
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
# Copy requirements and install
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application
COPY . .
# Collect static files
RUN python manage.py collectstatic --noinput
# Run migrations and start server
CMD ["sh", "-c", "python manage.py migrate && gunicorn config.wsgi:application --bind 0.0.0.0:8000"]version: '3.8'
services:
db:
image: postgres:15
environment:
POSTGRES_DB: ar_dashboard
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
web:
build: .
command: gunicorn config.wsgi:application --bind 0.0.0.0:8000
volumes:
- .:/app
ports:
- "8000:8000"
environment:
- DB_HOST=db
- DEBUG=False
depends_on:
- db
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health/"]
interval: 30s
timeout: 10s
retries: 3
dagster:
image: dagster/dagster-k8s:latest
ports:
- "3000:3000"
environment:
- POSTGRES_HOST=db
- DB_PASSWORD=${DB_PASSWORD}
depends_on:
- db
volumes:
postgres_data:# Build images
docker-compose build
# Start services
docker-compose up -d
# Run migrations
docker-compose exec web python manage.py migrate
# Create superuser
docker-compose exec web python manage.py createsuperuser# Use Ubuntu 22.04 LTS
# t3.medium or larger recommended
# Security Group: Allow ports 80, 443, 8000sudo apt update && sudo apt upgrade -y
sudo apt install -y python3.10 python3.10-venv postgresql-client git nginx
# Clone repository
git clone https://github.com/yourusername/ar-dashboard.git
cd ar-dashboard
# Create virtual environment
python3.10 -m venv venv
source venv/bin/activate
# Install Python dependencies
pip install -r requirements.txt
pip install gunicornCreate /etc/nginx/sites-available/ar-dashboard:
upstream django {
server 127.0.0.1:8000;
}
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://django;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /static/ {
alias /home/ubuntu/ar-dashboard/staticfiles/;
}
location /media/ {
alias /home/ubuntu/ar-dashboard/media/;
}
}Enable the site:
sudo ln -s /etc/nginx/sites-available/ar-dashboard /etc/nginx/sites-enabled/
sudo systemctl restart nginxCreate /etc/systemd/system/ar-dashboard.service:
[Unit]
Description=AR Dashboard Gunicorn Service
After=network.target
[Service]
Type=notify
User=ubuntu
WorkingDirectory=/home/ubuntu/ar-dashboard
ExecStart=/home/ubuntu/ar-dashboard/venv/bin/gunicorn \
--workers 4 \
--bind 127.0.0.1:8000 \
config.wsgi:application
Restart=on-failure
[Install]
WantedBy=multi-user.targetStart the service:
sudo systemctl daemon-reload
sudo systemctl start ar-dashboard
sudo systemctl enable ar-dashboardsudo apt install certbot python3-certbot-nginx
sudo certbot certonly --nginx -d yourdomain.comCreate PostgreSQL RDS instance:
- Engine: PostgreSQL 15
- Instance class: db.t3.small or larger
- Multi-AZ: Yes (for production)
- Backup retention: 30 days
Update .env with RDS endpoint.
- Connect your GitHub repository
- Create new app from repository
- Configure environment variables in dashboard
- Add PostgreSQL managed database
- Deploy
- Welcome page with suggested workflows
- Quick-start cards for different views
- Feature overview
- Navigation to all tools
- Drag-and-drop widgets (customizable layout)
- KPI summary cards
- Aging distribution pie chart
- Top customers bar chart
- Payment velocity analysis
- Customer health scores
- DSO trends
- Collection effectiveness index
- Cash flow forecasts
- Advanced filtering controls
- Real-time data filtering
- Export functionality (CSV, PDF)
- Pipeline status monitoring
- Active filter badges
- Industry-standard aging report
- Detailed customer breakdown
- Time bucket analysis
- Print-optimized layout
- Drill-down capabilities
# Daily backup at 2 AM
0 2 * * * pg_dump ar_dashboard | gzip > /backups/ar_dashboard_$(date +\%Y\%m\%d).sql.gz# View Django logs
tail -f /var/log/ar-dashboard/django.log
# View Gunicorn logs
journalctl -u ar-dashboard -f# Add to crontab for health monitoring
*/5 * * * * curl -f http://localhost:8000/health/ || systemctl restart ar-dashboardError: could not translate host name "db" to addressSolution: Ensure PostgreSQL is running and .env credentials are correct.
python manage.py collectstatic --noinputEnsure Dagster is running on port 3000:
dagster dev -f dagster_project/repository.pyCheck that URLs are properly configured and views are imported.
Ensure html2pdf.js is loaded from CDN and permissions are set correctly.
- Database Indexing: Add indexes to frequently queried columns
- Caching: Implement Redis caching for summary statistics
- Query Optimization: Use
select_related()andprefetch_related() - Pagination: Limit API responses to reasonable page sizes
- CDN: Serve static files from CDN in production
- Never commit
.envfiles - Use strong SECRET_KEY (generate with
django.core.management.utils.get_random_secret_key()) - Enable HTTPS in production
- Set
DEBUG=Falsein production - Use environment variables for all sensitive data
- Implement rate limiting on APIs
- Regular security updates for dependencies
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see LICENSE file for details.
For issues and questions:
- Open an issue on GitHub
- Check existing documentation
- Initial release
- Core dashboard functionality
- Interactive widgets
- Filtered dashboard with export
- Dagster pipeline integration
- Multi-view reports