openapi: 3.1.0
info:
  title: WorkComposer API
  version: 2.0.0
  description: |
    The WorkComposer API enables developers to integrate productivity and project management 
    features into their applications. Access users, teams, projects, and tasks programmatically.
    
    ---
    
    ## 🔐 Authentication
    
    All API requests require an API key passed in the request header:
    
    ```http
    X-API-Key: your_api_key_here
    ```
    
    ---
    
    ## ⏱️ Rate Limiting
    
    API requests are subject to daily rate limits based on your organization's plan.
    
    **Rate limit headers included in all responses:**
    
    | Header | Description |
    |--------|-------------|
    | `X-RateLimit-Limit` | Your daily request limit |
    | `X-RateLimit-Remaining` | Remaining requests for today |
    | `X-RateLimit-Reset` | Unix timestamp when the limit resets |
    
    ---
    
    ## 🔍 Request ID
    
    Every response includes an `X-Request-Id` header for debugging and support purposes.
    
    ---
    
    ## 📄 Pagination
    
    List endpoints use **cursor-based pagination** with query parameters:
    
    - **`cursor`** - Pagination cursor (omit for first request)
    - **`limit`** - Number of items per page
    
    Use the `nextCursor` value from the response for subsequent requests.
    
    **Example:**
    ```
    GET /users?limit=50
    GET /users?limit=50&cursor=eyJpZCI6MTIzfQ
    ```
    
    ---
    
    ## 🔢 Sorting
    
    List endpoints support custom ordering with query parameters:
    
    - **`sort`** - Field name to sort by
    - **`sortDir`** - Sort direction (`asc` or `desc`)
    
    **Example:**
    ```
    GET /projects?sort=createdAt&sortDir=desc
    ```
    
    ---
    
    ## 🔄 Conditional Requests
    
    GET endpoints return `ETag` headers for caching optimization.
    
    Use the `If-None-Match` header with the ETag value to avoid re-downloading unchanged data. 
    The server will return `304 Not Modified` if the resource hasn't changed.
    
    ---
    
    ## 🎯 RESTful Design
    
    This API follows REST conventions:
    
    | Method | Purpose |
    |--------|---------|
    | `GET` | Retrieve resources |
    | `POST` | Create new resources |
    | `PATCH` | Partially update resources |
    | `DELETE` | Remove resources |
    
    ---
    
    ## 🔁 Idempotency
    
    POST endpoints support idempotent requests using the `Idempotency-Key` header.
    
    **How it works:**
    - Send a client-generated UUID as the `Idempotency-Key` header value
    - If the same key is sent within 24 hours, the API returns the cached response
    - Prevents duplicate resource creation from retried requests
    
    **Example:**
    ```http
    POST /projects
    Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
    Content-Type: application/json
    ```
    
    > **💡 Recommended:** Use idempotency keys for all resource creation requests.
    
    ---
    
    ## ❌ Error Format
    
    All errors follow a consistent JSON structure:
    
    ```json
    {
      "error": {
        "code": "ERROR_CODE",
        "message": "Human-readable error message",
        "details": [
          {
            "field": "email",
            "issue": "Invalid email format"
          }
        ]
      }
    }
    ```
    
    **Common error codes:**
    - `UNAUTHORIZED` - Invalid or missing API key
    - `RATE_LIMIT_EXCEEDED` - Too many requests
    - `NOT_FOUND` - Requested resource or route doesn't exist
    - `VALIDATION_ERROR` - Request body validation failed
    - `FORBIDDEN` - Insufficient permissions
    - `CONFLICT` - Resource already exists (e.g., duplicate email)
    - `UNSUPPORTED_MEDIA_TYPE` - Content-Type must be application/json
    - `INTERNAL_ERROR` - Unexpected server error
  contact:
    name: WorkComposer Support
    url: https://www.workcomposer.com/contact-us
    email: support@workcomposer.com
  license:
    name: Proprietary
    url: https://www.workcomposer.com/terms-and-conditions-of-service

servers:
  - url: https://api.workcomposer.com/v2
    description: Production API

security:
  - ApiKeyAuth: []

tags:
  - name: Users
    description: User management operations
  - name: Teams
    description: Team management operations
  - name: Projects
    description: Project management operations
  - name: Tasks
    description: Task management operations
  - name: Time Entries
    description: Work time tracking data
  - name: Attendance
    description: Attendance and daily summary data
  - name: Screenshots
    description: Screenshot metadata
  - name: Activity
    description: Real-time tracking activity status

paths:
  /users:
    get:
      tags: [Users]
      summary: List users
      description: Retrieve a list of users in your organization with optional filtering and pagination.
      operationId: listUsers
      parameters:
        - name: teamId
          in: query
          description: Filter by team ID
          schema:
            type: string
        - name: search
          in: query
          description: Search users by name or email
          schema:
            type: string
        - name: includeInactive
          in: query
          description: Include archived/inactive users
          schema:
            type: boolean
            default: false
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/cursor'
        - name: sort
          in: query
          description: Field to sort by
          schema:
            type: string
            enum: [createdAt, firstName, lastName, email]
            default: createdAt
        - $ref: '#/components/parameters/sortDir'
      responses:
        '200':
          description: Successful response
          headers:
            ETag:
              $ref: '#/components/headers/ETag'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
        '304':
          description: Not modified (ETag match)
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

    post:
      tags: [Users]
      summary: Create user
      description: |
        Create a new user in your workspace directly with a password.
        Consider using `POST /users/invite` instead to invite users via email.
      operationId: createUser
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [firstName, lastName, email, password]
              properties:
                firstName:
                  type: string
                  maxLength: 100
                  example: "John"
                lastName:
                  type: string
                  maxLength: 100
                  example: "Doe"
                email:
                  type: string
                  format: email
                  example: "john.doe@example.com"
                password:
                  type: string
                  example: "SecureP@ssw0rd!"
                teamId:
                  type: string
                  example: "507f1f77bcf86cd799439012"
      responses:
        '201':
          description: User created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/User'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

  /users/invite:
    post:
      tags: [Users]
      summary: Invite user
      description: |
        Invite a new user to your workspace via email. The user will receive an invitation 
        email with a link to set up their account. This is the recommended way to add users.
      operationId: inviteUser
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email]
              properties:
                email:
                  type: string
                  format: email
                  example: "newuser@example.com"
                teamId:
                  type: string
                  example: "507f1f77bcf86cd799439012"
      responses:
        '201':
          description: Invitation sent successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/User'
                  message:
                    type: string
                    example: "Invitation sent successfully"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

  /users/{userId}:
    get:
      tags: [Users]
      summary: Get user
      description: Retrieve details about a specific user.
      operationId: getUser
      parameters:
        - $ref: '#/components/parameters/userId'
      responses:
        '200':
          description: Successful response
          headers:
            ETag:
              $ref: '#/components/headers/ETag'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/User'
        '304':
          description: Not modified (ETag match)
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

    patch:
      tags: [Users]
      summary: Update user
      description: |
        Update an existing user. Supports partial updates.
        Use `isActive` to activate or deactivate users.
      operationId: updateUser
      parameters:
        - $ref: '#/components/parameters/userId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              minProperties: 1
              properties:
                firstName:
                  type: string
                  maxLength: 100
                lastName:
                  type: string
                  maxLength: 100
                teamId:
                  type: string
                isActive:
                  type: boolean
                  description: Set to true to activate or false to deactivate the user
      responses:
        '200':
          description: User updated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/User'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

    delete:
      tags: [Users]
      summary: Delete user
      description: Soft-delete a user from the workspace.
      operationId: deleteUser
      parameters:
        - $ref: '#/components/parameters/userId'
      responses:
        '200':
          description: User deleted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

  /teams:
    get:
      tags: [Teams]
      summary: List teams
      description: Retrieve a list of teams in your organization.
      operationId: listTeams
      parameters:
        - name: search
          in: query
          description: Search teams by name
          schema:
            type: string
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/cursor'
        - name: sort
          in: query
          description: Field to sort by
          schema:
            type: string
            enum: [createdAt, name]
            default: createdAt
        - $ref: '#/components/parameters/sortDir'
      responses:
        '200':
          description: Successful response
          headers:
            ETag:
              $ref: '#/components/headers/ETag'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Team'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
        '304':
          description: Not modified (ETag match)
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

    post:
      tags: [Teams]
      summary: Create team
      description: Create a new team in the workspace.
      operationId: createTeam
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                  maxLength: 100
                  example: "Engineering"
      responses:
        '201':
          description: Team created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Team'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

  /teams/{teamId}:
    get:
      tags: [Teams]
      summary: Get team
      description: Retrieve details about a specific team.
      operationId: getTeam
      parameters:
        - $ref: '#/components/parameters/teamId'
      responses:
        '200':
          description: Successful response
          headers:
            ETag:
              $ref: '#/components/headers/ETag'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/TeamDetail'
        '304':
          description: Not modified (ETag match)
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

    patch:
      tags: [Teams]
      summary: Update team
      description: Update an existing team.
      operationId: updateTeam
      parameters:
        - $ref: '#/components/parameters/teamId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              minProperties: 1
              properties:
                name:
                  type: string
                  maxLength: 100
      responses:
        '200':
          description: Team updated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/TeamDetail'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

    delete:
      tags: [Teams]
      summary: Delete team
      description: Delete a team. Teams with users cannot be deleted.
      operationId: deleteTeam
      parameters:
        - $ref: '#/components/parameters/teamId'
      responses:
        '200':
          description: Team deleted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

  /projects:
    get:
      tags: [Projects]
      summary: List projects
      description: Retrieve a list of projects the user has access to.
      operationId: listProjects
      parameters:
        - name: search
          in: query
          description: Search projects by title
          schema:
            type: string
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/cursor'
        - name: sort
          in: query
          description: Field to sort by
          schema:
            type: string
            enum: [createdAt, title]
            default: createdAt
        - $ref: '#/components/parameters/sortDir'
      responses:
        '200':
          description: Successful response
          headers:
            ETag:
              $ref: '#/components/headers/ETag'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Project'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
        '304':
          description: Not modified (ETag match)
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

    post:
      tags: [Projects]
      summary: Create project
      description: Create a new project in the workspace.
      operationId: createProject
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [title]
              properties:
                title:
                  type: string
                  maxLength: 100
                  example: "Website Redesign"
                members:
                  type: array
                  items:
                    type: string
                  description: Array of user IDs to add as members
                teams:
                  type: array
                  items:
                    type: string
                  description: Array of team IDs to add
      responses:
        '201':
          description: Project created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/ProjectDetail'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

  /projects/{projectId}:
    get:
      tags: [Projects]
      summary: Get project
      description: Retrieve details about a specific project.
      operationId: getProject
      parameters:
        - $ref: '#/components/parameters/projectId'
      responses:
        '200':
          description: Successful response
          headers:
            ETag:
              $ref: '#/components/headers/ETag'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/ProjectDetail'
        '304':
          description: Not modified (ETag match)
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

    patch:
      tags: [Projects]
      summary: Update project
      description: Update an existing project.
      operationId: updateProject
      parameters:
        - $ref: '#/components/parameters/projectId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              minProperties: 1
              properties:
                title:
                  type: string
                  maxLength: 100
                members:
                  type: array
                  items:
                    type: string
                teams:
                  type: array
                  items:
                    type: string
      responses:
        '200':
          description: Project updated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/ProjectDetail'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

    delete:
      tags: [Projects]
      summary: Delete project
      description: Delete a project and all its tasks.
      operationId: deleteProject
      parameters:
        - $ref: '#/components/parameters/projectId'
      responses:
        '200':
          description: Project deleted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

  /tasks:
    get:
      tags: [Tasks]
      summary: List tasks
      description: Retrieve a list of tasks for a specific project.
      operationId: listTasks
      parameters:
        - name: projectId
          in: query
          required: true
          description: Project ID (required)
          schema:
            type: string
        - name: status
          in: query
          description: "Filter by status. Use 'deleted' to view soft-deleted tasks."
          schema:
            type: string
            enum: [ToDo, InProgress, Done, deleted]
        - name: assigneeId
          in: query
          description: Filter by assignee user ID
          schema:
            type: string
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/cursor'
        - name: sort
          in: query
          description: Field to sort by
          schema:
            type: string
            enum: [createdAt, title, priority, status]
            default: createdAt
        - $ref: '#/components/parameters/sortDir'
      responses:
        '200':
          description: Successful response
          headers:
            ETag:
              $ref: '#/components/headers/ETag'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Task'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
        '304':
          description: Not modified (ETag match)
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

    post:
      tags: [Tasks]
      summary: Create task
      description: Create a new task in a project.
      operationId: createTask
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [title, projectId]
              properties:
                title:
                  type: string
                  maxLength: 100
                  example: "Fix login bug"
                projectId:
                  type: string
                  example: "507f1f77bcf86cd799439013"
                description:
                  type: string
                assigneeId:
                  type: string
                priority:
                  type: integer
                  enum: [1, 2, 3, 4]
                  description: "1=Low, 2=Medium, 3=High, 4=Urgent"
                  default: 2
      responses:
        '201':
          description: Task created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/TaskDetail'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

  /tasks/{taskId}:
    get:
      tags: [Tasks]
      summary: Get task
      description: Retrieve details about a specific task.
      operationId: getTask
      parameters:
        - $ref: '#/components/parameters/taskId'
      responses:
        '200':
          description: Successful response
          headers:
            ETag:
              $ref: '#/components/headers/ETag'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/TaskDetail'
        '304':
          description: Not modified (ETag match)
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

    patch:
      tags: [Tasks]
      summary: Update task
      description: Update an existing task.
      operationId: updateTask
      parameters:
        - $ref: '#/components/parameters/taskId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              minProperties: 1
              properties:
                title:
                  type: string
                  maxLength: 100
                description:
                  type: string
                assigneeId:
                  type: [string, "null"]
                priority:
                  type: integer
                  enum: [1, 2, 3, 4]
                status:
                  type: string
                  enum: [ToDo, InProgress, Done]
      responses:
        '200':
          description: Task updated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/TaskDetail'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

    delete:
      tags: [Tasks]
      summary: Delete task
      description: Soft-delete a task.
      operationId: deleteTask
      parameters:
        - $ref: '#/components/parameters/taskId'
      responses:
        '200':
          description: Task deleted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

  /time-entries:
    get:
      tags: [Time Entries]
      summary: List time entries
      description: |
        Retrieve work time summaries per user for a date range. Each entry includes
        worked time, break time, activity percentage, and first/last activity timestamps.
        Requires ACCESS_REPORTS privilege.
      operationId: listTimeEntries
      parameters:
        - name: from
          in: query
          description: Start date (YYYY-MM-DD). Defaults to today.
          schema:
            type: string
            format: date
            example: "2024-01-01"
        - name: to
          in: query
          description: End date (YYYY-MM-DD). Defaults to today.
          schema:
            type: string
            format: date
            example: "2024-01-31"
        - name: timezone
          in: query
          description: IANA timezone (e.g., America/New_York). Defaults to organization timezone.
          schema:
            type: string
            example: "America/New_York"
        - name: userId
          in: query
          description: Filter by specific user ID
          schema:
            type: string
        - name: teamId
          in: query
          description: Filter by team ID
          schema:
            type: string
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/cursor'
        - name: sort
          in: query
          description: Field to sort by
          schema:
            type: string
            enum: [firstName, lastName, email]
            default: firstName
        - $ref: '#/components/parameters/sortDir'
      responses:
        '200':
          description: Successful response
          headers:
            ETag:
              $ref: '#/components/headers/ETag'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TimeEntry'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
        '304':
          description: Not modified (ETag match)
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

  /attendance/daily-summary:
    get:
      tags: [Attendance]
      summary: Daily attendance summary
      description: |
        Returns daily attendance data per user for a date range, including total worked time,
        break time, overtime, first clock-in, and last clock-out times.
        Maximum date range is 31 days. Requires ACCESS_REPORTS privilege.
      operationId: getDailySummary
      parameters:
        - name: from
          in: query
          description: Start date (YYYY-MM-DD). Defaults to start of current month.
          schema:
            type: string
            format: date
            example: "2024-01-01"
        - name: to
          in: query
          description: End date (YYYY-MM-DD). Defaults to end of current month.
          schema:
            type: string
            format: date
            example: "2024-01-31"
        - name: timezone
          in: query
          description: IANA timezone. Defaults to organization timezone.
          schema:
            type: string
            example: "America/New_York"
        - name: userId
          in: query
          description: Filter by specific user ID
          schema:
            type: string
        - name: teamId
          in: query
          description: Filter by team ID
          schema:
            type: string
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/cursor'
        - name: sort
          in: query
          description: Field to sort by
          schema:
            type: string
            enum: [firstName, lastName, email]
            default: firstName
        - $ref: '#/components/parameters/sortDir'
      responses:
        '200':
          description: Successful response
          headers:
            ETag:
              $ref: '#/components/headers/ETag'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/AttendanceSummary'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
        '304':
          description: Not modified (ETag match)
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

  /screenshots:
    get:
      tags: [Screenshots]
      summary: List screenshots
      description: |
        Returns screenshot metadata for a specific user within a date range.
        Each screenshot includes URL, thumbnail URL, activity percentage, and timestamp.
        Requires ACCESS_SCREENSHOTS privilege.
      operationId: listScreenshots
      parameters:
        - name: userId
          in: query
          required: true
          description: User ID to get screenshots for
          schema:
            type: string
        - name: from
          in: query
          description: Start date (YYYY-MM-DD). Defaults to today.
          schema:
            type: string
            format: date
            example: "2024-01-15"
        - name: to
          in: query
          description: End date (YYYY-MM-DD). Defaults to today.
          schema:
            type: string
            format: date
            example: "2024-01-15"
        - name: timezone
          in: query
          description: IANA timezone. Defaults to organization timezone.
          schema:
            type: string
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/cursor'
        - $ref: '#/components/parameters/sortDir'
      responses:
        '200':
          description: Successful response
          headers:
            ETag:
              $ref: '#/components/headers/ETag'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Screenshot'
                  user:
                    type: object
                    properties:
                      id:
                        type: string
                      externalId:
                        type: string
                      firstName:
                        type: string
                      lastName:
                        type: string
                      email:
                        type: string
                  pagination:
                    $ref: '#/components/schemas/Pagination'
        '304':
          description: Not modified (ETag match)
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

  /activity/summary:
    get:
      tags: [Activity]
      summary: Activity summary
      description: |
        Returns real-time tracking status for each user in the organization.
        Shows whether each user is currently tracking, on break, or not tracking.
        Requires ACCESS_REPORTS privilege.
      operationId: getActivitySummary
      parameters:
        - name: teamId
          in: query
          description: Filter by team ID
          schema:
            type: string
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/cursor'
        - name: sort
          in: query
          description: Field to sort by
          schema:
            type: string
            enum: [firstName, lastName, email]
            default: firstName
        - $ref: '#/components/parameters/sortDir'
      responses:
        '200':
          description: Successful response
          headers:
            ETag:
              $ref: '#/components/headers/ETag'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ActivityStatus'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
        '304':
          description: Not modified (ETag match)
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: API key for authentication

  headers:
    ETag:
      description: Entity tag for conditional requests
      schema:
        type: string
    X-Request-Id:
      description: Unique request identifier for debugging
      schema:
        type: string
        format: uuid

  parameters:
    userId:
      name: userId
      in: path
      required: true
      description: User ID
      schema:
        type: string
        example: "507f1f77bcf86cd799439011"

    teamId:
      name: teamId
      in: path
      required: true
      description: Team ID
      schema:
        type: string
        example: "507f1f77bcf86cd799439012"

    projectId:
      name: projectId
      in: path
      required: true
      description: Project ID
      schema:
        type: string
        example: "507f1f77bcf86cd799439013"

    taskId:
      name: taskId
      in: path
      required: true
      description: Task ID
      schema:
        type: string
        example: "507f1f77bcf86cd799439014"

    limit:
      name: limit
      in: query
      description: Maximum number of results to return
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 25

    cursor:
      name: cursor
      in: query
      description: Cursor for cursor-based pagination
      schema:
        type: string

    sortDir:
      name: sortDir
      in: query
      description: Sort direction
      schema:
        type: string
        enum: [asc, desc]
        default: desc

  schemas:
    ErrorResponse:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [code, message]
          properties:
            code:
              type: string
              description: Machine-readable error code
            message:
              type: string
              description: Human-readable error message
            details:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                  message:
                    type: string

    DeleteResponse:
      type: object
      required: [data]
      properties:
        data:
          type: object
          required: [id, deleted]
          properties:
            id:
              type: string
            deleted:
              type: boolean
              enum: [true]

    Pagination:
      type: object
      required: [total, limit, hasMore, nextCursor]
      properties:
        total:
          type: integer
          description: Total number of matching records
        limit:
          type: integer
          description: Maximum number of results per page
        hasMore:
          type: boolean
          description: Whether there are more records after this page
        nextCursor:
          type: [string, "null"]
          description: Cursor to fetch the next page, null if no more results

    User:
      type: object
      required: [id, firstName, lastName, email, isActive, createdAt, updatedAt]
      properties:
        id:
          type: string
        externalId:
          type: string
        firstName:
          type: string
        lastName:
          type: string
        email:
          type: string
          format: email
        teamId:
          type: string
        teamName:
          type: string
        role:
          type: string
          description: "Owner, Admin, Manager, or User"
        isActive:
          type: boolean
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        lastSyncedAt:
          type: string
          format: date-time

    Team:
      type: object
      required: [id, name, createdAt, updatedAt]
      properties:
        id:
          type: string
        name:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    TeamDetail:
      allOf:
        - $ref: '#/components/schemas/Team'
        - type: object
          properties:
            userCount:
              type: integer

    Project:
      type: object
      required: [id, title, createdAt, updatedAt]
      properties:
        id:
          type: string
        title:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    ProjectDetail:
      allOf:
        - $ref: '#/components/schemas/Project'
        - type: object
          properties:
            members:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: string
                  firstName:
                    type: string
                  lastName:
                    type: string
                  email:
                    type: string
            teams:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: string
                  name:
                    type: string
            taskCount:
              type: integer

    Task:
      type: object
      required: [id, title, status, priority, projectId, createdAt, updatedAt]
      properties:
        id:
          type: string
        title:
          type: string
        description:
          type: string
        status:
          type: string
          enum: [ToDo, InProgress, Done]
        priority:
          type: integer
          enum: [1, 2, 3, 4]
          description: "1=Low, 2=Medium, 3=High, 4=Urgent"
        projectId:
          type: string
        assigneeId:
          type: [string, "null"]
        authorId:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    TaskDetail:
      type: object
      required: [id, title, status, priority, project, createdAt, updatedAt]
      properties:
        id:
          type: string
        title:
          type: string
        description:
          type: string
        status:
          type: string
          enum: [ToDo, InProgress, Done]
        priority:
          type: integer
          enum: [1, 2, 3, 4]
        project:
          type: object
          properties:
            id:
              type: string
            title:
              type: string
        assignee:
          type: [object, "null"]
          properties:
            id:
              type: string
            firstName:
              type: string
            lastName:
              type: string
            email:
              type: string
        author:
          type: [object, "null"]
          properties:
            id:
              type: string
            firstName:
              type: string
            lastName:
              type: string
            email:
              type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    TimeEntry:
      type: object
      required: [userId, firstName, lastName, email, workedTime, breakTime, awayTime, activityPercentage, from, to]
      properties:
        userId:
          type: string
        externalId:
          type: string
        firstName:
          type: string
        lastName:
          type: string
        email:
          type: string
          format: email
        workedTime:
          type: integer
          description: Total worked time in seconds
        breakTime:
          type: integer
          description: Total break time in seconds
        awayTime:
          type: integer
          description: Total away time in seconds
        activityPercentage:
          type: integer
          description: Activity percentage (0-100)
          minimum: 0
          maximum: 100
        firstActivityAt:
          type: [string, "null"]
          format: date-time
          description: Timestamp of first activity in the period
        lastActivityAt:
          type: [string, "null"]
          format: date-time
          description: Timestamp of last activity in the period
        from:
          type: string
          format: date-time
          description: Start of the queried period
        to:
          type: string
          format: date-time
          description: End of the queried period

    AttendanceSummary:
      type: object
      required: [userId, firstName, lastName, email, from, to, days]
      properties:
        userId:
          type: string
        externalId:
          type: string
        firstName:
          type: string
        lastName:
          type: string
        email:
          type: string
          format: email
        from:
          type: string
          format: date-time
        to:
          type: string
          format: date-time
        days:
          type: array
          items:
            type: object
            properties:
              date:
                type: string
                format: date
                description: Date in YYYY-MM-DD format
              totalWorkedSeconds:
                type: integer
                description: Total worked time in seconds for the day
              breakTimeSeconds:
                type: integer
                description: Total break time in seconds for the day
              overtimeSeconds:
                type: integer
                description: Overtime in seconds (beyond 8-hour standard workday)
              firstClockIn:
                type: [string, "null"]
                description: First clock-in time (HH:mm:ss) in the requested timezone
              lastClockOut:
                type: [string, "null"]
                description: Last clock-out time (HH:mm:ss) in the requested timezone

    Screenshot:
      type: object
      required: [timestamp, minuteTimestamp, url, thumbnailUrl, activityPercentage]
      properties:
        timestamp:
          type: string
          format: date-time
          description: ISO 8601 timestamp of the screenshot
        minuteTimestamp:
          type: integer
          description: Unix minute timestamp
        url:
          type: string
          description: Full-size screenshot URL
        thumbnailUrl:
          type: string
          description: Thumbnail screenshot URL
        activityPercentage:
          type: integer
          description: Activity percentage at the time of screenshot (0-100)
          minimum: 0
          maximum: 100

    ActivityStatus:
      type: object
      required: [userId, firstName, lastName, email, status]
      properties:
        userId:
          type: string
        externalId:
          type: string
        firstName:
          type: string
        lastName:
          type: string
        email:
          type: string
          format: email
        status:
          type: string
          enum: [tracking, break, not_tracking]
          description: Current tracking status
        lastSeenAt:
          type: [string, "null"]
          format: date-time
          description: Timestamp of last tracking activity

  responses:
    Unauthorized:
      description: Authentication failed
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: "UNAUTHORIZED"
              message: "Invalid or missing API key"

    Forbidden:
      description: Permission denied
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: "FORBIDDEN"
              message: "You don't have privileges to perform this action."

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: "NOT_FOUND"
              message: "Resource not found."

    ValidationError:
      description: Validation error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: "VALIDATION_ERROR"
              message: "Invalid request parameters"
              details:
                - field: "email"
                  message: "Please provide a valid email address."

    Conflict:
      description: Resource conflict
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: "CONFLICT"
              message: "A resource with this name already exists."

    UnsupportedMediaType:
      description: Unsupported Content-Type
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: "UNSUPPORTED_MEDIA_TYPE"
              message: "Content-Type must be application/json"

    RateLimitExceeded:
      description: Rate limit exceeded
      headers:
        X-RateLimit-Limit:
          schema:
            type: integer
          description: Daily rate limit
        X-RateLimit-Remaining:
          schema:
            type: integer
          description: Remaining requests
        X-RateLimit-Reset:
          schema:
            type: integer
          description: Unix timestamp when the limit resets
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: "RATE_LIMIT_EXCEEDED"
              message: "Daily API rate limit exceeded. Please try again tomorrow."
