Product documentation

PixelCast — complete technical guide

PixelCast is a self-hosted or SaaS digital signage system: Django REST back end, real-time channels, a Vue 3 admin SPA, and a browser-based web player. This page describes how the repository is structured, how to run and configure it, and where to find APIs and operational tools.

Security: Never commit a real .env file. Use strong SECRET_KEY and DB_PASSWORD values in production, and keep DEBUG=False outside local development.
Docker: Development uses docker-compose.yml (Vite + Uvicorn hot reload). Production uses docker-compose.prod.yml (Nginx + Gunicorn/Uvicorn). The production frontend image serves this HTML under /documentation/.

1) Introduction

You can manage screens, templates, media, schedules, and device commands from the admin UI. Devices and web players talk to the same back end over HTTPS and WebSockets; heavy work (email, SMS, billing webhooks) runs through Celery workers backed by Redis.

Browser / player
Nginx (SPA + proxy)
Django (Gunicorn + Uvicorn)
PostgreSQL
+
Redis

2) How this documentation is served

Canonical copies of these pages live under documentation/ at the repository root. The same HTML and CSS are mirrored into frontend/public/documentation/ so Vite (dev) and the production build emit them under /documentation/ (e.g. /documentation/index.html). Nginx in the frontend container serves that path; short URLs /docs and /docs/changelog in the SPA redirect to the static files. After editing files under documentation/, copy them into frontend/public/documentation/ (or rebuild from a CI step that syncs both).

Files in the package

documentation/                    # source (edit here)
├── index.html
├── changelog.html
└── assets/
    ├── style.css
    └── screenshots/                # optional; figures hide if missing

frontend/public/documentation/      # shipped with the SPA build

For marketing and long-form guides, use the in-app blog. For interactive REST exploration, authenticated operators can use OpenAPI / Swagger at /api/docs/ (see below).

3) Architecture (verified stack)

Back end

  • Python 3.12, Django 5.2.x, Django REST Framework, djangorestframework-simplejwt
  • Django Channels (ASGI) for WebSockets; Redis channel layer in production-style deployments
  • Celery with Redis as broker and result backend
  • PostgreSQL 15 in Docker; SQLite optional for local experiments (USE_SQLITE=True)
  • drf-spectacular: schema at /api/schema/, Swagger UI at /api/docs/, ReDoc at /api/redoc/ (legacy Django routes /docs/ and /swagger/ also exist)

Front end & delivery

  • Vue 3, Vite, Pinia, Vue Router, Tailwind CSS, Chart.js (analytics charts)
  • Production: multi-stage Docker build (Node 20 → Nginx Alpine)
  • Nginx terminates HTTP, serves the SPA and static docs, and reverse-proxies /api/, /iot/, /ws/, /media/, etc.

The Django settings package is Screengram under app/Screengram/ (ROOT_URLCONF is Screengram.urls); product branding in the UI is PixelCast. IoT routes are mounted at /iot/ and (for backward compatibility) /public-iot/, both including the same signage URLs, while authenticated app traffic also uses /api/… for signage and related endpoints.

4) Repository layout

├── app/                         # Django project (manage.py lives here)
│   ├── Screengram/              # settings, ASGI/WSGI, root URLconf
│   ├── accounts/                # users, JWT, 2FA/TOTP, SSO hooks, invitations, RBAC
│   ├── analytics/               # dashboard metrics APIs
│   ├── api_docs/                # protected Swagger / ReDoc / OpenAPI views
│   ├── blog/                    # public blog API + platform admin content API
│   ├── bulk_operations/         # batch action endpoints
│   ├── commands/                # remote device commands API
│   ├── content_validation/      # upload validation helpers API
│   ├── core/                    # audit, backups, rate limits, system email, deployment helpers
│   ├── licensing/               # license enforcement, operator gateway, registry APIs
│   ├── log/                     # centralized error logging API + middleware
│   ├── notifications/         # email/SMS (Twilio) channels, Celery tasks
│   ├── saas_platform/           # tenants, Stripe, super-admin reporting
│   ├── setup/                   # installation wizard API
│   ├── signage/                 # screens, IoT, pairing, heartbeat (also mounted at /iot/)
│   ├── templates/               # template authoring, media, QR redirect routes
│   ├── tickets/                 # helpdesk (queues, SLA, operator bridge, platform APIs)
│   ├── tests/                   # pytest suite (shared under app/tests)
│   ├── Dockerfile
│   ├── entrypoint.sh
│   └── requirements.txt
├── frontend/                    # Vue 3 SPA, Vite, Nginx config, Dockerfiles
├── documentation/               # static HTML product docs (mirrored to frontend/public/documentation/)
├── docker-compose.yml           # dev: Vite 5173, Django 8000, db, redis
├── docker-compose.prod.yml      # prod: Nginx + Gunicorn/Uvicorn stack
├── install.sh
├── .env.example                 # env template (copy to .env)
├── requirements.txt             # mirrors app/requirements.txt for tooling
└── README.md

5) Requirements

Runtime & tooling

  • Docker Engine 24+ and Docker Compose v2 (recommended path)
  • Python 3.12+ if you run Django on the host
  • Node.js 20+ for front-end builds (matches frontend/Dockerfile)
  • PostgreSQL 15+ (or SQLite for dev only)
  • Redis 7+ for cache, Celery, and channel layer

Browser support (admin & player)

  • Current evergreen Chrome, Firefox, Safari, Edge
  • Players need WebSocket support for live template pushes

6) Installation

6a) Development with Docker (recommended)

  1. Clone and create environment

    cp .env.example .env
    # Edit SECRET_KEY, DB_PASSWORD, ALLOWED_HOSTS, CSRF_TRUSTED_ORIGINS, BASE_URL as needed
  2. Start the stack

    docker compose up --build

    Open the Vite dev app at http://localhost:5173. Django is available through the proxy at same-origin /api/ — do not point the browser at http://backend:8000 (that hostname exists only inside the Compose network).

6b) Production with Docker

docker compose -f docker-compose.prod.yml up -d --build

The production compose file maps the frontend container to host port 8080 (8080:80 on the frontend service). To use another host port, change that mapping (or terminate TLS on a reverse proxy and do not publish the container port publicly). Both frontend and backend attach to the external network dokploy-network when present—create it on the host if you deploy behind Traefik/Dokploy. Static documentation is baked into the frontend image from frontend/public/documentation/; avoid bind-mounting documentation/ unless you control that path on every host.

6c) Installer script

chmod +x install.sh && ./install.sh

6d) First-run wizard

After containers are healthy, open /install in the browser to complete database checks and create the first administrator. Setup APIs live under /api/setup/.

dbPostgreSQL 15 with a persistent volume
redisCache, Celery broker, Channels layer
backendDjango ASGI, migrations on boot
frontendDev: Vite; Prod: Nginx + built SPA + this HTML

7) Configuration (.env)

Compose loads only .env from the project root; .env.example is a template and is not loaded automatically. Mirror DB_* credentials into POSTGRES_* for the database container when using the bundled Postgres service.

# — excerpt; see .env.example for the full list —

# Django
SECRET_KEY=<generate-a-long-random-string>
DEBUG=False
ALLOWED_HOSTS=your.domain,localhost,127.0.0.1
CSRF_TRUSTED_ORIGINS=https://your.domain
BASE_URL=https://your.domain

# Database (Docker service name is usually `db`)
DB_HOST=db
DB_NAME=pixelcast_signage_db
DB_USER=pixelcast_signage_user
DB_PASSWORD=<your-secure-password>
DB_PORT=5432

# Redis / Celery
REDIS_HOST=redis
REDIS_PORT=6379
CELERY_BROKER_URL=redis://redis:6379/0
CELERY_RESULT_BACKEND=redis://redis:6379/0
USE_REDIS_CACHE=True

# Deployment mode: saas | self_hosted | hybrid
DEPLOYMENT_MODE=hybrid
PLATFORM_SAAS_ENABLED=True

# Stripe (SaaS billing — optional per deployment)
STRIPE_SECRET_KEY=
STRIPE_PUBLISHABLE_KEY=
STRIPE_WEBHOOK_SECRET=

# License / marketplace (see .env.example for full registry + grace tuning)
LICENSE_ENFORCEMENT_ENABLED=True
LICENSE_GATEWAY_BASE_URL=     # self-hosted installs (operator ↔ license service)
LICENSE_SERVER_URL=           # SaaS / gateway URL when applicable
CODECANYON_TOKEN=

# Optional integrations
OPENWEATHER_API_KEY=          # weather widget in templates
SSO_ENABLED=False             # SSO-ready account flows when True
Never commit real secrets Use UTC on servers for schedules Set PUBLIC_WEB_APP_URL for email links ANDROID_TV_APK_URL → GET /api/public/downloads/ CHANNEL_LAYERS_BACKEND=redis in real deployments

8) URLs, API & OpenAPI

These paths are defined in app/Screengram/urls.py and related URLconfs.

Common browser routes (Vue SPA)

  • / — marketing / landing
  • /login, /signup, /forgot-password, /reset-password, /install
  • /player — web player (pairing and playback)
  • /blog, /pricing, /data-center — public content
  • /docs — redirects to static product documentation
  • /dashboard, /screens, /templates, /schedules, /commands, /analytics, … — signed-in app
  • /super-admin/… — platform operator console (when your account is allowed)

API groups (see app/Screengram/urls.py)

/api/setup/                 # installation wizard
/api/health/               # JSON health probe
/api/public/downloads/     # Android TV APK URL JSON
/api/public/deployment/    # deployment metadata
/api/public/pricing/       # public pricing snapshot
/api/public/blog/          # public blog feed/content
/api/license/              # license activation & enforcement API
/api/license-registry/v1/  # license registry (telemetry / admin integrations)
/api/platform/blog/        # platform blog admin API
/api/platform/tickets/     # platform ticket admin API
/api/platform/             # SaaS super-admin (tenants, Stripe, reporting…)
/api/auth/…                # JWT, sessions, invitations (accounts.urls)
/api/…                     # signage, templates, commands, bulk_operations,
                           # content_validation, analytics (see each app’s urls)
/api/tickets/              # requester helpdesk API
/api/core/                 # audit, backup, infrastructure
/api/logs/                 # centralized error log ingestion
/api/admin/errors/         # admin error log API (DRF router)
/iot/ …                    # same signage IoT routes, same-origin for browsers
/public-iot/ …             # legacy alias for signage IoT URLs
/qr/<slug>/               # QR action redirects (templates)
/api/docs/                 # Swagger UI (authenticated)
/api/redoc/                # ReDoc (authenticated)
/api/schema/               # OpenAPI schema

Administrative API documentation is protected — you must sign in as a user who is allowed to view schema (see api_docs views). The JSON health check is lightweight and suitable for uptime monitors.

9) WebSockets & IoT paths

  • WebSockets: Nginx proxies /ws/ to Django Channels (upgrade headers in frontend/nginx.conf). Configure CHANNEL_LAYERS_BACKEND (and Redis) for production-style multi-worker setups.
  • IoT: Browsers and players should call same-origin /iot/… (build-time VITE_IOT_BASE_URL=/iot in Docker) so hostnames like backend:8000 never appear in the client.
  • Media: With local disk storage, Django serves uploads under /media/ even when DEBUG=False; Nginx is configured to proxy that path to the backend.

10) SaaS & deployment modes

  • DEPLOYMENT_MODE=self_hosted — single-tenant style; platform SaaS features follow settings.
  • DEPLOYMENT_MODE=saas — multi-tenant operation with super-admin tooling.
  • DEPLOYMENT_MODE=hybrid — common middle ground; PLATFORM_SAAS_ENABLED gates Stripe, tenant admin, and related APIs.

Stripe Checkout, customer portal, and webhooks are integrated under saas_platform. Per-plan Stripe Price IDs can be managed from the Super Admin pricing catalog (database-backed), not only from a single legacy env var.

11) Product features (what ships in-repo)

Signage core

  • Screen registry, grouping, online/offline heartbeats, pairing flows
  • Template editor (layers, widgets, live preview, push-to-screen)
  • Content library, upload validation, schedules (one-off and recurring)
  • Remote commands (reboot, refresh, screenshot, etc.) — API under commands, UI under /commands
  • Bulk operations API for batch work across entities

Platform & operations

  • RBAC roles, 2FA (TOTP), invitations, session management, audit logs; SSO-oriented settings when enabled
  • Analytics dashboards (uptime, commands, template usage, trends) backed by analytics
  • Tickets / helpdesk with queues, SLA, routing, attachments; optional operator bridge for external tooling
  • Notifications (email, SMS via Twilio) with encrypted channel settings; Celery-backed dispatch
  • Centralized error logging (log app) and super-admin log review
  • Backups, system email settings, license enforcement and registry APIs with offline grace
  • Public blog + platform blog tools; Data Center page for downloads (e.g. Android TV APK)
Dashboard screenshot
Example: main dashboard (image omitted if not bundled)

12) Operations, logs & updates

  • Application logs: Django, Gunicorn/Uvicorn, and Celery worker output (use docker compose logs).
  • Edge logs: Nginx access and error logs inside the frontend container.
  • Updates: Back up the database and media, pull new images or files, run migrations, rebuild the SPA if front-end assets changed, then restart services. Always read changelog.html for breaking changes.

Static assets / 500 errors after deploy

If the UI loads but assets fail, rebuild the front end and ensure Nginx is serving the new dist output. If API calls return 500, verify environment variables — especially database connectivity and SECRET_KEY.

13) Troubleshooting

net::ERR_NAME_NOT_RESOLVED for backend:8000: The browser cannot resolve Docker service names. The SPA must call same-origin /api (and /iot for device traffic) so Vite (dev) or Nginx (prod) proxies to Django. Rebuild the front end after changing any VITE_* variable and hard-refresh.
  • WebSocket disconnects: confirm Redis is healthy, /ws/ is proxied with upgrade headers, and firewalls allow long-lived connections.
  • CSRF errors on login: add your exact origin (scheme + host + port) to CSRF_TRUSTED_ORIGINS.
  • CORS: additional origins can be set via CORS_ALLOWED_ORIGINS in env (merged with defaults in settings).

14) Running tests

# Backend (pytest inside backend container)
docker compose exec backend pytest --cov

# Frontend unit tests
cd frontend && npm run test

# Frontend e2e
cd frontend && npx playwright test

15) FAQ

Is SQLite supported?

Yes for local experimentation via USE_SQLITE=True. Production should use PostgreSQL.

Where is the OpenAPI schema?

JSON/YAML at /api/schema/; interactive docs at /api/docs/ once authenticated.

Are front-end route guards a security boundary?

No. Authorization is enforced in Django and DRF. Hiding a menu item in Vue is UX only.

16) Support & changelog

Use the support channel provided with your license or marketplace purchase (for example, item comments on CodeCanyon). Custom development, third-party integrations, and managed hosting are outside standard item support unless separately agreed.

Open changelog.html for version history.