openapi: 3.1.0
info:
  title: Nasak Content and SEO API
  version: 1.0.0-alpha.1
  description: Public book content plus audited blog, metadata, SEO draft, and Search Console management.
servers:
  - url: https://api.nasak.ir/v1/content
paths:
  /live:
    get:
      operationId: getContentLiveness
      summary: Check Content API liveness
      security: []
      responses:
        '200': { $ref: '#/components/responses/Success' }
  /books/{slug}:
    get:
      operationId: getPublishedBookContent
      summary: Get a published book page and approved public discussion
      parameters: [{ $ref: '#/components/parameters/Slug' }]
      security: []
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '404': { $ref: '#/components/responses/NotFound' }
  /books/{slug}/comments:
    post:
      operationId: commentOnBookContent
      summary: Submit a moderated book-page comment
      parameters: [{ $ref: '#/components/parameters/Slug' }]
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Same-origin, authenticated, rate-limited compatibility mutation.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '201': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/TooManyRequests' }
  /admin/blog/dashboard:
    get:
      operationId: getBlogAdminDashboard
      summary: Get blog posts, book pages, comments, generation jobs, and SEO state
      security: [{ cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /admin/blog/posts:
    post:
      operationId: createBlogPost
      summary: Create a draft or published editorial post
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Audited administrator content mutation.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /admin/blog/posts/{id}:
    patch:
      operationId: updateBlogPost
      summary: Edit, publish, unpublish, or archive a blog post
      parameters: [{ $ref: '#/components/parameters/Id' }]
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Audited administrator content mutation.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
  /admin/blog/comments/{id}:
    patch:
      operationId: moderateBlogComment
      summary: Approve, reject, or update moderation state for a comment
      parameters: [{ $ref: '#/components/parameters/Id' }]
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Audited moderation mutation.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
  /admin/blog/books/{bookId}/generate:
    post:
      operationId: generateBookBlogPage
      summary: Queue or regenerate the SEO-ready page for a book
      parameters: [{ $ref: '#/components/parameters/BookId' }]
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Rate-limited administrator generation action.
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '429': { $ref: '#/components/responses/TooManyRequests' }
  /admin/seo/run:
    post:
      operationId: runContentSeoAudit
      summary: Run the global SEO agent for an approved content target
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Audited administrator AI action with server-side target validation.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/TooManyRequests' }
  /admin/seo/scheduled:
    post:
      operationId: runScheduledContentSeo
      summary: Run the configured scheduled SEO batch
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Rate-limited administrator batch action.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/TooManyRequests' }
  /admin/pdf-review/run:
    post:
      operationId: runBookMetadataReview
      summary: Queue or execute metadata review for a selected PDF book
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Rate-limited administrator review action.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/TooManyRequests' }
  /admin/shop/seo/drafts:
    get:
      operationId: listShopSeoDrafts
      summary: List SEO content drafts belonging to the active store
      security: [{ cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /admin/shop/seo/drafts/{id}:
    patch:
      operationId: reviewShopSeoDraft
      summary: Approve, reject, edit, or publish a store SEO draft
      parameters: [{ $ref: '#/components/parameters/Id' }]
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Tenant-scoped and audited editorial mutation.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
  /admin/shop/seo/run:
    post:
      operationId: runShopSeoAudit
      summary: Generate technical findings or a reviewable store content draft
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Store-scoped, entitlement-checked AI action.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/TooManyRequests' }
  /admin/shop/seo/scheduled:
    post:
      operationId: runScheduledShopSeo
      summary: Run the active store scheduled SEO program
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Store-scoped, rate-limited batch action.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/TooManyRequests' }
  /admin/shop/seo/search-console:
    get:
      operationId: getShopSearchConsole
      summary: Get safe Search Console connection state and synced metrics
      security: [{ cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
    patch:
      operationId: configureShopSearchConsole
      summary: Configure the exact property belonging to the active store domain
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Property ownership is constrained to the active store.
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '422': { $ref: '#/components/responses/Unprocessable' }
    post:
      operationId: syncShopSearchConsole
      summary: Synchronize metrics for the active store property
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Store-scoped and rate-limited synchronization action.
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/TooManyRequests' }
  /admin/shop/seo/search-console/connect:
    post:
      operationId: connectShopSearchConsole
      summary: Start the secure Google Search Console OAuth flow
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Generates a short-lived state bound to the active store and user.
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /admin/shop/seo/search-console/callback:
    get:
      operationId: completeShopSearchConsoleOAuth
      summary: Complete OAuth with validated state and encrypted refresh credentials
      security: [{ cookieSession: [] }]
      responses:
        '302': { description: Redirect to the active store SEO panel. }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /admin/shop/seo/search-console/sitemap:
    post:
      operationId: submitShopSitemap
      summary: Submit the canonical sitemap for the active store property
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      x-migration-note: Store-scoped Search Console action.
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
components:
  securitySchemes:
    cookieSession: { type: apiKey, in: cookie, name: pdf_library_session }
  parameters:
    Id:
      name: id
      in: path
      required: true
      schema: { type: string, format: uuid }
    BookId:
      name: bookId
      in: path
      required: true
      schema: { type: string, format: uuid }
    Slug:
      name: slug
      in: path
      required: true
      schema: { type: string, minLength: 1, maxLength: 180 }
  requestBodies:
    Mutation:
      required: true
      content:
        application/json:
          schema: { type: object, additionalProperties: true }
  schemas:
    Error:
      type: object
      additionalProperties: true
      required: [error]
      properties: { error: { type: string } }
  responses:
    Success:
      description: Successful response within the actor's content or store scope.
      content:
        application/json:
          schema: { type: object, additionalProperties: true }
    BadRequest:
      description: Invalid request.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    Unauthorized:
      description: Authentication is required.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    Forbidden:
      description: Administrator, entitlement, or store permission is insufficient.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    NotFound:
      description: Content resource was not found.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    Unprocessable:
      description: Input is valid JSON but violates the content or domain policy.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    TooManyRequests:
      description: Rate limit exceeded.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
