Push Notifications Kit
Backend push notifications with device registration, sending, logging, and pluggable providers (FCM, OneSignal, AWS SNS, Pushy, Pusher Beams).
Quick reference
CLI commands
# Scaffold with defaults (NestJS + TypeORM + FCM)
npx @fivfold/api add push
# With explicit stack and provider
npx @fivfold/api add push --framework=express --orm=prisma --provider=onesignal
# Use MongoDB + Mongoose
npx @fivfold/api add push --framework=nestjs --orm=mongoose --database=mongodb
# Use Cosmos DB
npx @fivfold/api add push --orm=cosmos-sdk --database=cosmosdb --dry-run
# Dry run to preview files
npx @fivfold/api add push --dry-runOverview
The Push Notifications Kit is a backend-only module that scaffolds a complete push notification system for your Node.js application. It handles device registration, sending notifications to devices/users/topics, and optional audit logging. Unlike the Email and Kanban Kits, it does not include a frontend UI—your mobile app or PWA obtains push tokens and registers them with the backend.
The kit follows Hexagonal Architecture: a domain port (IPushNotificationService) defines the contract, and pluggable adapters implement it using third-party SDKs. You choose one provider at scaffold time (FCM, OneSignal, AWS SNS, Pushy, or Pusher Beams), and the generated code is ready to integrate with your Express or NestJS app. Supported stack combinations:
| Layer | Options |
|---|---|
| Framework | NestJS, Express |
| SQL | TypeORM (PostgreSQL, MySQL, MariaDB, MSSQL), Prisma |
| NoSQL | Mongoose (MongoDB), Prisma (MongoDB connector) |
| Cloud NoSQL | Azure Cosmos DB SDK, AWS DynamoDB SDK |
| Push Provider | FCM, OneSignal, AWS SNS, Pushy, Pusher Beams |
Backend-only Kit
The Push Notifications Kit scaffolds only backend code. Your frontend (React Native, Flutter, PWA, etc.) must request notification permission, obtain a device token from the platform, and call POST /api/push/subscribe to register it. The guide below covers backend setup; frontend integration is provider-specific.
Architecture
The kit is structured in layers, with clear separation between domain logic and infrastructure:
Layer structure
IPushNotificationService port interface and DTOs (SendNotificationDto, RegisterDeviceDto). Framework-agnostic.PushSubscription (device tokens per user) andPushNotificationLog (audit trail). TypeORM entities or Prisma models.IPushNotificationService using the vendor SDK (e.g. FcmPushAdapter uses firebase-admin). One adapter per provider.Swapping providers (e.g. FCM → OneSignal) requires re-scaffolding with --provider=onesignal or manually replacing the adapter file. The controller, service, and entities remain unchanged.
Supported providers
Choose one provider when scaffolding. Each has different setup requirements and capabilities:
| Provider | Package | Best for |
|---|---|---|
| fcm | firebase-admin | Android, iOS, Web. Free tier. Google ecosystem. |
| onesignal | axios (REST API) | Multi-platform, easy setup, free tier. |
| sns | @aws-sdk/client-sns | AWS-native, scalable, pay-per-use. |
| pushy | pushy | Reliable delivery, topics, status tracking. |
| pusher-beams | @pusher/push-notifications-server | Interests (topics), user targeting, simple API. |
Guide
Step-by-step backend integration (clients obtain tokens and call your API—there is no FivFold UI kit for Push). Select framework, ORM, and push provider in the sidebar for stack-specific instructions.
The Push API module provides entities, DTOs, services, controllers/routes, and a provider adapter. Platform icons indicate your current selection.
1Install / scaffold the module
Run npx @fivfold/api init first if you haven't. The push kit requires a provider (push notification service). Select your stack and provider above, then run:
npx @fivfold/api add pushWithout --provider, the CLI will prompt you to choose: FCM, OneSignal, AWS SNS, Pushy, or Pusher Beams.
2Generated file structure & wire into the app
Subsections below follow the framework and ORM from the stack sidebar (see AGENTS.md API tab §2–§3).
Generated file tree
push/
domain/
push.port.ts # IPushNotificationService interface
dto/
send-notification.dto.ts
register-device.dto.ts
send-to-topic.dto.ts
entities/
push-subscription.entity.ts
notification-log.entity.ts
adapters/
fcm-push.adapter.ts # Provider-specific implementation
push.controller.ts # NestJS controller with all push endpoints
push.service.ts # Business logic
push.module.ts # NestJS module (registers entities, controller, service, adapter)Import PushModule into AppModule
// src/app.module.ts
import { PushModule } from './modules/push/push.module';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
url: process.env.DATABASE_URL,
autoLoadEntities: true,
synchronize: process.env.NODE_ENV !== 'production',
}),
PushModule,
],
})
export class AppModule {}Add auth guard to the controller
In push.controller.ts, add your JWT guard and replace the getUser helper.
import { UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
@UseGuards(JwtAuthGuard)
@Controller('push')
export class PushController { ... }Run TypeORM migrations (production)
npx typeorm migration:generate src/migrations/AddPushModule -d src/data-source.ts
npx typeorm migration:run -d src/data-source.ts3API reference
REST endpoints
| Method | Path | Description |
|---|---|---|
| POST | /api/push/subscribe | Register device token for a user |
| DELETE | /api/push/subscribe/:token | Unregister device token |
| GET | /api/push/subscriptions | List user's registered devices |
| POST | /api/push/send/device | Send notification to a specific device token |
| POST | /api/push/send/user | Send notification to all devices of a user |
| POST | /api/push/send/topic | Send notification to a topic (FCM, Pushy, Pusher Beams) |
Request / response examples
Register a device (mobile app or web client calls this after obtaining a push token):
POST /api/push/subscribe
Content-Type: application/json
Authorization: Bearer <jwt>
{
"token": "fcm-or-apns-device-token-here",
"platform": "ios",
"metadata": { "appVersion": "1.0.0" }
}Send a notification to a user (admin or server-triggered):
POST /api/push/send/user
Content-Type: application/json
Authorization: Bearer <jwt>
{
"userId": "user-uuid",
"payload": {
"title": "New message",
"body": "You have a new message from John",
"data": { "type": "chat", "chatId": "123" },
"imageUrl": "https://example.com/image.png"
}
}Send to a topic (e.g. "news", "promotions"):
POST /api/push/send/topic
Content-Type: application/json
Authorization: Bearer <jwt>
{
"topic": "news",
"payload": {
"title": "Breaking news",
"body": "Check out our latest update"
}
}4Integration with frontend
You own the wiring
The step-by-step guides, environment variables, and dev-server proxy or rewrite examples are suggestions—not a mandated layout. You should read the generated files, your existing routes and auth, and your deployment topology, then choose URLs, origins, and headers that match your app. We encourage verifying every connection yourself before shipping.
Step-by-step: API ↔ browser (and ↔ UI)
This kit is backend-only: mobile and desktop clients call your API directly. Browsers and PWAs still need correct CORS when they hit a different origin than the API.
- Confirm routes — Ensure your Express app or Nest module exposes
/api/push(or your chosen prefix). If a web UI calls same-origin/api/..., its dev server must forward to this API. - CORS & clients — Native apps use HTTPS to your API (no CORS). For web or admin dashboards, allow the exact browser origins that will call
/api/push— not*in production. - Auth context — Resolve the current user in middleware or guards and pass
req.user.id(or equivalent) into Push services so list/create endpoints are scoped correctly. - Response shape — The kit UI expects specific prop shapes; map your entities in the client or add a thin BFF (see UI tab and the "Connecting UI" section below).
Connecting Push data to your user system
PushSubscription (and related log rows) store a user id for each device token. That id must be the same stable identifier you use elsewhere when sending notifications after domain events.
- Open push-subscription entity or model: align userId (or equivalent) with your User table PK or the subject you derive from JWT when registering devices.
- When calling send-to-user endpoints, the userId in the payload should resolve to the same keys stored on subscriptions.
- If you partition data by organization, filter subscriptions in the service layer so one admin cannot target another tenant’s users.
Inspect generated code
userId, ownerId, etc.) to your User table or IdP subject. Migrate or add FKs where needed—FivFold cannot know your prior schema.Environment variables
Examples only—replace with real secrets and URLs after reading the disclaimer above.
Database URL plus provider-specific credentials. For fcm:
DATABASE_URL=postgresql://user:password@localhost:5432/yourdb
FIREBASE_PROJECT_ID=your-project-id
FIREBASE_CLIENT_EMAIL=firebase-adminsdk-xxx@your-project.iam.gserviceaccount.com
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"Clients and the Push API
The Push Notifications Kit is backend-only. Your mobile app (React Native, Flutter, etc.) or web app (PWA with service worker) must implement the client side yourself:
- Request notification permission from the user
- Obtain a device token from the platform (FCM, APNs, Web Push)
- Call
POST /api/push/subscribewith the token and platform - Handle incoming notifications (foreground/background handlers)
For web push, use the Web Push API and a service worker. For mobile, use the native SDK (e.g. @react-native-firebase/messaging) to get the token, then register it with your backend.
5Third-party integrations
Provider fcm uses the vendor SDK or REST client wired in fcm-push.adapter.ts (e.g. firebase-admin for FCM, @aws-sdk/client-sns for SNS, @pusher/push-notifications-server for Pusher Beams). Inspect api/manifests/push.kit.json for the exact dependency set in this revision.
8Additional notes
Restrict who may call POST /api/push/send/*; validate userId and topics against your authorization rules. Rotate provider API keys on the same schedule as database credentials.
Domain port methods
The IPushNotificationService port defines the following methods. Provider adapters implement this interface.
| Method | Parameters | Return | Purpose |
|---|---|---|---|
| registerDevice | userId, dto | Promise<PushSubscription> | Register device token for a user |
| unregisterDevice | userId, token | Promise<void> | Unregister device token |
| sendToDevice | token, payload | Promise<SendResult> | Send notification to a specific device |
| sendToUser | userId, payload | Promise<SendResult> | Send to all devices of a user |
| sendToTopic | topic, payload | Promise<SendResult> | Send to topic (FCM, Pushy, Pusher Beams) |
| getSubscriptions | userId | Promise<PushSubscription[]> | List user's registered devices |
| logNotification | subscriptionId, messageId, status, ... | Promise<void> | Audit trail for sent notifications |
