From cf7f4269ccc66bae21a6c6afa24900cc50885319 Mon Sep 17 00:00:00 2001 From: Sachintechjoomla <92356209+Sachintechjoomla@users.noreply.github.com> Date: Fri, 12 Dec 2025 18:32:07 +0530 Subject: [PATCH] Issue#250717 Feat: In-App Notifications in Notification Service --- docs/notifications-service/1_about.md | 2 +- docs/notifications-service/2_features.md | 2 +- .../6_database-schema.md | 22 +- docs/notifications-service/7_api-docs.md | 261 ++++++++++++++++++ .../assets/inappnotification_db.png | Bin 0 -> 33921 bytes 5 files changed, 284 insertions(+), 3 deletions(-) create mode 100644 docs/notifications-service/assets/inappnotification_db.png diff --git a/docs/notifications-service/1_about.md b/docs/notifications-service/1_about.md index 50d69b1..a04c9e9 100644 --- a/docs/notifications-service/1_about.md +++ b/docs/notifications-service/1_about.md @@ -4,5 +4,5 @@ sidebar_position: 1 # About -Notification Service is designed to deliver messages to users swiftly and effectively. By supporting a range of notification types like SMS, push notifications and email, this service ensures that user will receive timely updates through their preferred communication channels. +Notification Service is designed to deliver messages to users swiftly and effectively. By supporting a range of notification types like SMS, push notifications, inApp and email, this service ensures that user will receive timely updates through their preferred communication channels. This service is vital for maintaining user engagement and keeping them informed about key events and activities within your application or system. \ No newline at end of file diff --git a/docs/notifications-service/2_features.md b/docs/notifications-service/2_features.md index eb719c7..323f1e2 100644 --- a/docs/notifications-service/2_features.md +++ b/docs/notifications-service/2_features.md @@ -9,7 +9,7 @@ title: Notification Service Features Seamlessly manage and distribute large volumes of notifications using RabbitMQ. ### 2. Multiple Delivery Modes -Choose from various notification methods, including SMS, email, and push notifications. +Choose from various notification methods, including SMS, email, inApp and push notifications. ### 3. Customizable Templates Personalize notifications with adaptable templates to meet specific needs. diff --git a/docs/notifications-service/6_database-schema.md b/docs/notifications-service/6_database-schema.md index 2ce7f25..e2a09fd 100644 --- a/docs/notifications-service/6_database-schema.md +++ b/docs/notifications-service/6_database-schema.md @@ -52,4 +52,24 @@ sidebar_position: 6 | recipient | character varying(255) | Recipient of the notification | | error | character varying(255) | Error message, if any | -![NotificationLogs](assets/notification_db2.png) \ No newline at end of file +![NotificationLogs](assets/notification_db2.png) +#### InAppNotification #### + +| Column Name | Data Type | Description | +|-------------|--------------------------|-----------------------------------------------------------------------------------| +| id | uuid | Unique identifier (Primary Key) | +| userId | uuid | ID of the user who is the recipient of the in-app notification. | +| action_key | character varying (255) | "Key associated with the action (e.g., references NotificationActionTemplates.key)." | +| org_code | character varying(255) | Optional organization code. | +| context | character varying(255) | "Context or purpose of the notification (e.g., 'task_assignment')." | +| title | character varying(255) | Title of the in-app notification. | +| message | text | Full content/body of the in-app notification. | +| link | character varying(500) | Optional URL or link associated with the notification action | +| metadata | jsonb | Optional JSON data for extra context or dynamic content. | +| isRead | boolean | Flag indicating if the user has read the notification (default: false) | +| createdAt | timestamp with time zone | Timestamp for when the notification was created. | +| readAt | timestamp with time zone | Timestamp for when the notification was marked as read. | +| expiresAt | timestamp with time zone | Optional timestamp after which the notification should be considered expired/removed. | + + +![inAppNotification](assets/inappnotification_db.png) diff --git a/docs/notifications-service/7_api-docs.md b/docs/notifications-service/7_api-docs.md index 89e652e..a6cabe2 100644 --- a/docs/notifications-service/7_api-docs.md +++ b/docs/notifications-service/7_api-docs.md @@ -372,3 +372,264 @@ sidebar_position: 7 "name": "projects/PROJECT_ID/messages/0:1618924844212%6e23a5c0f9e1a1e8" } ``` + + +# In-App Notifications - API & Integration Guide + +This document explains how to use the new in-app notifications in the Notification Service. + +## Endpoints + +- Create in-app notification (raw or template-based) + - POST `notification/inApp` +- List notifications with filters and pagination + - GET `notification/inApp?userId={uuid}&status=unread|read|all&page=1&limit=20` +- Count unread (reuse list with `limit=0`) + - GET `notification/inApp?userId={uuid}&status=unread&limit=0` +- Mark read (single or all) + - PATCH `notification/inApp/mark-read` + +All endpoints require `Authorization: Bearer ` header (Swagger auth key `access-token`). + +--- + +## Create (Raw) + +POST `notification/inApp` + +Body: +```json +{ + "userId": "c12fa913-6fc1-4e90-bd44-2c75724f2b3c", + "title": "Task Completed", + "message": "Your review task is completed.", + "link": "https://app.example.com/tasks/T-9001", + "metadata": { "taskId": "T-9001" }, + "tenant_code": "TENANT1", + "org_code": "ORG1", + "expiresAt": "2026-01-01T00:00:00.000Z" +} +``` + +Notes: +- `title` is required only when neither `templateId` nor `key` is provided. +- `message` (body) is stored at create time from template and replacements (if provided). List returns stored message directly. +- Optional fields: `link`, `metadata`, `tenant_code`, `org_code`, `expiresAt`. + +--- + +## Create (Template-based) + +POST `notification/inApp` + +Body: +```json +{ + "userId": "c12fa913-6fc1-4e90-bd44-2c75724f2b3c", + "templateId": "0d3b4b24-8a00-4f1d-9a1c-2f6f1c5f2b11", + "replacements": { + "userName": "Sachin", + "{taskId}": "T-9001" + }, + "metadata": { "priority": "high" } +} +``` + +Rules: +- The template is taken from `NotificationActionTemplates` with `type='inApp'`. +- Placeholders in the template subject/body/link are replaced by `replacements`. + - Keys can be provided either with braces (`"{userName}"`) or without (`"userName"`). +- If both `templateId` and raw `title/message` are provided, the template takes precedence. + +--- + +## Create (Action-based, consistent with Email/SMS/Push) + +POST `notification/inApp` + +Body: +```json +{ + "userId": "c12fa913-6fc1-4e90-bd44-2c75724f2b3c", + "context": "USER", + "key": "OnRegister", + "replacements": { + "userName": "Sachin" + }, + "metadata": { "role": "superuser" } +} +``` + +Rules: +- We resolve `NotificationActions` by `context` and `key`, then pick the `NotificationActionTemplates` with `type='inApp'`. +- Placeholders are replaced using `replacements`. +- We store `context`, `key`, and resolved fields; template is used transiently at create time. + +--- + +## Create (Key-only) + +POST `notification/inApp` + +Body: +```json +{ + "userId": "c12fa913-6fc1-4e90-bd44-2c75724f2b3c", + "key": "OnRegister", + "replacements": { "userName": "Sachin" } +} +``` + +Rules: +- If `key` resolves to a single action, we use that. If multiple actions share the same key, provide `context` as well. +- We fetch the in-app template for the resolved action and perform placeholder replacement. + +--- + +## Create (Send-structure, bulk over recipients) + +POST `notification/inApp` + +Curl: +```bash +curl -X POST http://localhost:4000/notification/inApp \ + -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \ + -d '{ + "context":"USER", + "key":"OnRegister", + "replacements":{"userName":"Sachin"}, + "inApp": { "receipients": ["", ""] } + }' +``` + +Behavior: +- For each userId in `inApp.receipients`, the service resolves the action/template and creates an in-app record with stored title/message/link and metadata. +- Response returns `{ inApp: { data: [{recipient, id}, ...] } }`. + +## List + +GET `notification/inApp?userId={uuid}&status=unread|read|all&offset=0&limit=20` + +Examples: +``` +GET notification/inApp?userId=c12f...&status=unread&offset=0&limit=20 +GET notification/inApp?userId=c12f...&status=read +GET notification/inApp?userId=c12f... (defaults to status=all) +``` + +Response: +```json +{ + "id": "api.send.notification", + "responseCode": "OK", + "result": { + "data": [ + { + "id": "7f7e6b10-5bdc-4f8b-bf4b-3e4f11a1b2c3", + "userId": "c12f...", + "title": "Task Completed", + "message": "Your review task is completed.", + "link": "https://app.example.com/tasks/T-9001", + "metadata": { "taskId": "T-9001" }, + "isRead": false, + "createdAt": "2025-12-05T10:30:00.000Z", + "readAt": null, + "expiresAt": null + } + ], + "count": 1, + "offset": 0, + "limit": 20 + } +} +``` + +--- + +## Count Unread + +GET `notification/inApp?userId={uuid}&status=unread&limit=0` + +Response: +```json +{ + "id": "api.send.notification", + "responseCode": "OK", + "result": { "count": 3 } +} +``` + +--- + +## Mark Read + +PATCH `notification/inApp/mark-read` + +- Mark single: +```json +{ "notificationId": "7f7e6b10-5bdc-4f8b-bf4b-3e4f11a1b2c3" } +``` + +- Mark all for a user: +```json +{ "userId": "c12fa913-6fc1-4e90-bd44-2c75724f2b3c", "markAll": true } +``` + +Responses: +- Success (single): +```json +{ "updated": 1, "message": "Notification marked as read" } +``` + + +--- + +## Logging + +All in-app operations write to `notificationLogs` for audit: +- Create (raw or template): `type='inApp'`, `action='create'`, `subject=title`, `recipient=userId` +- Mark read (single): `type='inApp'`, `action='mark-read-single'`, body includes notificationId +- Mark read (all): `type='inApp'`, `action='mark-read-all'`, body includes affected count and userId + +Use these logs for tracing, analytics, and support. + +--- + +## Kafka Integration (optional) + +If you publish to Kafka to create in-app notifications, use the unified service topic: +- `notifications` + +Message formats: + +1) Raw create (channel discriminator) +```json +{ + "channel": "inApp", + "userId": "c12fa913-6fc1-4e90-bd44-2c75724f2b3c", + "title": "Task Completed", + "message": "Your review task is completed.", + "link": "https://app.example.com/tasks/T-9001", + "metadata": { "taskId": "T-9001" }, + "tenant_code": "TENANT1", + "org_code": "ORG1", + "expiresAt": "2026-01-01T00:00:00.000Z", + "traceId": "d9f7a1a0-6e4f-4a44-a9d0-1234567890ab" +} +``` + +2) Key-based create (channel discriminator) +```json +{ + "channel": "inApp", + "userId": "c12fa913-6fc1-4e90-bd44-2c75724f2b3c", + "key": "OnRegister", + "context": "USER", + "replacements": { + "userName": "Sachin", + "{taskId}": "T-9001" + }, + "metadata": { "priority": "high" }, + "traceId": "d9f7a1a0-6e4f-4a44-a9d0-1234567890ab" +} +``` diff --git a/docs/notifications-service/assets/inappnotification_db.png b/docs/notifications-service/assets/inappnotification_db.png new file mode 100644 index 0000000000000000000000000000000000000000..16d87c9ce9ffde59caa7598df3634d2cd4ab739e GIT binary patch literal 33921 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

o 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 LK%-FI=F