Self-hosted web push infrastructure for teams that want direct control over subscribers, campaigns, scheduling, analytics, and operational ownership.
Contributing | Security | Runbook | Sponsor
AmaNotify is packaged as a standalone product repository, not a recycled client handoff. The goal is simple: own the push stack, keep the data in-house, and run campaigns without SaaS lock-in.
AmaNotify is a self-hosted web push platform built around the full operator workflow:
- capture and manage browser subscriptions
- segment audiences and create reusable templates
- run or schedule campaigns
- inspect logs, exports, and dashboard analytics
- keep the infrastructure, credentials, and deployment decisions inside your environment
| Area | What AmaNotify provides |
|---|---|
| Public surface | Subscription API, VAPID key endpoint, prompt config, asset hosting |
| Operator surface | Admin console for campaigns, segments, subscribers, logs, exports, and settings |
| Delivery engine | Queue-backed dispatching, scheduled sends, push workers, delivery persistence |
| Storage | PostgreSQL for product data and logs, Redis for queue orchestration |
| Hosting model | Self-hosted, infrastructure-owned, deployment-agnostic |
| Capability | Included in this repo |
|---|---|
| Subscriber management | Public subscribe / unsubscribe / tag updates, admin listing, detail views, exports |
| Campaign operations | Create, edit, send, cancel, inspect logs, review delivery stats |
| Audience targeting | Segment definitions and audience preview |
| Scheduling | Queue-backed delayed sends and orchestration |
| Analytics | Dashboard metrics, growth endpoint, delivery summaries |
| Prompt customization | Editable pre-prompt banner copy, colors, timing, and optional logo |
| Browser SDK assets | push-client.js and service-worker.js integration path |
| Operations | Health checks, metrics, migration checks, backup scripts, restore smoke checks |
| Why it exists | Why it matters |
|---|---|
| Infrastructure ownership | Your VAPID keys, queues, subscriber records, and delivery logs stay in your stack |
| Product honesty | The repo does not pretend to be a hosted SaaS or a one-click platform when it is not |
| Practical surface area | You get auth, analytics, exports, and operational scripts in the same codebase |
| Reusable packaging | No client-specific branding, domains, credentials, or deployment leftovers in tracked docs |
| Use case | Fit |
|---|---|
| Product updates and release announcements | Reusable templates, campaign stats, and controlled rollout scheduling |
| SaaS lifecycle messaging | Tag-based segmentation by locale, plan, or environment |
| Content and media notifications | Self-hosted delivery from your own domain and infrastructure |
| Internal platforms | Push operations without sending product data to an external notification vendor |
AmaNotify splits the system into a public integration surface and a protected operator surface.
flowchart LR
Site["Your website or web app"] --> SDK["AmaNotify browser SDK<br/>service-worker.js + push-client.js"]
SDK --> PublicAPI["Public API<br/>/api/public/*"]
PublicAPI --> DB["PostgreSQL<br/>subscribers, templates, campaigns, logs"]
PublicAPI --> Redis["Redis + BullMQ<br/>dispatch, send, cleanup queues"]
Admin["AmaNotify admin panel"] --> AdminAPI["Admin API<br/>/api/admin/*"]
AdminAPI --> DB
AdminAPI --> Redis
Redis --> Worker["Push dispatcher / worker / scheduler"]
Worker --> PushProviders["Browser push services"]
PushProviders --> Users["Subscriber devices"]
AdminAPI --> Metrics["Health + metrics + exports"]
- A website registers the service worker and stores subscriptions through the public API.
- Operators manage templates, segments, campaigns, settings, and exports through the admin console.
- Campaigns are dispatched through Redis and BullMQ, executed by push workers, and logged into PostgreSQL.
- Operators inspect delivery progress, queue health, analytics, and restore paths from the same stack.
| Layer | Technologies |
|---|---|
| Backend | Node.js, TypeScript, Express, Zod, JWT, Winston |
| Queueing | Redis, BullMQ, scheduled dispatch orchestration |
| Database | PostgreSQL, migrations via node-pg-migrate |
| Admin UI | React, Vite, React Query, React Hook Form, Zustand, Tailwind CSS |
| Browser integration | Service Worker API, Notifications API, Fetch API |
| Operations | GitHub Actions, Docker Compose for local services, Nginx reference config |
.
|-- admin-panel/ # React admin console
|-- backend/ # API, scheduler, worker, auth, analytics, exports
|-- client-sdk/ # Browser SDK assets
|-- docs/ # Product and operations documentation
|-- nginx/ # Reverse proxy example
|-- scripts/ # Backup and maintenance scripts
`-- docker-compose.dev.yml
- Node.js 20+
- npm
- Docker Desktop or another Docker runtime
docker compose -f docker-compose.dev.yml up -dPowerShell:
Copy-Item backend/.env.example backend/.envBash:
cp backend/.env.example backend/.envcd backend
npm ci
npm run generate-vapidPaste the generated keys into backend/.env.
npm run migrate
npm run create-admin -- --email admin@example.com --password "ChangeThisPassword123!"npm run devcd admin-panel
npm ci
npm run devDefault local endpoints:
- API:
http://localhost:3000 - Admin UI:
http://localhost:5173
AmaNotify currently ships with:
docker-compose.dev.ymlfor local PostgreSQL and Redisnginx/amanotify.confas a hardened reverse-proxy example- operational scripts for backup rotation, restore smoke checks, and log partition maintenance
What is intentionally not in this repo yet:
- a production-ready full-stack Docker Compose bundle
- Kubernetes manifests
- a hosted control plane
That is deliberate. The repository is honest about its current deployment surface instead of shipping placeholder infrastructure.
The backend environment template lives in backend/.env.example.
| Variable | Purpose |
|---|---|
DATABASE_URL |
Primary PostgreSQL connection string |
REDIS_URL |
Queue and scheduler connection |
VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY |
Browser push authentication keys |
VAPID_SUBJECT |
Contact identity for VAPID |
JWT_SECRET |
Admin auth signing secret |
PUBLIC_CORS_ORIGINS |
Allow-list for public subscription calls |
LOG_FILE / LOG_LEVEL |
Runtime logging configuration |
ALERT_WEBHOOK_URL |
Optional alert sink |
Operational docs
docs/admin-access.mddocs/operations-runbook.mddocs/restore-playbook.mddocs/alerts.mddocs/ci.mddocs/contributing.mddocs/security.mdclient-sdk/README.mdGeneral.mdfor the deeper implementation spec
- Self-hosted by default: subscriber data, delivery logs, and campaign history stay in your stack.
- Admin endpoints are protected by JWT auth and auth rate limiting.
- Public subscription endpoints respect an explicit CORS allow-list.
- Health and metrics exist for operators without forcing third-party monitoring SaaS.
- VAPID keys are generated locally and never hardcoded in the repository.
If you discover a vulnerability, follow docs/security.md.
- Admin auth, templates, segments, campaigns, logs, and exports
- Queue-backed scheduling and delivery orchestration
- Analytics, health checks, metrics, and backup smoke tooling
- Browser SDK and editable pre-prompt banner
- Production-grade container bundle for the whole stack
- Richer delivery observability and operator dashboards
- More campaign automation triggers and integration hooks
- Harder multi-environment packaging for public releases
Contributions are welcome if they improve AmaNotify as a product.
Start with docs/contributing.md for setup, scope, and review expectations.
AmaNotify is available under AGPL-3.0, with commercial licensing available by direct arrangement with the maintainer.
If AmaNotify helps you keep push infrastructure in-house, support the project here:
- GitHub Sponsors: https://github.com/sponsors/AmaLS367