Skip to main content

System Architecture

:::info Status Implemented — reflects docker-compose.yml, Caddyfile, and fastapi-backend/main.py. :::

Azan360 is one Python/FastAPI backend serving three built React frontends as static files, backed by PostgreSQL, an MQTT broker (EMQX) for device control, and Icecast for audio streaming.

Components

ComponentResponsibilityCommunicationTrust boundary
WebsitePublic marketing/info siteServed static by Nginx (prod) or Vite dev serverPublic, unauthenticated
Admin PanelMosque admin dashboard: broadcasts, prayer times, events, devices, memberships, audioREST (/api/v1), WebSocket (/ws)JWT-authenticated mosque admin
Super Admin PanelPlatform operator: approve devices, manage all mosquesREST (/api/v1)JWT-authenticated superadmin, hardened with 2FA
fastapi-backendAll business logic, WebSocket handlers, FFmpeg process management, MQTT publish/subscribe, push deliveryOwns all outbound integrationsSingle trust boundary — everything else talks through it
PostgreSQLSystem of record for mosques, users, memberships, devices, triggers, audit logsasyncpg, plain TCP, no pooler, pod-network onlyNot exposed publicly
EMQX (MQTT broker)Self-hosted; per-device credentials, command/event delivery to hardwareMQTT over TLSPer-device auth — see MQTT Protocol
IcecastAudio streaming server — one mount per mosque+roomHTTP source-client push (backend), HTTPS pull (listeners)Source push requires ICECAST_PASSWORD; listener pull is public

Data ownership

Every table lives in PostgreSQL, owned exclusively by fastapi-backend — no other service touches the database directly. See Database for the split between Alembic-owned and ensure_*-owned schema.

Authentication boundary

  • Browser/admin traffic — JWT bearer tokens issued by /api/v1/auth/*; see Authentication.
  • Device traffic (MQTT) — per-device EMQX credentials, provisioned at claim time; see MQTT Protocol and Device Authorization.
  • Live broadcast WebSocket — a shared static BROADCAST_TOKEN, not per-user; see Azaan Broadcast.
  • Stream pull (/stream/*) — public, unauthenticated at the Icecast layer; per-request gating exists at /api/v1/stream-auth/* for scoped tokens (see API Reference).

Local development

No Docker, no Caddy — Vite dev servers proxy /api and /ws to localhost:8082 directly. See Local Development.

Next