export function plazaOpenApiExtensions() { const dataResponse = (description) => ({ description, content: { 'application/json': { schema: { $ref: '#/components/schemas/DataEnvelope' }, }, }, }); const errorResponse = (description) => ({ description, content: { 'application/json': { schema: { $ref: '#/components/schemas/ErrorResponse' }, }, }, }); return { tags: [{ name: 'Plaza' }, { name: 'Plaza Ops' }], paths: { '/plaza/v1/feed': { get: { tags: ['Plaza'], summary: 'Get plaza feed (hot or new)', parameters: [ { name: 'sort', in: 'query', schema: { type: 'string', enum: ['hot', 'new'] } }, { name: 'category', in: 'query', schema: { type: 'string' } }, { name: 'cursor', in: 'query', schema: { type: 'string' } }, { name: 'limit', in: 'query', schema: { type: 'integer', maximum: 50 } }, ], responses: { 200: dataResponse('Feed page') }, }, }, '/plaza/v1/categories': { get: { tags: ['Plaza'], summary: 'List plaza categories', responses: { 200: dataResponse('Category list') }, }, }, '/plaza/v1/posts/{postId}': { get: { tags: ['Plaza'], summary: 'Get published plaza post', parameters: [{ $ref: '#/components/parameters/PostId' }], responses: { 200: dataResponse('Post detail'), 404: errorResponse('Post not found or hidden'), }, }, patch: { tags: ['Plaza'], summary: 'Update own plaza post metadata', parameters: [{ $ref: '#/components/parameters/PostId' }], requestBody: { required: true, content: { 'application/json': { schema: { $ref: '#/components/schemas/UpdatePlazaPostRequest' }, }, }, }, responses: { 200: dataResponse('Updated post') }, }, delete: { tags: ['Plaza'], summary: 'Hide own plaza post', parameters: [{ $ref: '#/components/parameters/PostId' }], responses: { 200: dataResponse('Hidden post') }, }, }, '/plaza/v1/posts': { post: { tags: ['Plaza'], summary: 'Publish an online MindSpace publication to plaza', requestBody: { required: true, content: { 'application/json': { schema: { $ref: '#/components/schemas/CreatePlazaPostRequest' }, }, }, }, responses: { 201: dataResponse('Created plaza post'), 409: errorResponse('Already published to plaza'), }, }, }, '/plaza/v1/posts/{postId}/reactions': { post: { tags: ['Plaza'], summary: 'Add like, collect, or share reaction', parameters: [{ $ref: '#/components/parameters/PostId' }], requestBody: { required: true, content: { 'application/json': { schema: { $ref: '#/components/schemas/PlazaReactionRequest' }, }, }, }, responses: { 200: dataResponse('Reaction applied') }, }, }, '/plaza/v1/posts/{postId}/reactions/{type}': { delete: { tags: ['Plaza'], summary: 'Remove like or collect reaction', parameters: [ { $ref: '#/components/parameters/PostId' }, { $ref: '#/components/parameters/ReactionType' }, ], responses: { 200: dataResponse('Reaction removed') }, }, }, '/plaza/v1/posts/{postId}/comments': { get: { tags: ['Plaza'], summary: 'List post comments', parameters: [ { $ref: '#/components/parameters/PostId' }, { name: 'parent_id', in: 'query', schema: { type: 'string' } }, { name: 'cursor', in: 'query', schema: { type: 'string' } }, ], responses: { 200: dataResponse('Comment page') }, }, post: { tags: ['Plaza'], summary: 'Create comment or reply', parameters: [{ $ref: '#/components/parameters/PostId' }], requestBody: { required: true, content: { 'application/json': { schema: { $ref: '#/components/schemas/CreatePlazaCommentRequest' }, }, }, }, responses: { 201: dataResponse('Created comment') }, }, }, '/plaza/v1/comments/{commentId}': { delete: { tags: ['Plaza'], summary: 'Soft-delete own comment', parameters: [{ $ref: '#/components/parameters/CommentId' }], responses: { 200: dataResponse('Deleted comment') }, }, }, '/plaza/v1/comments/{commentId}/reactions': { post: { tags: ['Plaza'], summary: 'Like or unlike a comment', parameters: [{ $ref: '#/components/parameters/CommentId' }], requestBody: { required: true, content: { 'application/json': { schema: { type: 'object', required: ['liked'], properties: { liked: { type: 'boolean' } }, }, }, }, }, responses: { 200: dataResponse('Comment reaction') }, }, }, '/plaza/v1/posts/{postId}/reports': { post: { tags: ['Plaza'], summary: 'Report a plaza post', parameters: [{ $ref: '#/components/parameters/PostId' }], requestBody: { required: true, content: { 'application/json': { schema: { $ref: '#/components/schemas/PlazaReportRequest' }, }, }, }, responses: { 201: dataResponse('Report created') }, }, }, '/plaza/v1/comments/{commentId}/reports': { post: { tags: ['Plaza'], summary: 'Report a plaza comment', parameters: [{ $ref: '#/components/parameters/CommentId' }], requestBody: { required: true, content: { 'application/json': { schema: { $ref: '#/components/schemas/PlazaReportRequest' }, }, }, }, responses: { 201: dataResponse('Report created') }, }, }, '/plaza/v1/users/{slug}': { get: { tags: ['Plaza'], summary: 'Get plaza user profile', parameters: [{ $ref: '#/components/parameters/UserSlug' }], responses: { 200: dataResponse('User profile') }, }, }, '/plaza/v1/users/{slug}/posts': { get: { tags: ['Plaza'], summary: 'List user published plaza posts', parameters: [ { $ref: '#/components/parameters/UserSlug' }, { name: 'cursor', in: 'query', schema: { type: 'string' } }, ], responses: { 200: dataResponse('User posts') }, }, }, '/plaza/v1/users/{slug}/follow': { post: { tags: ['Plaza'], summary: 'Follow user', parameters: [{ $ref: '#/components/parameters/UserSlug' }], responses: { 200: dataResponse('Following') }, }, delete: { tags: ['Plaza'], summary: 'Unfollow user', parameters: [{ $ref: '#/components/parameters/UserSlug' }], responses: { 200: dataResponse('Unfollowed') }, }, }, '/plaza/v1/seo/sitemap': { get: { tags: ['Plaza'], summary: 'Sitemap data for Next.js', responses: { 200: dataResponse('Sitemap entries') }, }, }, '/plaza/v1/attribution/events': { post: { tags: ['Plaza'], summary: 'Record UTM attribution event', requestBody: { required: true, content: { 'application/json': { schema: { $ref: '#/components/schemas/PlazaAttributionRequest' }, }, }, }, responses: { 201: dataResponse('Attribution recorded') }, }, }, '/ops/v1/review/queue': { get: { tags: ['Plaza Ops'], summary: 'List posts in review queue', parameters: [ { name: 'status', in: 'query', schema: { type: 'string' } }, { name: 'cursor', in: 'query', schema: { type: 'string' } }, ], responses: { 200: dataResponse('Review queue') }, }, }, '/ops/v1/review/posts/{postId}': { post: { tags: ['Plaza Ops'], summary: 'Review a single plaza post', parameters: [{ $ref: '#/components/parameters/PostId' }], requestBody: { required: true, content: { 'application/json': { schema: { $ref: '#/components/schemas/OpsReviewRequest' }, }, }, }, responses: { 200: dataResponse('Review result') }, }, }, '/ops/v1/review/batch': { post: { tags: ['Plaza Ops'], summary: 'Batch review plaza posts (editor+)', requestBody: { required: true, content: { 'application/json': { schema: { $ref: '#/components/schemas/OpsBatchReviewRequest' }, }, }, }, responses: { 200: dataResponse('Batch review result') }, }, }, '/ops/v1/reports': { get: { tags: ['Plaza Ops'], summary: 'List pending reports', responses: { 200: dataResponse('Reports') }, }, }, '/ops/v1/reports/{reportId}/process': { post: { tags: ['Plaza Ops'], summary: 'Process a report', parameters: [{ $ref: '#/components/parameters/ReportId' }], requestBody: { required: true, content: { 'application/json': { schema: { $ref: '#/components/schemas/OpsProcessReportRequest' }, }, }, }, responses: { 200: dataResponse('Processed report') }, }, }, '/ops/v1/featured': { get: { tags: ['Plaza Ops'], summary: 'List featured placements', responses: { 200: dataResponse('Featured list') }, }, post: { tags: ['Plaza Ops'], summary: 'Set featured placement', requestBody: { required: true, content: { 'application/json': { schema: { $ref: '#/components/schemas/OpsFeaturedRequest' }, }, }, }, responses: { 201: dataResponse('Featured created') }, }, }, '/ops/v1/featured/{featuredId}': { delete: { tags: ['Plaza Ops'], summary: 'Remove featured placement', parameters: [{ $ref: '#/components/parameters/FeaturedId' }], responses: { 200: dataResponse('Featured removed') }, }, }, '/ops/v1/analytics/overview': { get: { tags: ['Plaza Ops'], summary: 'Plaza analytics overview', responses: { 200: dataResponse('Analytics overview') }, }, }, '/ops/v1/creators': { get: { tags: ['Plaza Ops'], summary: 'List plaza creators', parameters: [{ name: 'keyword', in: 'query', schema: { type: 'string' } }], responses: { 200: dataResponse('Creators') }, }, }, '/ops/v1/creators/{userId}': { patch: { tags: ['Plaza Ops'], summary: 'Update creator moderation flags', parameters: [{ $ref: '#/components/parameters/OpsUserId' }], requestBody: { required: true, content: { 'application/json': { schema: { $ref: '#/components/schemas/OpsCreatorPatchRequest' }, }, }, }, responses: { 200: dataResponse('Creator updated') }, }, }, }, parameters: { PostId: { name: 'postId', in: 'path', required: true, schema: { type: 'string' } }, CommentId: { name: 'commentId', in: 'path', required: true, schema: { type: 'string' } }, UserSlug: { name: 'slug', in: 'path', required: true, schema: { type: 'string' } }, ReactionType: { name: 'type', in: 'path', required: true, schema: { type: 'string', enum: ['like', 'collect'] }, }, ReportId: { name: 'reportId', in: 'path', required: true, schema: { type: 'string' } }, FeaturedId: { name: 'featuredId', in: 'path', required: true, schema: { type: 'string' } }, OpsUserId: { name: 'userId', in: 'path', required: true, schema: { type: 'string' } }, }, schemas: { CreatePlazaPostRequest: { type: 'object', required: ['publication_id', 'category_id'], properties: { publication_id: { type: 'string' }, category_id: { type: 'string' }, category_slug: { type: 'string' }, tags: { type: 'array', items: { type: 'string' } }, cover_url: { type: 'string' }, allow_comment: { type: 'boolean' }, }, }, UpdatePlazaPostRequest: { type: 'object', properties: { tags: { type: 'array', items: { type: 'string' } }, cover_url: { type: 'string' }, allow_comment: { type: 'boolean' }, }, }, PlazaReactionRequest: { type: 'object', required: ['type'], properties: { type: { type: 'string', enum: ['like', 'collect', 'share'] }, }, }, CreatePlazaCommentRequest: { type: 'object', required: ['content'], properties: { content: { type: 'string', maxLength: 500 }, parent_id: { type: ['string', 'null'] }, }, }, PlazaReportRequest: { type: 'object', required: ['reason'], properties: { reason: { type: 'string', enum: ['spam', 'violence', 'porn', 'political', 'privacy', 'other'], }, detail: { type: 'string', maxLength: 500 }, }, }, PlazaAttributionRequest: { type: 'object', required: ['event_type', 'utm_source'], properties: { event_type: { type: 'string', enum: ['landing', 'signup'] }, utm_source: { type: 'string' }, utm_medium: { type: 'string' }, utm_campaign: { type: 'string' }, ref_id: { type: 'string' }, }, }, OpsReviewRequest: { type: 'object', required: ['action'], properties: { action: { type: 'string', enum: ['approve', 'reject', 'hide'] }, reason: { type: 'string' }, }, }, OpsBatchReviewRequest: { type: 'object', required: ['post_ids', 'action'], properties: { post_ids: { type: 'array', items: { type: 'string' }, maxItems: 50 }, action: { type: 'string', enum: ['approve', 'reject', 'hide'] }, reason: { type: 'string' }, }, }, OpsProcessReportRequest: { type: 'object', required: ['action'], properties: { action: { type: 'string', enum: ['dismiss', 'hide_post'] }, action_taken: { type: 'string' }, }, }, OpsFeaturedRequest: { type: 'object', required: ['post_id', 'position'], properties: { post_id: { type: 'string' }, position: { type: 'string', enum: ['homepage_banner', 'category_top', 'trending'] }, sort_order: { type: 'integer' }, expires_at: { type: ['string', 'null'], format: 'date-time' }, }, }, OpsCreatorPatchRequest: { type: 'object', properties: { verified: { type: 'boolean' }, post_banned: { type: 'boolean' }, comment_banned: { type: 'boolean' }, }, }, }, }; }