openapi: 3.1.0
info:
  title: Productier API
  version: 0.1.0
  description: Core API contract for Productier workspaces, planning, notes, and focus sessions.
servers:
  - url: http://localhost:8080
paths:
  /v1/health:
    get:
      operationId: getHealth
      tags: [system]
      responses:
        "200":
          description: Health check
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HealthResponse"
        "503":
          description: Dependency health check failed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HealthResponse"
  /v1/metrics:
    get:
      operationId: getMetrics
      tags: [system]
      responses:
        "200":
          description: Runtime request metrics snapshot
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MetricsResponse"
        "401":
          description: Metrics token missing or invalid
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/metrics/prometheus:
    get:
      operationId: getMetricsPrometheus
      tags: [system]
      responses:
        "200":
          description: Runtime request metrics in Prometheus text format
          content:
            text/plain:
              schema:
                type: string
        "401":
          description: Metrics token missing or invalid
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/workspaces:
    get:
      operationId: listWorkspaces
      tags: [workspaces]
      responses:
        "200":
          description: Workspace list
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Workspace"
  /v1/members:
    get:
      operationId: listMembers
      tags: [workspaces]
      parameters:
        - name: workspaceSlug
          in: query
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Workspace members
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Member"
  /v1/members/{memberId}:
    patch:
      operationId: updateMember
      tags: [workspaces]
      parameters:
        - name: memberId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateMemberInput"
      responses:
        "200":
          description: Updated member
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/Member"
        "400":
          description: Invalid input
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Member not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: Business rule conflict
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/invites:
    get:
      operationId: listInvites
      tags: [workspaces]
      parameters:
        - name: workspaceSlug
          in: query
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Workspace invites
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Invite"
    post:
      operationId: createInvite
      tags: [workspaces]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateInviteInput"
      responses:
        "201":
          description: Created invite
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/Invite"
        "400":
          description: Invalid input
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/invites/{token}:
    get:
      operationId: getInviteByToken
      tags: [workspaces]
      parameters:
        - name: token
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Invite detail
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/Invite"
        "404":
          description: Invite not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/invites/{token}/accept:
    post:
      operationId: acceptInvite
      tags: [workspaces]
      parameters:
        - name: token
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AcceptInviteInput"
      responses:
        "200":
          description: Accepted invite
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/Invite"
        "400":
          description: Invalid input
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Invite not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/invites/{inviteId}/revoke:
    post:
      operationId: revokeInvite
      tags: [workspaces]
      parameters:
        - name: inviteId
          in: path
          required: true
          schema:
            type: string
      responses:
        "204":
          description: Invite revoked
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Invite not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: Invite state conflict
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/activity:
    get:
      operationId: listActivity
      tags: [workspaces]
      parameters:
        - name: workspaceSlug
          in: query
          required: true
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Max entries to return (1-40, default 8)
          schema:
            type: integer
            minimum: 1
            maximum: 40
        - name: type
          in: query
          required: false
          description: Optional inferred activity category filter
          schema:
            type: string
            enum: [task, board, calendar, note, focus, mail, invite, system]
        - name: q
          in: query
          required: false
          description: Case-insensitive text search over title and detail
          schema:
            type: string
      responses:
        "200":
          description: Workspace activity feed
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/ActivityEntry"
        "400":
          description: Invalid activity query parameters
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/board-groups:
    get:
      operationId: listBoardGroups
      tags: [board]
      parameters:
        - name: workspaceSlug
          in: query
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Board groups
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/BoardGroup"
    post:
      operationId: createBoardGroup
      tags: [board]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateBoardGroupInput"
      responses:
        "201":
          description: Created board group
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/BoardGroup"
  /v1/board-groups/{groupId}:
    patch:
      operationId: updateBoardGroup
      tags: [board]
      parameters:
        - name: groupId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateBoardGroupInput"
      responses:
        "200":
          description: Updated board group
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/BoardGroup"
  /v1/labels:
    get:
      operationId: listLabels
      tags: [labels]
      parameters:
        - name: workspaceSlug
          in: query
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Label list
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Label"
    post:
      operationId: createLabel
      tags: [labels]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateLabelInput"
      responses:
        "201":
          description: Created label
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/Label"
  /v1/tasks:
    get:
      operationId: listTasks
      tags: [tasks]
      parameters:
        - name: workspaceSlug
          in: query
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Task list
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Task"
    post:
      operationId: createTask
      tags: [tasks]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateTaskInput"
      responses:
        "201":
          description: Created task
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/Task"
  /v1/calendar/events:
    get:
      operationId: listCalendarEvents
      tags: [calendar]
      parameters:
        - name: workspaceSlug
          in: query
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Calendar events
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/CalendarEvent"
    post:
      operationId: createCalendarEvent
      tags: [calendar]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateCalendarEventInput"
      responses:
        "201":
          description: Created event
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/CalendarEvent"
  /v1/tasks/{taskId}:
    patch:
      operationId: updateTask
      tags: [tasks]
      parameters:
        - name: taskId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateTaskInput"
      responses:
        "200":
          description: Updated task
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/Task"
  /v1/tasks/{taskId}/attachments:
    post:
      operationId: uploadTaskAttachment
      tags: [tasks]
      parameters:
        - name: taskId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [file]
              properties:
                file:
                  type: string
                  format: binary
      responses:
        "201":
          description: Uploaded task attachment
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/Attachment"
        "400":
          description: Invalid upload
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Task not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "500":
          description: Attachment storage or update failure
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/tasks/{taskId}/attachments/{attachmentId}:
    delete:
      operationId: deleteTaskAttachment
      tags: [tasks]
      parameters:
        - name: taskId
          in: path
          required: true
          schema:
            type: string
        - name: attachmentId
          in: path
          required: true
          schema:
            type: string
      responses:
        "204":
          description: Deleted attachment
        "404":
          description: Task or attachment not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "500":
          description: Attachment delete failure
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/tasks/{taskId}/attachments/{attachmentId}/download:
    get:
      operationId: downloadTaskAttachment
      tags: [tasks]
      parameters:
        - name: taskId
          in: path
          required: true
          schema:
            type: string
        - name: attachmentId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Attachment file stream
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        "404":
          description: Task or attachment not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "500":
          description: Attachment read failure
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/calendar/events/{eventId}:
    patch:
      operationId: updateCalendarEvent
      tags: [calendar]
      parameters:
        - name: eventId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateCalendarEventInput"
      responses:
        "200":
          description: Updated event
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/CalendarEvent"
  /v1/notes:
    get:
      operationId: listNotes
      tags: [notes]
      parameters:
        - name: workspaceSlug
          in: query
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Notes list
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Note"
    post:
      operationId: createNote
      tags: [notes]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateNoteInput"
      responses:
        "201":
          description: Created note
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/Note"
  /v1/notes/{noteId}:
    patch:
      operationId: updateNote
      tags: [notes]
      parameters:
        - name: noteId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateNoteInput"
      responses:
        "200":
          description: Updated note
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/Note"
  /v1/focus/sessions:
    get:
      operationId: listFocusSessions
      tags: [focus]
      parameters:
        - name: workspaceSlug
          in: query
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Focus sessions
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/FocusSession"
    post:
      operationId: createFocusSession
      tags: [focus]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateFocusSessionInput"
      responses:
        "201":
          description: Created focus session
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/FocusSession"
  /v1/focus/sessions/{sessionId}:
    patch:
      operationId: updateFocusSession
      tags: [focus]
      parameters:
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateFocusSessionInput"
      responses:
        "200":
          description: Updated focus session
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/FocusSession"
  /v1/mailboxes:
    get:
      operationId: listMailboxes
      tags: [mail]
      parameters:
        - name: workspaceSlug
          in: query
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Connected mailboxes
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Mailbox"
    post:
      operationId: connectMailbox
      tags: [mail]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ConnectMailboxInput"
      responses:
        "201":
          description: Connected mailbox
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/Mailbox"
        "400":
          description: Invalid mailbox configuration
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/mailboxes/{mailboxId}/sync:
    post:
      operationId: syncMailbox
      tags: [mail]
      parameters:
        - name: mailboxId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Synced mailbox
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/Mailbox"
        "404":
          description: Mailbox not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "502":
          description: Mail provider sync failure
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/mail/messages:
    get:
      operationId: listMailMessages
      tags: [mail]
      parameters:
        - name: workspaceSlug
          in: query
          required: true
          schema:
            type: string
        - name: mailboxId
          in: query
          required: false
          schema:
            type: string
      responses:
        "200":
          description: Mail messages
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/MailMessage"
  /v1/mail/messages/{messageId}/create-task:
    post:
      operationId: createTaskFromMail
      tags: [mail]
      parameters:
        - name: messageId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateTaskFromMailInput"
      responses:
        "201":
          description: Created task from mail
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/Task"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Message not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: Message already linked
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "500":
          description: Link operation failure
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/mail/outgoing:
    get:
      operationId: listOutgoingMails
      tags: [mail]
      parameters:
        - name: workspaceSlug
          in: query
          required: true
          schema:
            type: string
        - name: mailboxId
          in: query
          required: false
          schema:
            type: string
      responses:
        "200":
          description: Outgoing mail queue
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/OutgoingMail"
    post:
      operationId: createOutgoingMail
      tags: [mail]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateOutgoingMailInput"
      responses:
        "201":
          description: Queued outgoing mail
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    $ref: "#/components/schemas/OutgoingMail"
        "400":
          description: Invalid input
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Mailbox does not belong to workspace
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Mailbox not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "502":
          description: Queue delivery upstream failure
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
components:
  schemas:
    HealthResponse:
      type: object
      required: [ok, mode, timestamp, storage]
      properties:
        ok:
          type: boolean
        mode:
          type: string
        timestamp:
          type: string
          format: date-time
        storage:
          $ref: "#/components/schemas/HealthStorageStatus"
    HealthStorageStatus:
      type: object
      required: [provider, ok]
      properties:
        provider:
          type: string
        ok:
          type: boolean
        error:
          type: string
    MetricsResponse:
      type: object
      required: [generatedAt, uptimeSeconds, requestsTotal, statusClassTotals, routes]
      properties:
        generatedAt:
          type: string
          format: date-time
        uptimeSeconds:
          type: integer
          format: int64
        requestsTotal:
          type: integer
          format: int64
        statusClassTotals:
          type: object
          additionalProperties:
            type: integer
            format: int64
        routes:
          type: array
          items:
            $ref: "#/components/schemas/MetricsRouteStat"
    MetricsRouteStat:
      type: object
      required: [method, path, status, count, avgLatencyMs, maxLatencyMs, lastSeenAt]
      properties:
        method:
          type: string
        path:
          type: string
        status:
          type: integer
        count:
          type: integer
          format: int64
        avgLatencyMs:
          type: number
          format: double
        maxLatencyMs:
          type: number
          format: double
        lastSeenAt:
          type: string
          format: date-time
    ErrorResponse:
      type: object
      required: [error]
      properties:
        error:
          $ref: "#/components/schemas/ErrorDetail"
    ErrorDetail:
      type: object
      required: [code, message, requestId]
      properties:
        code:
          type: string
        message:
          type: string
        requestId:
          type: string
    BoardGroup:
      type: object
      required: [id, workspaceSlug, name, color, order]
      properties:
        id:
          type: string
        workspaceSlug:
          type: string
        name:
          type: string
        color:
          type: string
        order:
          type: integer
    Workspace:
      type: object
      required:
        - id
        - slug
        - name
        - role
        - createdAt
      properties:
        id:
          type: string
        slug:
          type: string
        name:
          type: string
        role:
          type: string
          enum: [owner, admin, member]
        createdAt:
          type: string
          format: date-time
    Member:
      type: object
      required:
        - id
        - workspaceSlug
        - name
        - email
        - role
        - status
      properties:
        id:
          type: string
        workspaceSlug:
          type: string
        name:
          type: string
        email:
          type: string
        role:
          type: string
          enum: [owner, admin, member]
        status:
          type: string
          enum: [active, invited, removed]
    Invite:
      type: object
      required:
        - id
        - workspaceSlug
        - email
        - role
        - token
        - createdAt
        - status
      properties:
        id:
          type: string
        workspaceSlug:
          type: string
        email:
          type: string
          format: email
        role:
          type: string
          enum: [owner, admin, member]
        token:
          type: string
        createdAt:
          type: string
          format: date-time
        status:
          type: string
          enum: [pending, accepted]
    ActivityEntry:
      type: object
      required:
        - id
        - workspaceSlug
        - title
        - detail
        - createdAt
      properties:
        id:
          type: string
        workspaceSlug:
          type: string
        title:
          type: string
        detail:
          type: string
        createdAt:
          type: string
          format: date-time
    Label:
      type: object
      required: [id, workspaceSlug, name, color]
      properties:
        id:
          type: string
        workspaceSlug:
          type: string
        name:
          type: string
        color:
          type: string
    Attachment:
      type: object
      required: [id, name, mimeType, size]
      properties:
        id:
          type: string
        name:
          type: string
        mimeType:
          type: string
        size:
          type: integer
        dataUrl:
          type: string
    TaskComment:
      type: object
      required: [id, taskId, author, content, createdAt]
      properties:
        id:
          type: string
        taskId:
          type: string
        author:
          type: string
        content:
          type: string
        createdAt:
          type: string
          format: date-time
    Task:
      type: object
      required:
        - id
        - workspaceSlug
        - boardGroupId
        - title
        - status
        - color
        - labelIds
        - attachments
        - comments
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
        workspaceSlug:
          type: string
        boardGroupId:
          type: string
        title:
          type: string
        description:
          type: string
        status:
          type: string
          enum: [todo, in_progress, done]
        color:
          type: string
        dueAt:
          type: string
          format: date-time
        scheduledStart:
          type: string
          format: date-time
        scheduledEnd:
          type: string
          format: date-time
        assigneeId:
          type: string
        labelIds:
          type: array
          items:
            type: string
        attachments:
          type: array
          items:
            $ref: "#/components/schemas/Attachment"
        comments:
          type: array
          items:
            $ref: "#/components/schemas/TaskComment"
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    CreateTaskInput:
      type: object
      required: [workspaceSlug, boardGroupId, title]
      properties:
        workspaceSlug:
          type: string
        boardGroupId:
          type: string
        title:
          type: string
        description:
          type: string
        dueAt:
          type: string
          format: date-time
        color:
          type: string
    UpdateTaskInput:
      type: object
      properties:
        title:
          type: string
        description:
          type: string
        status:
          type: string
          enum: [todo, in_progress, done]
        boardGroupId:
          type: string
        color:
          type: string
        dueAt:
          type: string
          format: date-time
        scheduledStart:
          type: string
          format: date-time
        scheduledEnd:
          type: string
          format: date-time
        assigneeId:
          type: string
        labelIds:
          type: array
          items:
            type: string
        attachments:
          type: array
          items:
            $ref: "#/components/schemas/Attachment"
        comments:
          type: array
          items:
            $ref: "#/components/schemas/TaskComment"
    CalendarEvent:
      type: object
      required:
        - id
        - workspaceSlug
        - title
        - startsAt
        - endsAt
        - color
        - attachments
      properties:
        id:
          type: string
        workspaceSlug:
          type: string
        title:
          type: string
        description:
          type: string
        startsAt:
          type: string
          format: date-time
        endsAt:
          type: string
          format: date-time
        color:
          type: string
        linkedTaskId:
          type: string
        attachments:
          type: array
          items:
            $ref: "#/components/schemas/Attachment"
    CreateCalendarEventInput:
      type: object
      required: [workspaceSlug, title, startsAt, endsAt]
      properties:
        workspaceSlug:
          type: string
        title:
          type: string
        description:
          type: string
        startsAt:
          type: string
          format: date-time
        endsAt:
          type: string
          format: date-time
        linkedTaskId:
          type: string
        color:
          type: string
        attachments:
          type: array
          items:
            $ref: "#/components/schemas/Attachment"
    UpdateCalendarEventInput:
      type: object
      properties:
        title:
          type: string
        description:
          type: string
        startsAt:
          type: string
          format: date-time
        endsAt:
          type: string
          format: date-time
        linkedTaskId:
          type: string
        color:
          type: string
        attachments:
          type: array
          items:
            $ref: "#/components/schemas/Attachment"
    Note:
      type: object
      required:
        - id
        - workspaceSlug
        - title
        - content
        - updatedAt
      properties:
        id:
          type: string
        workspaceSlug:
          type: string
        title:
          type: string
        content:
          type: string
        updatedAt:
          type: string
          format: date-time
    CreateNoteInput:
      type: object
      required: [workspaceSlug, title, content]
      properties:
        workspaceSlug:
          type: string
        title:
          type: string
        content:
          type: string
    UpdateNoteInput:
      type: object
      properties:
        title:
          type: string
        content:
          type: string
    FocusSession:
      type: object
      required:
        - id
        - workspaceSlug
        - mode
        - startedAt
        - pausedTotalSeconds
        - durationSeconds
      properties:
        id:
          type: string
        workspaceSlug:
          type: string
        taskId:
          type: string
        mode:
          type: string
          enum: [focus, short_break, long_break]
        startedAt:
          type: string
          format: date-time
        completedAt:
          type: string
          format: date-time
        pausedAt:
          type: string
          format: date-time
        pausedTotalSeconds:
          type: integer
        durationSeconds:
          type: integer
    CreateFocusSessionInput:
      type: object
      required: [workspaceSlug, mode, durationSeconds]
      properties:
        workspaceSlug:
          type: string
        taskId:
          type: string
        mode:
          type: string
          enum: [focus, short_break, long_break]
        durationSeconds:
          type: integer
    UpdateFocusSessionInput:
      type: object
      properties:
        completedAt:
          type: string
          format: date-time
        pausedAt:
          type: string
          format: date-time
        pausedTotalSeconds:
          type: integer
    MailAddress:
      type: object
      required: [name, email]
      properties:
        name:
          type: string
        email:
          type: string
          format: email
    Mailbox:
      type: object
      required:
        - id
        - workspaceSlug
        - label
        - email
        - displayName
        - imapHost
        - imapPort
        - imapUsername
        - imapUseTls
        - smtpHost
        - smtpPort
        - smtpUsername
        - smtpUseTls
        - createdAt
        - updatedAt
        - syncStatus
      properties:
        id:
          type: string
        workspaceSlug:
          type: string
        label:
          type: string
        email:
          type: string
          format: email
        displayName:
          type: string
        imapHost:
          type: string
        imapPort:
          type: integer
        imapUsername:
          type: string
        imapUseTls:
          type: boolean
        smtpHost:
          type: string
        smtpPort:
          type: integer
        smtpUsername:
          type: string
        smtpUseTls:
          type: boolean
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        lastSyncedAt:
          type: string
          format: date-time
        syncStatus:
          type: string
          enum: [idle, syncing, ready, error]
        syncError:
          type: string
    MailMessage:
      type: object
      required:
        - id
        - workspaceSlug
        - mailboxId
        - remoteUid
        - messageId
        - folder
        - from
        - to
        - cc
        - subject
        - snippet
        - textBody
        - htmlBody
        - receivedAt
        - isRead
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
        workspaceSlug:
          type: string
        mailboxId:
          type: string
        remoteUid:
          type: integer
        messageId:
          type: string
        folder:
          type: string
        from:
          $ref: "#/components/schemas/MailAddress"
        to:
          type: array
          items:
            $ref: "#/components/schemas/MailAddress"
        cc:
          type: array
          items:
            $ref: "#/components/schemas/MailAddress"
        subject:
          type: string
        snippet:
          type: string
        textBody:
          type: string
        htmlBody:
          type: string
        receivedAt:
          type: string
          format: date-time
        isRead:
          type: boolean
        linkedTaskId:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    OutgoingMail:
      type: object
      required:
        - id
        - workspaceSlug
        - mailboxId
        - to
        - cc
        - bcc
        - subject
        - textBody
        - htmlBody
        - status
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
        workspaceSlug:
          type: string
        mailboxId:
          type: string
        to:
          type: array
          items:
            $ref: "#/components/schemas/MailAddress"
        cc:
          type: array
          items:
            $ref: "#/components/schemas/MailAddress"
        bcc:
          type: array
          items:
            $ref: "#/components/schemas/MailAddress"
        subject:
          type: string
        textBody:
          type: string
        htmlBody:
          type: string
        status:
          type: string
          enum: [queued, scheduled, sent, failed]
        scheduledFor:
          type: string
          format: date-time
        sentAt:
          type: string
          format: date-time
        error:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    ConnectMailboxInput:
      type: object
      required:
        - workspaceSlug
        - email
        - imapHost
        - imapPassword
        - smtpHost
      properties:
        workspaceSlug:
          type: string
        label:
          type: string
        email:
          type: string
          format: email
        displayName:
          type: string
        imapHost:
          type: string
        imapPort:
          type: integer
        imapUsername:
          type: string
        imapPassword:
          type: string
        imapUseTls:
          type: boolean
        smtpHost:
          type: string
        smtpPort:
          type: integer
        smtpUsername:
          type: string
        smtpPassword:
          type: string
        smtpUseTls:
          type: boolean
    CreateOutgoingMailInput:
      type: object
      required: [workspaceSlug, mailboxId, to]
      properties:
        workspaceSlug:
          type: string
        mailboxId:
          type: string
        to:
          type: array
          items:
            $ref: "#/components/schemas/MailAddress"
        cc:
          type: array
          items:
            $ref: "#/components/schemas/MailAddress"
        bcc:
          type: array
          items:
            $ref: "#/components/schemas/MailAddress"
        subject:
          type: string
        textBody:
          type: string
        htmlBody:
          type: string
        scheduledFor:
          type: string
          format: date-time
    CreateTaskFromMailInput:
      type: object
      required: [boardGroupId]
      properties:
        boardGroupId:
          type: string
        title:
          type: string
        dueAt:
          type: string
          format: date-time
        color:
          type: string
    CreateBoardGroupInput:
      type: object
      required: [workspaceSlug, name]
      properties:
        workspaceSlug:
          type: string
        name:
          type: string
        color:
          type: string
    UpdateBoardGroupInput:
      type: object
      properties:
        name:
          type: string
        color:
          type: string
        order:
          type: integer
    CreateLabelInput:
      type: object
      required: [workspaceSlug, name, color]
      properties:
        workspaceSlug:
          type: string
        name:
          type: string
        color:
          type: string
    CreateInviteInput:
      type: object
      required: [workspaceSlug, email, role]
      properties:
        workspaceSlug:
          type: string
        email:
          type: string
          format: email
        role:
          type: string
          enum: [owner, admin, member]
    AcceptInviteInput:
      type: object
      required: [name, email]
      properties:
        name:
          type: string
        email:
          type: string
          format: email
    UpdateMemberInput:
      type: object
      properties:
        role:
          type: string
          enum: [owner, admin, member]
        status:
          type: string
          enum: [active, removed]
