openapi: 3.1.0
info:
  title: Nasak Board API
  version: 1.0.0-alpha.1
  description: Membership-scoped project boards, tasks, activity streams, reports, and mind maps.
servers:
  - url: https://api.nasak.ir/v1/board
paths:
  /live:
    get:
      operationId: getBoardLiveness
      summary: Check Board API liveness
      security: []
      responses:
        '200': { $ref: '#/components/responses/Success' }
  /projects:
    get:
      operationId: listBoardProjects
      summary: List boards visible to the current actor
      description: Anonymous actors only receive the official public update board. Other boards require membership.
      security: [{}, { cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
    post:
      operationId: createBoardProject
      summary: Create a private project board
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      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' }
  /projects/{id}:
    parameters: [{ $ref: '#/components/parameters/Id' }]
    get:
      operationId: getBoardProject
      summary: Get an accessible project board
      security: [{}, { cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
    patch:
      operationId: updateBoardProject
      summary: Update project settings with manager access
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      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' }
  /projects/{id}/member-search:
    get:
      operationId: searchBoardMembers
      summary: Search eligible users before adding a project member
      parameters:
        - { $ref: '#/components/parameters/Id' }
        - name: q
          in: query
          required: true
          schema: { type: string, minLength: 2, maxLength: 80 }
      security: [{ cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /projects/{id}/members:
    parameters: [{ $ref: '#/components/parameters/Id' }]
    get:
      operationId: listBoardMembers
      summary: List project members
      security: [{ cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
    post:
      operationId: addBoardMember
      summary: Add a member to a project
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      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' }
  /projects/{id}/members/{userId}:
    parameters:
      - { $ref: '#/components/parameters/Id' }
      - { $ref: '#/components/parameters/UserId' }
    patch:
      operationId: updateBoardMember
      summary: Change a project member role
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
    delete:
      operationId: removeBoardMember
      summary: Remove a project member
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /projects/{id}/tasks:
    post:
      operationId: createBoardTask
      summary: Create a task in an accessible project
      parameters: [{ $ref: '#/components/parameters/Id' }]
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      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' }
  /projects/{id}/stream:
    get:
      operationId: getBoardActivityStream
      summary: Get the project activity stream
      parameters: [{ $ref: '#/components/parameters/Id' }]
      security: [{}, { cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /projects/{id}/report:
    get:
      operationId: getBoardReport
      summary: Get a filtered project report
      parameters:
        - { $ref: '#/components/parameters/Id' }
        - name: from
          in: query
          schema: { type: string, format: date-time }
        - name: to
          in: query
          schema: { type: string, format: date-time }
      security: [{ cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /projects/{id}/mind:
    get:
      operationId: getBoardMindMap
      summary: Get project mind-map nodes and edges
      parameters: [{ $ref: '#/components/parameters/Id' }]
      security: [{ cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /projects/{id}/mind/nodes:
    post:
      operationId: createBoardMindNode
      summary: Add a project mind-map node
      parameters: [{ $ref: '#/components/parameters/Id' }]
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '201': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /projects/{id}/mind/nodes/{nodeId}:
    parameters:
      - { $ref: '#/components/parameters/Id' }
      - { $ref: '#/components/parameters/NodeId' }
    patch:
      operationId: updateBoardMindNode
      summary: Update a mind-map node
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
    delete:
      operationId: deleteBoardMindNode
      summary: Delete a mind-map node
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /projects/{id}/mind/edges:
    post:
      operationId: createBoardMindEdge
      summary: Connect two project mind-map nodes
      parameters: [{ $ref: '#/components/parameters/Id' }]
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '201': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /projects/{id}/mind/edges/{edgeId}:
    delete:
      operationId: deleteBoardMindEdge
      summary: Delete a project mind-map edge
      parameters:
        - { $ref: '#/components/parameters/Id' }
        - { $ref: '#/components/parameters/EdgeId' }
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /tasks/{taskId}:
    parameters: [{ $ref: '#/components/parameters/TaskId' }]
    get:
      operationId: getBoardTask
      summary: Get an accessible task
      security: [{}, { cookieSession: [] }]
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
    patch:
      operationId: updateBoardTask
      summary: Update a task with edit access
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
    delete:
      operationId: archiveBoardTask
      summary: Archive a task with edit access
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /tasks/{taskId}/move:
    post:
      operationId: moveBoardTask
      summary: Move a task to another project column
      parameters: [{ $ref: '#/components/parameters/TaskId' }]
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '200': { $ref: '#/components/responses/Success' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /tasks/{taskId}/comments:
    post:
      operationId: commentOnBoardTask
      summary: Add a plain-text task comment
      parameters: [{ $ref: '#/components/parameters/TaskId' }]
      security: [{ cookieSession: [] }]
      x-idempotency-exempt: true
      requestBody: { $ref: '#/components/requestBodies/Mutation' }
      responses:
        '201': { $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 }
    UserId:
      name: userId
      in: path
      required: true
      schema: { type: string, format: uuid }
    TaskId:
      name: taskId
      in: path
      required: true
      schema: { type: string, format: uuid }
    NodeId:
      name: nodeId
      in: path
      required: true
      schema: { type: string, format: uuid }
    EdgeId:
      name: edgeId
      in: path
      required: true
      schema: { type: string, format: uuid }
  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 membership-scoped response.
      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: Project membership or capability is insufficient.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    NotFound:
      description: Resource not found.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    TooManyRequests:
      description: Rate limit exceeded.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
