feat(social): add friends, private chats, inbox and music sharing
ci / module boundaries / boundaries (push) Successful in 7s
ci / api / api (push) Successful in 1m9s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m8s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m23s
ci / db / db (push) Successful in 2m29s
ci / ts / ts (packages + web) (push) Successful in 2m55s

This commit is contained in:
mrleo1nid committed 2026-10-23 03:19:29 +03:00
1 parent f1528de948
commit 0a05bfe2cd
43 files changed
+2828 -389

No files matched your search

+139
View File
@@ -22,6 +22,88 @@ tags:
security:
- bearerAuth: []
paths:
/api/v1/me/social:
get:
operationId: getSocial
tags: [me]
description: Friends, incoming/outgoing requests, own blocks and up to 100 notifications, unread first. No private account fields.
responses:
'200':
description: Social inbox
content:
application/json:
schema: {$ref: '#/components/schemas/SocialInbox'}
default: {$ref: '#/components/responses/Problem'}
/api/v1/me/social/people:
get:
operationId: searchPeople
tags: [me]
parameters:
- in: query
name: q
required: true
schema: {type: string, minLength: 2, maxLength: 80}
responses:
'200':
description: Up to 30 people, excluding blocked accounts and either direction of personal blocking
content:
application/json:
schema:
type: array
items: {$ref: '#/components/schemas/SocialPerson'}
default: {$ref: '#/components/responses/Problem'}
/api/v1/me/social/actions:
post:
operationId: socialAction
tags: [me]
description: Request is idempotent; accept is recipient-only. Remove cancels, declines or unfriends. Block removes friendship. Unblock never restores it. Read chat acknowledges only messages through up_to_seq. Read notification uses notification ID as target_id.
requestBody:
required: true
content:
application/json:
schema: {$ref: '#/components/schemas/SocialAction'}
responses:
'204': {description: Applied}
default: {$ref: '#/components/responses/Problem'}
/api/v1/me/social/chats/{peerId}:
parameters:
- in: path
name: peerId
required: true
schema: {type: string, format: uuid}
get:
operationId: getDirectMessages
tags: [me]
description: Last 50 messages in ascending sequence order. Before loads older history. Requires current friendship, never marks messages read.
parameters:
- in: query
name: before
schema: {type: integer, format: int64, minimum: 1}
responses:
'200':
description: Message page
content:
application/json:
schema:
type: array
items: {$ref: '#/components/schemas/DirectMessage'}
default: {$ref: '#/components/responses/Problem'}
post:
operationId: sendDirectMessage
tags: [me]
description: Friends only. Client-generated UUID makes retries idempotent; changed payload for the same ID returns 409. Playlist attachment is its active share UUID; track attachment is a catalog UUID. No arbitrary URLs.
requestBody:
required: true
content:
application/json:
schema: {$ref: '#/components/schemas/SendDirectMessage'}
responses:
'200':
description: Stored message
content:
application/json:
schema: {$ref: '#/components/schemas/DirectMessage'}
default: {$ref: '#/components/responses/Problem'}
/api/v1/admin/server/updates:
get:
operationId: getServerUpdates
@@ -1994,6 +2076,63 @@ components:
schema:
$ref: "#/components/schemas/Problem"
schemas:
SocialPerson:
type: object
required: [id, username, display_name, relationship, unread]
properties:
id: {type: string, format: uuid}
username: {type: string}
display_name: {type: string}
relationship: {type: string, enum: [none, incoming, outgoing, friend, blocked]}
unread: {type: integer}
SocialNotification:
type: object
required: [id, actor_id, actor_name, kind, created_at, read]
properties:
id: {type: string, format: uuid}
actor_id: {type: string, format: uuid}
actor_name: {type: string}
kind: {type: string, enum: [friend_request, friend_accepted, message, music]}
created_at: {type: string, format: date-time}
read: {type: boolean}
SocialInbox:
type: object
required: [people, notifications, unread]
properties:
people:
type: array
items: {$ref: '#/components/schemas/SocialPerson'}
notifications:
type: array
items: {$ref: '#/components/schemas/SocialNotification'}
unread: {type: integer}
SocialAction:
type: object
required: [action, target_id]
properties:
action: {type: string, enum: [request, accept, remove, block, unblock, read_chat, read_notification]}
target_id: {type: string, format: uuid}
up_to_seq: {type: integer, format: int64, minimum: 1}
SendDirectMessage:
type: object
required: [id, text, attachment_kind]
properties:
id: {type: string, format: uuid}
text: {type: string, maxLength: 4000}
attachment_kind: {type: string, enum: [none, track, playlist]}
attachment_id: {type: string, format: uuid}
DirectMessage:
type: object
required: [id, seq, sender_id, text, attachment_kind, created_at, read]
properties:
id: {type: string, format: uuid}
seq: {type: integer, format: int64}
sender_id: {type: string, format: uuid}
text: {type: string}
attachment_kind: {type: string, enum: [none, track, playlist]}
attachment_id: {type: string, format: uuid}
created_at: {type: string, format: date-time}
read: {type: boolean}
ServerSource:
type: object
required: [id, name, url]