From f1d00233700e7a2d0c92b0a8d3b870276f9e1b45 Mon Sep 17 00:00:00 2001 From: interisti Date: Wed, 10 Jun 2026 11:27:40 +0400 Subject: [PATCH 1/3] #1133 add notification preferences to accounts spec --- .../endpoint/accounts/openapi.json | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/docs/api-reference/endpoint/accounts/openapi.json b/docs/api-reference/endpoint/accounts/openapi.json index c6705f7..a0fd847 100644 --- a/docs/api-reference/endpoint/accounts/openapi.json +++ b/docs/api-reference/endpoint/accounts/openapi.json @@ -499,6 +499,14 @@ "passkey_enabled": { "type": "boolean", "description": "Enable passkey authentication" + }, + "notification_preferences": { + "allOf": [ + { + "$ref": "#/components/schemas/NotificationPrefs" + } + ], + "description": "User's notification preferences across all notification types and delivery channels." } } }, @@ -1142,6 +1150,143 @@ "file", "content_type" ] + }, + "NotificationChannels": { + "type": "object", + "description": "Per-channel delivery toggles for a single notification type.", + "properties": { + "in_app": { + "type": "boolean", + "description": "Whether in-app notifications are delivered for this type.", + "example": true + }, + "email": { + "type": "boolean", + "description": "Whether email notifications are delivered for this type.", + "example": false + }, + "push": { + "type": "boolean", + "description": "Whether push notifications are delivered for this type.", + "example": true + } + }, + "required": [ + "in_app", + "email", + "push" + ] + }, + "NotificationTypePrefs": { + "type": "object", + "description": "Opt-in state and channel configuration for one notification type.", + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether the user receives notifications of this type at all. When false, channel toggles are ignored.", + "example": true + }, + "channels": { + "$ref": "#/components/schemas/NotificationChannels" + } + }, + "required": [ + "enabled", + "channels" + ] + }, + "NotificationQuietHours": { + "type": "object", + "description": "Time window during which notifications are suppressed. Times are interpreted in the configured timezone.", + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether quiet hours are active. When false, the time fields are ignored.", + "example": true + }, + "start": { + "type": "string", + "description": "Start of the quiet window in 24-hour HH:MM format.", + "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", + "example": "22:00" + }, + "end": { + "type": "string", + "description": "End of the quiet window in 24-hour HH:MM format.", + "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", + "example": "07:00" + }, + "timezone": { + "type": "string", + "description": "IANA timezone name used to interpret the start and end times.", + "example": "Europe/London" + } + }, + "required": [ + "enabled", + "start", + "end", + "timezone" + ] + }, + "NotificationPrefs": { + "type": "object", + "description": "A user's global notification preferences across all notification types and delivery channels.", + "properties": { + "task_status_changes": { + "allOf": [ + { + "$ref": "#/components/schemas/NotificationTypePrefs" + } + ], + "description": "Preferences for notifications when a task's status changes." + }, + "task_assignments": { + "allOf": [ + { + "$ref": "#/components/schemas/NotificationTypePrefs" + } + ], + "description": "Preferences for notifications when a task is assigned to the user." + }, + "task_mentions": { + "allOf": [ + { + "$ref": "#/components/schemas/NotificationTypePrefs" + } + ], + "description": "Preferences for notifications when the user is mentioned on a task." + }, + "task_watcher_updates": { + "allOf": [ + { + "$ref": "#/components/schemas/NotificationTypePrefs" + } + ], + "description": "Preferences for notifications about tasks the user is watching." + }, + "batch_mode": { + "type": "string", + "description": "How email notifications are grouped before delivery. 'realtime' sends immediately; 'hourly' and 'daily' send digests.", + "enum": [ + "realtime", + "hourly", + "daily" + ], + "example": "daily" + }, + "quiet_hours": { + "$ref": "#/components/schemas/NotificationQuietHours" + } + }, + "required": [ + "task_status_changes", + "task_assignments", + "task_mentions", + "task_watcher_updates", + "batch_mode", + "quiet_hours" + ] } } }, @@ -4227,6 +4372,9 @@ }, "profile_image": { "$ref": "#/components/schemas/UserProfileImage" + }, + "notification_preferences": { + "$ref": "#/components/schemas/NotificationPrefs" } }, "required": [ From 0cd5ad25055a44402a31fbb0a0b322eec16f825a Mon Sep 17 00:00:00 2001 From: interisti Date: Wed, 10 Jun 2026 11:28:04 +0400 Subject: [PATCH 2/3] #1133 add task mute/unmute endpoint specs in workspaces --- .../endpoint/workspaces/openapi.json | 366 +++++++++++------- 1 file changed, 224 insertions(+), 142 deletions(-) diff --git a/docs/api-reference/endpoint/workspaces/openapi.json b/docs/api-reference/endpoint/workspaces/openapi.json index edf615c..cffb57f 100644 --- a/docs/api-reference/endpoint/workspaces/openapi.json +++ b/docs/api-reference/endpoint/workspaces/openapi.json @@ -188,139 +188,139 @@ "x-resource-type": "service", "x-resource": "microstrate.workspaces.get.tasks", "parameters": [ - { - "name": "space_id", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "archived", - "in": "query", - "schema": { - "type": "boolean" - } - }, - { - "name": "scheduled", - "in": "query", - "schema": { - "type": "boolean" - } - }, - { - "name": "limit", - "in": "query", - "description": "How many maximum results should be returned", - "schema": { - "type": "integer", - "default": 300 - } - }, - { - "name": "offset", - "in": "query", - "description": "If there are more results than the limit, offset can be used to get to the next batch of results", - "schema": { - "type": "integer", - "default": 0 - } - }, - { - "name": "sort_by", - "in": "query", - "description": "Name of the field used for sorting the list of results", - "schema": { - "type": "string", - "default": "created_at" - } - }, - { - "name": "sort_order", - "in": "query", - "description":"Should the results be sorted in ascending or descending order relative to sort_by field", - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "asc" - } - }, - { - "name": "created_by", - "in": "query", - "description": "Exact match on the user ID of the task creator", - "schema": { - "type": "string" - } - }, - { - "name": "priority", - "in": "query", - "description": "Exact match on priority; comma-separated values to filter by priority", - "schema": { - "type": "string" - } - }, - { - "name": "status", - "in": "query", - "description": "Exact match on status; comma-separated values to filter by multiple statuses", - "schema": { - "type": "string" - } - }, - { - "name": "title", - "in": "query", - "description": "Term search on task title", - "schema": { - "type": "string" - } - }, - { - "name": "asignees", - "in": "query", - "description": "Comma-separated assignee IDs; at least one must match", - "schema": { - "type": "string" - } - }, - { - "name": "reporter", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "created_at", - "in": "query", - "description": "Filter by creation date. Use a single date or a range as `{start_date},{end_date}`", - "schema": { - "type": "string" - } - }, - { - "name": "updated_at", - "in": "query", - "description": "Filter by last-updated date. Use a single date or a range as `{start_date},{end_date}`", - "schema": { - "type": "string" - } - }, - { - "name": "scheduled_at", - "in": "query", - "description": "Filter by scheduled date. Use a single date or a range as `{start_date},{end_date}`", - "schema": { - "type": "string" - } - } + { + "name": "space_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "archived", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "scheduled", + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "limit", + "in": "query", + "description": "How many maximum results should be returned", + "schema": { + "type": "integer", + "default": 300 + } + }, + { + "name": "offset", + "in": "query", + "description": "If there are more results than the limit, offset can be used to get to the next batch of results", + "schema": { + "type": "integer", + "default": 0 + } + }, + { + "name": "sort_by", + "in": "query", + "description": "Name of the field used for sorting the list of results", + "schema": { + "type": "string", + "default": "created_at" + } + }, + { + "name": "sort_order", + "in": "query", + "description": "Should the results be sorted in ascending or descending order relative to sort_by field", + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc" + } + }, + { + "name": "created_by", + "in": "query", + "description": "Exact match on the user ID of the task creator", + "schema": { + "type": "string" + } + }, + { + "name": "priority", + "in": "query", + "description": "Exact match on priority; comma-separated values to filter by priority", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "Exact match on status; comma-separated values to filter by multiple statuses", + "schema": { + "type": "string" + } + }, + { + "name": "title", + "in": "query", + "description": "Term search on task title", + "schema": { + "type": "string" + } + }, + { + "name": "asignees", + "in": "query", + "description": "Comma-separated assignee IDs; at least one must match", + "schema": { + "type": "string" + } + }, + { + "name": "reporter", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "created_at", + "in": "query", + "description": "Filter by creation date. Use a single date or a range as `{start_date},{end_date}`", + "schema": { + "type": "string" + } + }, + { + "name": "updated_at", + "in": "query", + "description": "Filter by last-updated date. Use a single date or a range as `{start_date},{end_date}`", + "schema": { + "type": "string" + } + }, + { + "name": "scheduled_at", + "in": "query", + "description": "Filter by scheduled date. Use a single date or a range as `{start_date},{end_date}`", + "schema": { + "type": "string" + } + } ], "responses": { "200": { @@ -764,13 +764,72 @@ } } } + }, + "/workspaces/task/{task_id}/mute": { + "post": { + "summary": "Mute every notification for a task", + "operationId": "muteNotification", + "x-resource-type": "service", + "x-resource": "microstrate.workspaces.post.task-mute", + "parameters": [ + { + "name": "task_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/SuccessResponse" + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "delete": { + "summary": "Unmute every notification for a task", + "operationId": "unmuteNotification", + "x-resource-type": "service", + "x-resource": "microstrate.workspaces.delete.task-mute", + "parameters": [ + { + "name": "task_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/SuccessResponse" + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } } }, "components": { "schemas": { "SpaceStatus": { "type": "object", - "required": ["id", "name"], + "required": [ + "id", + "name" + ], "properties": { "id": { "type": "string" @@ -798,7 +857,10 @@ }, "CreateSpaceRequest": { "type": "object", - "required": ["id", "name"], + "required": [ + "id", + "name" + ], "properties": { "id": { "type": "string", @@ -835,7 +897,9 @@ }, "UpdateSpaceRequest": { "type": "object", - "required": ["id"], + "required": [ + "id" + ], "properties": { "id": { "type": "string" @@ -1011,7 +1075,9 @@ }, "CreateTaskRequest": { "type": "object", - "required": ["title"], + "required": [ + "title" + ], "properties": { "title": { "type": "string" @@ -1061,7 +1127,9 @@ }, { "type": "object", - "required": ["id"], + "required": [ + "id" + ], "properties": { "id": { "type": "string" @@ -1075,7 +1143,9 @@ }, "UpdateMultiTaskRequest": { "type": "object", - "required": ["tasks"], + "required": [ + "tasks" + ], "properties": { "tasks": { "type": "array", @@ -1150,7 +1220,9 @@ }, "CreateCommentRequest": { "type": "object", - "required": ["body"], + "required": [ + "body" + ], "properties": { "body": { "type": "string", @@ -1198,7 +1270,9 @@ }, "CommentReactionRequest": { "type": "object", - "required": ["reaction"], + "required": [ + "reaction" + ], "properties": { "reaction": { "type": "object", @@ -1228,6 +1302,14 @@ } }, "responses": { + "SuccessResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + }, "BadRequest": { "description": "Bad Request", "content": { @@ -1273,4 +1355,4 @@ } } } -} +} \ No newline at end of file From d0427eb69d86b2b4c2cc4276bb7a63e4dbabde61 Mon Sep 17 00:00:00 2001 From: interisti Date: Mon, 29 Jun 2026 17:20:30 +0400 Subject: [PATCH 3/3] #1131 add user notifications endpoints --- .../endpoint/accounts/openapi.json | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/docs/api-reference/endpoint/accounts/openapi.json b/docs/api-reference/endpoint/accounts/openapi.json index a0fd847..ff7fa23 100644 --- a/docs/api-reference/endpoint/accounts/openapi.json +++ b/docs/api-reference/endpoint/accounts/openapi.json @@ -5806,6 +5806,179 @@ } } } + }, + "/accounts/users/notifications": { + "get": { + "summary": "List user notifications", + "description": "Retrieves the list of notifications for the user", + "operationId": "listNotifications", + "tags": [ + "User Management" + ], + "x-resource-type": "service", + "x-resource": "microstrate.accounts.get.list-user-notifications", + "responses": { + "200": { + "description": "Notifications retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "viewed": { + "type": "boolean" + }, + "refs": { + "type": "array", + "items": { + "type": "object", + "required": [ + "label", + "ref_id", + "type", + "url" + ], + "properties": { + "label": { + "type": "string" + }, + "ref_id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "url": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "No Notifications found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + } + }, + "/accounts/users/notifications/viewed": { + "patch": { + "summary": "Set user notification as viewed", + "description": "Updates status of the user notification as viewed", + "operationId": "patchNotificationViewed", + "tags": [ + "User Management" + ], + "x-resource-type": "service", + "x-resource": "microstrate.accounts.patch.user-notification-viewed", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "subject": { + "type": "string", + "description": "Subject of the notificaiton" + } + }, + "required": [ + "subject" + ] + } + } + } + }, + "responses": { + "200": { + "description": "Notification successfully updated as viewed", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "object" + } + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "description": "No Notifications found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + } } } } \ No newline at end of file