# Next-gen Task execution REST APIs (paths under `task/v1/...`).
# Paths are under the Pulse DispatcherServlet, e.g. /MYWORK/service/task/v1/...
# Same servers[] base URL as walk-execution/next-gen-walk-execution-api.yaml and legacy swagger packs.
openapi: 3.0.3
info:
  title: TM Next-Gen — Task execution
  description: |
    OpenAPI for task execution APIs (`task/v1/...`).

    Same server base URL as MYWORK next-gen and legacy specs: `/MYWORK/service/`.

    Query and form fields are generally **snake_case**; the server normalizes to camelCase internally.

    **Authentication:** All endpoints require the `X-reflexis-csrf-token-X` header carrying a valid
    session token. Session-derived identity fields (`domain_id`, `user_id`, `unit_id`, `dept_id`,
    `profile_id`, `time_zone_long`, `lang_code`) are **not** accepted as request parameters — they
    are always resolved from the validated session.

    Companion specs: `mywork/next-gen-mywork-api.yaml` (app config, broadcasts, user notes, recent tabs),
    `walk-execution/next-gen-walk-execution-api.yaml` (walk execution). Use Swagger UI definition dropdown to switch modules.
  version: 1.0.0
  contact:
    name: API Support
    email: noreply@zebra.com

servers:
  - url: /MYWORK/service/
    description: Application context + Pulse servlet (typical deployment)
  - url: https://fs3.reflexisinc.com/MYWORK/service/
    description: Example development host
  - url: http://localhost:3001/MYWORK/service/
    description: Local CORS proxy — npm run cors-proxy; path must include /MYWORK/service/ like deployed Pulse servlet

tags:
  - name: MyWorkConfig
    description: Unified MyWork configuration (feed, calendar, attachment, filter, refresh settings)
  - name: MyWorkCalendar
    description: Calendar and Gantt feed data; leadership calendar
  - name: MyWorkFeeds
    description: Feed retrieval, cluster feeds, feed detail fragments, feed notes, unified feed details, survey
  - name: MyWorkComments
    description: Messaging / comment threads — list, create, reply, close, read-status, transfer
  - name: MyWorkFeedActions
    description: Feed status, reassignment, claim, favorites, RTM actions

security:
  - AuthTokenHeader: []

components:
  securitySchemes:
    AuthTokenHeader:
      type: apiKey
      in: header
      name: X-reflexis-csrf-token-X
      description: Session authentication token validated server-side against the user session store.

  parameters:
    FeedKeyUnderscore:
      name: feed_key
      in: path
      required: true
      schema:
        type: integer
        minimum: 1
      description: Unique numeric feed identifier
    FeedKeyHyphen:
      name: feed-key
      in: path
      required: true
      schema:
        type: integer
      description: Unique numeric feed identifier
    NotesId:
      name: notes_id
      in: path
      required: true
      schema:
        type: integer
      description: Unique note identifier
    ClusterId:
      name: cluster_id
      in: path
      required: true
      schema:
        type: string
      description: Project cluster identifier (must not be blank or "-1")
    RetrieveType:
      name: retrieve-type
      in: path
      required: true
      schema:
        type: string
        enum: [list, count, list-latest]
      description: |
        Retrieve mode:
        - `list` — paginated feed list with cursor-based pagination
        - `count` — aggregated count by priority (requires start_date/end_date)
        - `list-latest` — incremental delta since last fetch timestamp
  schemas:
    JsonObject:
      type: object
      additionalProperties: true
      description: JSON object (structure varies by endpoint).
    JsonResponse:
      type: object
      additionalProperties: true
      description: Typical wrapper with status/response keys (snake_case in many payloads).
    ErrorResponse:
      type: object
      properties:
        status:
          type: string
          enum: [ER]
          description: Always "ER" for error responses
        errorCode:
          type: string
          description: Application-level error code (e.g. E202, E105, E404)
        response:
          type: string
          description: Human-readable error message
      required: [status, errorCode, response]
      example:
        status: ER
        errorCode: E202
        response: User session is invalid

  responses:
    Unauthorized:
      description: Missing or invalid X-reflexis-csrf-token-X session token
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: ER
            errorCode: E202
            response: User session is invalid
    BadRequest:
      description: Invalid or missing request parameter
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    NotFound:
      description: No data found (returned as HTTP 200 with status=ER)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: ER
            errorCode: E404
            response: No data found
    InternalServerError:
      description: Unexpected server-side error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: ER
            errorCode: E302
            response: Internal server error

paths:

  # ---------------------------------------------------------------------------
  # Task — unified config list (/task/v1/config/list)
  # ---------------------------------------------------------------------------
  /task/v1/config/list:
    get:
      tags: [MyWorkConfig]
      summary: Get merged MyWork configuration for requested types
      operationId: getMyWorkConfigList
      description: |
        Returns one or more MyWork configuration domains merged into a **flat** `config_list` object.
        Fields from all requested types appear at the same level under `config_list`.
        When multiple types are requested via comma-separation, fields are merged in enum declaration
        order: `calendar` → `feed` → `attachment` → `smart_search` → `refresh` → `filter` → `feed_component`.

        **Authentication:** `domainId` and `langCode` are always resolved from the validated session.

        ---

        ## Valid Config Types

        | Value | Description | Response Fields |
        |---|---|---|
        | `calendar` | Calendar/Gantt view settings | `default_calendar_view`, `gantt_date_span`, `calendar_setup[]`, `show_all_days` |
        | `feed` | Feed display and metadata | `feed_status_data`, `feed_date_span`, `sort_order[]`, `priority_data`, `overdue_date_span`, `allow_bulk_action`, `no_records`, `proj_status_css`, `fyi_config[]`, `feed_uiconfig`, `project_type_data`, `message_type_data` |
        | `attachment` | Upload constraints | `max_upload_size`, `allowed_attachments`, `comment_max_attach_count`, `button_max_attach_count` |
        | `smart_search` | Smart-search filter config | `sm_filter` (absent if user lacks RSP smart_search permission) |
        | `refresh` | Auto-refresh intervals (ms) | `feed_refresh_rate`, `msg_refresh_rate` |
        | `filter` | Filter panel settings | `max_filter_name_characters`, `filter_date_range`, `max_feed_notes_characters`, `list_task_limit` |
        | `feed_component` | DB-driven feed UI components | `feed_config_details[]` (empty array when none configured) |
        | `all` | All types merged (default) | All fields from every type above |

        ---

        ## Response Fields Reference

        ### `calendar` fields

        | Field | Type | Description |
        |---|---|---|
        | `default_calendar_view` | String | Default view code; empty string if not configured |
        | `gantt_date_span` | String | Number of days shown in Gantt date range |
        | `calendar_setup[]` | Array | Ordered list of calendar sources. Each: `key`, `value`, `on_click`, `view`, `default{layout,view}` |
        | `show_all_days` | String/null | `"Y"` when all calendar days are shown; absent/null otherwise |

        ### `feed` fields

        | Field | Type | Description |
        |---|---|---|
        | `feed_status_data` | Object | Map of status code → `{display_text}`. Keys: `p`, `r`, `c`, `e`, `f`, `n`, `o` |
        | `feed_date_span` | String | Default date span in days for feed list queries |
        | `sort_order[]` | Array | Sort options: each has `key`, `description`, `type` (`numeric`/`character`/`miscellaneous`), `value` (`A`/`D`) |
        | `priority_data` | Object | Map of priority number → `{priority_desc, color, img or img_path}` |
        | `overdue_date_span` | Integer | Days past due before considered overdue |
        | `allow_bulk_action` | String | `"Y"` if bulk actions enabled |
        | `no_records` | String | Default page size for feed list |
        | `proj_status_css` | Object | Map of project status code → CSS style string |
        | `fyi_config[]` | Array | CSS config objects for FYI message rendering |
        | `feed_uiconfig` | Object | UI feature flags: `show_efforts`, `msg_content_expanded`, `show_inactive_tasks`, `due_by_css`, `display_date`, `show_due_by`, `display_day_start_time` |
        | `project_type_data` | Object | Map of project type code → display name |
        | `message_type_data` | Object | Map of message type key → human-readable description |

        ### `attachment` fields

        | Field | Type | Description |
        |---|---|---|
        | `allowed_attachments` | String | Comma-separated permitted file extensions |
        | `max_upload_size` | Integer | Max upload size in bytes (e.g. `1048576` = 1 MB) |
        | `comment_max_attach_count` | Integer | Max attachments per comment |
        | `button_max_attach_count` | Integer | Max attachments per button action |

        ### `refresh` fields

        | Field | Type | Description |
        |---|---|---|
        | `feed_refresh_rate` | Integer | Feed auto-refresh polling interval in milliseconds |
        | `msg_refresh_rate` | Integer | Messaging auto-refresh polling interval in milliseconds |

        ### `filter` fields

        | Field | Type | Description |
        |---|---|---|
        | `max_filter_name_characters` | String | Max character length for a saved filter name |
        | `filter_date_range` | Integer | Default date range in days for filter date pickers |
        | `max_feed_notes_characters` | String | Max character length for feed notes |
        | `list_task_limit` | Integer | Max tasks shown in list view before pagination |

        ### `feed_component` fields

        | Field | Type | Description |
        |---|---|---|
        | `feed_config_details[]` | Array | DB-driven feed UI component overrides. Empty `[]` when none. Each item: `component_id`, `new_image`, `css_content`, `actual_image`, `show_flag` |

        ---

        ## Error Scenarios

        | Scenario | HTTP | Error Code | Message |
        |---|---|---|---|
        | Missing / invalid `X-reflexis-csrf-token-X` | 401 | `E202` | `User session is invalid` |
        | Unknown or empty `config_type` token | 400 | `E203` | `Invalid config type. Valid values: calendar, feed, ...` |
        | Unexpected server-side error | 500 | `E302` | `Internal server error` |

        ## Error Codes Reference

        | Code | Description |
        |---|---|
        | `E202` | User session is invalid |
        | `E203` | Invalid config type |
        | `E302` | Internal server error |
      parameters:
        - name: config_type
          in: query
          required: false
          schema:
            type: string
            default: ALL
            enum: [CALENDAR, FEED, ATTACHMENT, SMART_SEARCH, REFRESH, FILTER, FEED_COMPONENT, ALL]
          description: |
            **Default:** `ALL` (returned when parameter is omitted or set to `all`).
            Case-insensitive. Accepted values (single, comma-separated, or `all`):
            `CALENDAR`, `FEED`, `ATTACHMENT`, `SMART_SEARCH`, `REFRESH`, `FILTER`,
            `FEED_COMPONENT`, `ALL`.
            Any unrecognised token → HTTP 400 E203.
            Example: `?config_type=CALENDAR,FEED` returns only calendar and feed fields.
      responses:
        '200':
          description: |
            Success — `{status: OK, config_list: {...}}`. All requested type fields
            appear **flat** under `config_list`. When `config_type=ALL` or omitted,
            all 7 type field sets are merged together.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
              example:
                status: OK
                config_list:
                  default_calendar_view: ""
                  gantt_date_span: "10"
                  calendar_setup:
                    - key: CALENDAR
                      value: My Projects
                      on_click: FV
                      view: A
                      default:
                        layout: M
                        view: P
                  feed_status_data:
                    p: {display_text: In Progress}
                    r: {display_text: Reviewed}
                    c: {display_text: Completed}
                    e: {display_text: Expired}
                    f: {display_text: Force Closed}
                    n: {display_text: New}
                    o: {display_text: Overdue}
                  feed_date_span: "15"
                  no_records: "20"
                  overdue_date_span: 6
                  allow_bulk_action: "Y"
                  allowed_attachments: png,gif,jpg,jpeg,pdf,docx,pptx,xlsx,csv,txt,zip,mp4
                  max_upload_size: 1048576
                  comment_max_attach_count: 5
                  button_max_attach_count: 3
                  feed_refresh_rate: 15000
                  msg_refresh_rate: 60000
                  filter_date_range: 31
                  max_feed_notes_characters: "8000"
                  max_filter_name_characters: "255"
                  list_task_limit: 5
                  feed_config_details: []
        '400':
          description: |
            **E203** — Invalid config type. Returned when `config_type` contains an unrecognised token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                status: ER
                errorCode: E203
                response: "Invalid config type. Valid values: calendar, feed, attachment, smart_search, refresh, filter, feed_component, all, or comma-separated combination"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  # ---------------------------------------------------------------------------
  # Task — calendar (/task/v1/calendar)
  # ---------------------------------------------------------------------------
  /task/v1/calendar:
    get:
      tags: [MyWorkCalendar]
      summary: Retrieve calendar / Gantt feed data (CALENDAR, STORE_PROJECTS, STORE_WALK_CAL)
      operationId: getCalendarData
      description: |
        Retrieves calendar or Gantt feed data for the authenticated user.
        Corresponds to legacy: `POST /service/rtm/getCalendarData`.

        ---

        ## Source Types

        | `source_id` | RAR? | Response Shape | Sorting | Notes |
        |---|---|---|---|---|
        | `CALENDAR` | No | `feed_details[]` (40+ fields) | Yes | Standard feed data |
        | `STORE_PROJECTS` | Yes | `project_data[]` | Yes | Requires `active_projects`, `local_projects` |
        | `STORE_SUGGESTED_DATE_PROJECTS` | Yes | `project_data[]` | Yes | `local_projects` defaults `"N"` |
        | `STORE_WALK_CAL` | No | `project_data[]` (6 fields) | No | Store walk data; simpler items |

        ---

        ## Session-Derived Parameters (Always Injected — Not Overridable)

        | paramMap Key | Source | Description |
        |---|---|---|
        | `domainId` | `session.getDomainId()` | Tenant domain — always overwritten |
        | `authToken` | Request header | Auth token — always overwritten |
        | `loginAuthToken` | Request header | Same as authToken — always overwritten |
        | `userId` | `session.getUserId()` | User identifier — always overwritten |
        | `profileId` | `session.getProfileId()` | Profile — always overwritten |
        | `deptId` | `session.getDeptId()` | Department — always overwritten |
        | `storeId` | `session.getUnitId()` | Unit ID (mapped as storeId) — always overwritten |
        | `timeZoneLong` | `session.getTimeZoneLong()` | Timezone — always overwritten |

        ## Session-Defaulted Parameters (Client Can Override)

        | paramMap Key | Query Param | Default | Notes |
        |---|---|---|---|
        | `homeDeptId` | `home_dept_id` | `session.getHomeDeptId()` | Affects confidential project filtering |
        | `viewType` | `view_type` | `session.getCurrentView()` | `SV` triggers store-scoped feed query |
        | `cutOffTime` | `cut_off_time` | `"0"` | |
        | `returnType` | `return_type` | `"CAL"` | |
        | `calLayout` | `cal_layout` | `"M"` | Overridden by system filter if `filter_id` used |

        > `selected_dates` is **not a request parameter** — it is derived server-side by iterating
        > all dates between `from_date` and `to_date` in `yyyyMMdd` format.

        ---

        ## `p_` Prefix Parameters

        The `p_` prefixed params use a non-standard mixed-case mapping (`p_sort_column_1` →
        `p_SortColumn1`) used in the downstream template substitution. They cannot be produced
        by standard camelCase conversion and are mapped explicitly.

        | Query Param | Internal Key | Description |
        |---|---|---|
        | `p_requestor_level` | `p_RequestorLevel` | Requestor org level |
        | `p_sort_column_1` | `p_SortColumn1` | Primary sort column name |
        | `p_sort_column_order_1` | `p_SortColumnOrder1` | `1`=asc, `-1`=desc |
        | `p_sort_column_2` | `p_SortColumn2` | Secondary sort column |
        | `p_sort_column_order_2` | `p_SortColumnOrder2` | Sort direction |
        | `p_sort_column_3` | `p_SortColumn3` | Tertiary sort column |
        | `p_sort_column_order_3` | `p_SortColumnOrder3` | Sort direction |

        ---

        ## System Filter / RAR Handling

        When `filter_id` is present and parseable, `FilterService.getSystemFilter()` loads `MwFilterConfig`.
        Three paths follow:
        - **RAR source + filter** → `setRARParameters()` injects filter params, `calLayout` overridden from filter.
        - **Non-RAR filter with router** → `ServiceRouterUtil.authenticateAndExecute()` routes externally.
        - **No filter** → `RTMUpdateService.getCalendarData()` called directly with template substitution.

        ---

        ## Error Scenarios

        | Scenario | HTTP | Error Code | Message |
        |---|---|---|---|
        | Missing / invalid `X-reflexis-csrf-token-X` | 401 | `E202` | `User session is invalid` |
        | Missing `source_id` | 400 | `E140` | `source_id is mandatory` |
        | Missing `from_date` | 400 | `E142` | `from_date is mandatory` |
        | Missing `to_date` | 400 | `E143` | `to_date is mandatory` |
        | `from_date` is after `to_date` | 400 | `E147` | `from_date must not be after to_date` |
        | No data found | 200 | `E404` | `No data found` |
        | Unexpected server-side error | 500 | `E302` | `Internal server error` |

        ## Error Codes Reference

        | Code | Description |
        |---|---|
        | `E140` | `source_id` is mandatory |
        | `E142` | `from_date` is mandatory |
        | `E143` | `to_date` is mandatory |
        | `E147` | `from_date` must not be after `to_date` |
        | `E202` | User session is invalid |
        | `E302` | Internal server error |
        | `E404` | No data found |
      parameters:
        - name: source_id
          in: query
          required: true
          schema:
            type: string
            enum: [CALENDAR, STORE_PROJECTS, STORE_SUGGESTED_DATE_PROJECTS, STORE_WALK_CAL]
          description: |
            **Required.** Calendar data source type. Determines the response data shape:
            - `CALENDAR` → `feed_details[]` with 40+ fields per feed
            - `STORE_PROJECTS` → `project_data[]` with project-level items
            - `STORE_SUGGESTED_DATE_PROJECTS` → `project_data[]` (suggested-date projects)
            - `STORE_WALK_CAL` → `project_data[]` with simpler 6-field items
        - name: from_date
          in: query
          required: true
          schema:
            type: string
            example: "20260315"
          description: |
            **Required.** Range start date in `yyyyMMdd` format (e.g. `20260315`).
            Must not be after `to_date` (lexicographic comparison) → E147 if violated.
        - name: to_date
          in: query
          required: true
          schema:
            type: string
            example: "20260317"
          description: |
            **Required.** Range end date in `yyyyMMdd` format (e.g. `20260317`).
            Server generates `selectedDates` from all dates between `from_date` and `to_date`.
        - name: cal_layout
          in: query
          required: false
          schema:
            type: string
            default: M
            enum: [M, W, D, P]
          description: |
            **Default:** `M`. Calendar layout:
            - `M` = Month view
            - `W` = Week view
            - `D` = Day view
            - `P` = Pinboard view
            May be overridden by `MwFilterConfig` when `filter_id` is used.
        - name: return_type
          in: query
          required: false
          schema:
            type: string
            default: CAL
          description: "**Default:** `CAL`. Return type forwarded to the downstream service."
        - name: cut_off_time
          in: query
          required: false
          schema:
            type: string
            default: '0'
          description: "**Default:** `'0'`. Cut-off time value forwarded to the service."
        - name: home_dept_id
          in: query
          required: false
          schema:
            type: string
          description: |
            **Default:** session `homeDeptId`. Comma-separated home department IDs.
            Affects confidential project visibility — service computes the intersection of
            `deptId` and `homeDeptId` to determine visible confidential projects. Client can
            override by providing this parameter.
        - name: view_type
          in: query
          required: false
          schema:
            type: string
          description: |
            **Default:** session `currentView`. View type forwarded to the service.
            `SV` (Store View) triggers a store-scoped feed query path. The legacy frontend
            always sends this; if the headless client omits it, the session value is used.
        - name: message_type
          in: query
          required: false
          schema:
            type: string
          description: Message type filter (e.g. `PROJECTEXTRACT`). Forwarded to downstream service.
        - name: sort_by
          in: query
          required: false
          schema:
            type: string
          description: |
            Comma-separated sort column names for `CALENDAR` and `STORE_PROJECTS` sources.
            Example: `profileId,endDateTime,priority,startDateTime,feedTitle,feedTypeId`.
            **Not applicable to `STORE_WALK_CAL`** (no sorting supported for walk data).
        - name: sort_order
          in: query
          required: false
          schema:
            type: string
          description: |
            Comma-separated sort directions matching `sort_by` columns.
            Values: `A` (ascending), `D` (descending).
            Example: `D,D,A,A,D,D`.
        - name: week_dates
          in: query
          required: false
          schema:
            type: string
          description: |
            Comma-separated current-week date strings in `yyyyMMdd` format.
            Example: `20260315,20260316,20260317`.
        - name: status
          in: query
          required: false
          schema:
            type: string
          description: |
            Feed status filter. Comma-separated status codes.
            Example: `N,R,P,O,C,F,E`.
            Values: `N`=New, `R`=Reviewed, `P`=In Progress, `O`=Overdue,
            `C`=Completed, `F`=Force-closed, `E`=Expired.
        - name: feed_type_id
          in: query
          required: false
          schema:
            type: string
          description: Feed type identifier filter.
        - name: priority
          in: query
          required: false
          schema:
            type: string
          description: Comma-separated priority number filter (e.g. `1,3,9`).
        - name: local_projects
          in: query
          required: false
          schema:
            type: string
            enum: [Y, N, A]
          description: |
            Local projects flag. Applies to `STORE_PROJECTS` only.
            `Y`=local only, `N`=non-local only, `A`=all.
            Defaults to `"N"` internally for RAR sources if absent.
        - name: active_projects
          in: query
          required: false
          schema:
            type: string
            enum: [Y, N]
          description: |
            Active projects flag. Applies to `STORE_PROJECTS` only.
            `Y`=active only, `N`=all/inactive.
        - name: cal_filter_exc_level
          in: query
          required: false
          schema:
            type: string
          description: Executor org level filter for calendar data.
        - name: cal_filter_unit
          in: query
          required: false
          schema:
            type: string
          description: Unit filter for calendar data.
        - name: cal_filter_org_level
          in: query
          required: false
          schema:
            type: string
          description: Org level filter for calendar data.
        - name: feed_title
          in: query
          required: false
          schema:
            type: string
          description: |
            Feed title search string. The service further URL-encodes it internally via
            `URLEncoder.encode(title, "UTF-8")`. Send the title as-is.
        - name: favorite
          in: query
          required: false
          schema:
            type: string
          description: |
            Favorite filter flag. Send `"1"` to show only favorited feeds.
            Internally maps to `p_Favourite="A"` when value is `"1"`.
        - name: tags
          in: query
          required: false
          schema:
            type: string
          description: Tags filter forwarded to the downstream service.
        - name: filter_id
          in: query
          required: false
          schema:
            type: string
          description: |
            System filter ID. When present and parseable, loads `MwFilterConfig` and triggers
            either RAR parameter injection or `ServiceRouterUtil` external routing.
            After output is produced, adds `layout`, `calendarType`, and `selectedDates`
            (computed via `FeedProcessService.getDateRange()`) to the response.
        - name: p_requestor_level
          in: query
          required: false
          schema:
            type: string
          description: |
            Requestor org level for template substitution. Mapped to `p_RequestorLevel`
            (non-standard casing — cannot be produced by generic camelCase conversion).
            Set to `"null"` if not applicable.
        - name: p_sort_column_1
          in: query
          required: false
          schema:
            type: string
          description: "Primary sort column name for template substitution (maps to `p_SortColumn1`). E.g. `profileId`."
        - name: p_sort_column_order_1
          in: query
          required: false
          schema:
            type: string
          description: "Sort order for column 1 (maps to `p_SortColumnOrder1`). `1`=ascending, `-1`=descending."
        - name: p_sort_column_2
          in: query
          required: false
          schema:
            type: string
          description: "Secondary sort column name (maps to `p_SortColumn2`). E.g. `endDateTime`."
        - name: p_sort_column_order_2
          in: query
          required: false
          schema:
            type: string
          description: "Sort order for column 2 (maps to `p_SortColumnOrder2`). `1`=ascending, `-1`=descending."
        - name: p_sort_column_3
          in: query
          required: false
          schema:
            type: string
          description: "Tertiary sort column name (maps to `p_SortColumn3`). E.g. `priority`."
        - name: p_sort_column_order_3
          in: query
          required: false
          schema:
            type: string
          description: "Sort order for column 3 (maps to `p_SortColumnOrder3`). `1`=ascending, `-1`=descending."
      responses:
        '200':
          description: |
            Success — `{status: OK, calendar_data: {...}}`.
            Response shape depends on `source_id`:
            - `CALENDAR` → `calendar_data.feed_details[]` (full feed records, 40+ fields) + `last_fetch_time`
            - `STORE_PROJECTS` / `STORE_SUGGESTED_DATE_PROJECTS` → `calendar_data.project_data[]`
              Each item: `project_id`, `project_title`, `project_type`, `project_type_desc`, `icon`,
              `start_date`, `end_date`, `priority`, `is_overdue`, `is_completed`, `is_confidential`,
              `is_edited`, `has_survey`, `has_attachment`, `assigned_role`
            - `STORE_WALK_CAL` → `calendar_data.project_data[]`
              Each item: `project_id`, `project_title`, `project_type`, `assigned_to`, `start_date`, `end_date`
            - No data → `{status: ER, error_code: E404, response: "No data found"}`
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
              example:
                status: OK
                calendar_data:
                  feed_details:
                    - feed_key: 45810367
                      feed_title: HO%20Violation%20Project
                      feed_type: T
                      feed_type_id: V12
                      status: O
                      priority: 1
                      start_date_time: "2026-03-31 00:00:00"
                      end_date_time: "2026-03-31 23:59:59"
                      cluster_id: "4293672"
                  last_fetch_time: 1775827383742
        '400':
          description: |
            **E140** — source_id is mandatory.
            **E142** — from_date is mandatory.
            **E143** — to_date is mandatory.
            **E147** — from_date must not be after to_date.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/calendar/leadership:
    get:
      tags: [MyWorkCalendar]
      summary: Retrieve leadership calendar project data (monthly or annual view)
      operationId: getLeadershipCalendarData
      description: |
        Retrieves leadership calendar project data for Monthly (`M`) or Annual (`A`) views.
        Corresponds to legacy: `POST /service/execute/getLeadershipCalendarData`.

        **Always-injected from session:**
        `domainId` and `authToken` are resolved and injected. `ServiceRouterUtil` also auto-injects
        `pulseAuthToken` from `authToken` if absent.

        **Typed value parsing:**
        Since GET query params are strings, the service layer parses:
        - Comma-separated arrays → typed `List` (e.g. `exec_level=1,2` → `List<Integer>`)
        - `show_only_my_projects`, `show_field_projects` → parsed to `Boolean`
        - `month_no`, `year` → parsed to `Integer`

        **Note on absent boolean params:** The legacy frontend sets these from filter state that
        can be `undefined`. When `undefined`, the key is simply absent. The headless API handles
        absent keys gracefully — they are not included in the param map.

        ---

        ## Response Fields — `leadership_data`

        | Field | Type | Description |
        |---|---|---|
        | `leadership_calender_project_data[]` | Array | Leadership project items for the selected period. Each: `project_id`, `project_title`, `project_type`, `start_date` (Integer yyyyMMdd), `end_date`, `span`, `priority`, `legend_id` |
        | `leadership_categories[]` | Array | Available project categories. Each: `id`, `name` |
        | `leadership_admin_legend_details[]` | Array | Legend/color definitions. Each: `id`, `name`, `color` |
        | `notes` | Object | User notes for the period, keyed by date |
        | `monthly_notes` | Object | Monthly notes for the period |

        ---

        ## Error Scenarios

        | Scenario | HTTP | Error Code | Message |
        |---|---|---|---|
        | Missing / invalid `X-reflexis-csrf-token-X` | 401 | `E202` | `User session is invalid` |
        | Missing `cal_type` | 400 | `E144` | `cal_type is mandatory` |
        | Missing `month_no` | 400 | `E145` | `month_no is mandatory` |
        | Missing `year` | 400 | `E146` | `year is mandatory` |
        | No data / service exception | 200 | `E404` | `No data found` |
        | Unexpected server-side error | 500 | `E302` | `Internal server error` |

        ## Error Codes Reference

        | Code | Description |
        |---|---|
        | `E144` | `cal_type` is mandatory |
        | `E145` | `month_no` is mandatory |
        | `E146` | `year` is mandatory |
        | `E202` | User session is invalid |
        | `E302` | Internal server error |
        | `E404` | No data found |
      parameters:
        - name: cal_type
          in: query
          required: true
          schema:
            type: string
            enum: [M, A]
          description: |
            **Required** (→ E144 if missing). Calendar view type:
            - `M` = Monthly view
            - `A` = Annual / Year-at-glance view
        - name: month_no
          in: query
          required: true
          schema:
            type: integer
            minimum: 1
            maximum: 12
          description: |
            **Required** (→ E145 if missing). Month number 1–12.
            Parsed to `Integer` server-side.
        - name: year
          in: query
          required: true
          schema:
            type: integer
            example: 2026
          description: |
            **Required** (→ E146 if missing). Four-digit year (e.g. `2026`).
            Parsed to `Integer` server-side.
        - name: project_type_id
          in: query
          required: false
          schema:
            type: string
          description: |
            Comma-separated project type IDs to filter by (e.g. `TYPE_A,TYPE_B`).
            Parsed to `List<String>` server-side.
        - name: exec_level
          in: query
          required: false
          schema:
            type: string
          description: |
            Comma-separated execution level integers to filter by (e.g. `1,2`).
            Parsed to `List<Integer>` server-side.
        - name: assignments
          in: query
          required: false
          schema:
            type: string
          description: |
            Comma-separated department IDs to filter by.
            Parsed to `List<String>` server-side.
        - name: view_unit
          in: query
          required: false
          schema:
            type: string
          description: Comma-separated unit IDs to scope the leadership view.
        - name: project_title
          in: query
          required: false
          schema:
            type: string
          description: Project title search string (partial match).
        - name: legend_type
          in: query
          required: false
          schema:
            type: string
          description: |
            Comma-separated legend type IDs to filter by.
            Parsed to `List<String>` server-side.
        - name: priority
          in: query
          required: false
          schema:
            type: string
          description: |
            Comma-separated priority numbers to filter by (e.g. `1,3`).
            Parsed to `List<Integer>` server-side.
        - name: show_only_my_projects
          in: query
          required: false
          schema:
            type: string
            enum: ['true', 'false']
          description: |
            **Default:** absent (not sent). Filter to show only the user's own created projects.
            Parsed to `Boolean` server-side. When absent (key not in map), the service handles
            the missing key gracefully — equivalent to `false`.
        - name: show_field_projects
          in: query
          required: false
          schema:
            type: string
            enum: ['true', 'false']
          description: |
            **Default:** absent (not sent). Include field/sub-projects in results.
            Parsed to `Boolean` server-side.
      responses:
        '200':
          description: |
            Success — `{status: OK, leadership_data: {...}}`.
            No data (service exception) → `{status: ER, error_code: E404, response: "No data found"}`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
              example:
                status: OK
                leadership_data:
                  leadership_calender_project_data:
                    - project_id: "4290692"
                      project_title: Q1 Store Refresh
                      project_type: "310"
                      start_date: 20260401
                      end_date: 20260407
                      span: START_END_DATE
                      priority: 2
                      legend_id: LEGEND_1
                  leadership_categories:
                    - id: CAT_1
                      name: Operations
                  leadership_admin_legend_details:
                    - id: LEGEND_1
                      name: High Priority
                      color: "#FF0000"
                  notes: {}
                  monthly_notes: {}
        '400':
          description: |
            **E144** — cal_type is mandatory.
            **E145** — month_no is mandatory.
            **E146** — year is mandatory.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'


  # ---------------------------------------------------------------------------
  # Task — feeds (unified retrieve)
  # ---------------------------------------------------------------------------
  /task/v1/feeds/{retrieve-type}:
    get:
      tags: [MyWorkFeeds]
      summary: Retrieve feeds — list, count, or list-latest (unified endpoint)
      operationId: retrieveFeedsByType
      description: |
        Unified endpoint for three feed retrieval modes controlled by `retrieve-type` path variable.

        **Session-derived values** (`domain_id`, `user_id`, `unit_id`, `dept_id`, `profile_id`,
        `time_zone_long`, `lang_code`) are **always** resolved from the auth token and cannot be
        overridden by query parameters. Query params are auto-converted from `snake_case` to `camelCase`.
        All response keys are returned in `snake_case`.

        ---

        ## Retrieve Types

        | Value | Description |
        |---|---|
        | `list` | Paginated feed list with cursor-based pagination. Supports projections, sorting, all filters. |
        | `count` | Aggregated priority/total counts for a date range. **Requires** `start_date` + `end_date`. |
        | `list-latest` | Incremental delta since a given timestamp for polling. Supports projections but NOT pagination. |

        ---

        ## Parameter Applicability Matrix

        **Legend:** ✅ = accepted/used | **REQ** = required | — = not applicable (silently ignored)

        | Parameter | `list` | `count` | `list-latest` | Default |
        |---|---|---|---|---|
        | `projections` | ✅ | — | ✅ | all default fields |
        | `limit` | ✅ | — | — | 20 |
        | `starting_after` | ✅ | — | — | null |
        | `ending_before` | ✅ | — | — | null |
        | `start_date` | — | **REQ** | — | — |
        | `end_date` | — | **REQ** | — | — |
        | `today_from` | — | — | ✅ | 0 |
        | `from_time` | — | — | ✅ | 0 |
        | `feed_keys` | — | — | ✅ | null |
        | `selected_dates` | ✅ | — | ✅ | null |
        | `cut_off_time` | ✅ | ✅ | — | 0 |
        | `pin` | ✅ | ✅ | ✅ | -1 |
        | `favorite` | ✅ | ✅ | ✅ | -1 |
        | `follow` | ✅ | ✅ | ✅ | -1 |
        | `message_type` | ✅ | ✅ | ✅ | null |
        | `status` | ✅ | ✅ | ✅ | null |
        | `priority` | ✅ | ✅ | ✅ | null |
        | `feed_title` | ✅ | ✅ | ✅ | null |
        | `acknowledge_flag` | ✅ | ✅ | ✅ | -1 |
        | `promote_to_note_flag` | ✅ | ✅ | ✅ | -1 |
        | `com_attr_val` | ✅ | ✅ | ✅ | null |
        | `msg_attr_val` | ✅ | ✅ | ✅ | null |
        | `view_type` | ✅ | ✅ | ✅ | MV |
        | `task_view` | ✅ | ✅ | ✅ | P |
        | `return_type` | ✅ | ✅ | — | null |
        | `feed_type_id` | ✅ | ✅ | ✅ | null |
        | `tags` | ✅ | ✅ | ✅ | null |
        | `sort_by` | ✅ | — | — | null |
        | `sort_order` | ✅ | — | — | null |
        | `return_format` | ✅ | — | — | J |
        | `filter_id` | ✅ | — | ✅ | null |
        | `week_dates` | ✅ | — | ✅ | null |

        ---

        ## Cursor-Based Pagination (list only)

        1. **Initial request:** No cursor params — `GET /task/v1/feeds/list?status=N&limit=20`
        2. **Response includes:** `has_more`, `next_cursor` (base64 opaque), `previous_cursor`, `last_fetch_time`
        3. **Next page (forward):** `?...&starting_after=<next_cursor value>`
        4. **Previous page (backward):** `?...&ending_before=<previous_cursor value>`

        **Rules:**
        - Use only **one** of `starting_after` or `ending_before` per request — providing both → E112
        - Cursors are **opaque strings** — do not parse or construct them manually
        - `limit` is clamped to 1–100: values below 1 default to 20, values above 100 cap at 100
        - `has_more: false` means no further pages in the requested direction

        ---

        ## Projections — Default Fields

        When `projections` is omitted, the following 35 fields are returned for each feed object.
        `feed_key` is **always** included regardless of what is requested.

        `feed_key`, `feed_title`, `message_type`, `status`, `priority`, `feed_type`, `feed_type_id`,
        `cluster_id`, `cluster_child_id`, `start_date_time`, `end_date_time`, `display_launch_date`,
        `create_dtm`, `last_updated_time`, `task_count`, `overdue_task_count`, `pin`, `favorite_flag`,
        `acknowledged_flag`, `is_confidential`, `has_survey`, `title_css`, `panel_config`,
        `assign_to_desc`, `has_comments`, `enable_comment`, `future_feed`, `show_why_url`,
        `has_action`, `enable_action`, `show_how_url`, `has_history`, `has_user_notes`, `has_actions`,
        `has_contents`, `has_key_attributes`

        ## Projections — Additional Available Fields

        These fields are **not** in the default set but can be explicitly requested:

        `transaction_key`, `feed_owner`, `feed_type_id_desc`, `ext_link_info`, `dept_id`,
        `end_date_utc`, `display_start_date`, `last_action_time_in_millis`, `profile_id`,
        `display_date`, `has_predecessor`, `show_acknowledge`, `last_updated_time_in_millis`,
        `event_date`, `additional_attributes`, `show_claim`, `promote_to_note_flag`,
        `update_all_mul_asg_task_attr`, `flag`, `is_edited`, `allow_future_quick_links`,
        `thread_flag`, `acknowledge_flag`, `txn_dtm`, `lock_status`, `start_date_utc`,
        `unit_id`, `last_action_time`, `action_taken_flag`, `time_to_act`, `feed_description`,
        `feed_params`, `event_end_date`, `watch_flag`, `follow`, `user_id`, `feed_task_count`,
        `display_end_date`

        > **Note:** `filter_id` overrides the standard query path — when provided, the system uses
        > the `MwFilterConfig` for data retrieval instead of applying the filter params above.

        ---

        ## Error Scenarios

        | Scenario | HTTP | Error Code | Message |
        |---|---|---|---|
        | Missing / invalid `X-reflexis-csrf-token-X` | 401 | `E202` | `User session is invalid` |
        | Invalid `retrieve-type` value | 400 | `E111` | `Invalid retrieve-type. Allowed values: list, count, list-latest` |
        | Both `starting_after` and `ending_before` provided | 400 | `E112` | `Cannot use both starting_after and ending_before simultaneously.` |
        | Missing `start_date` for `count` | 400 | `E114` | `start_date is required for count.` |
        | Missing `end_date` for `count` | 400 | `E115` | `end_date is required for count.` |
        | Refresh interval exceeded (`list-latest`) | 400 | `E116` | `Refresh interval exceeded maximum allowed limit.` |
        | No data found | 200 | `E404` | `No data found` |

        ## Error Codes Reference

        | Code | Description |
        |---|---|
        | `E111` | Invalid `retrieve-type` path variable |
        | `E112` | Both pagination cursors provided simultaneously |
        | `E114` | Missing `start_date` for count |
        | `E115` | Missing `end_date` for count |
        | `E116` | Refresh interval exceeded for list-latest |
        | `E202` | Invalid or expired authentication token |
        | `E404` | No data found for the given filter criteria |
      parameters:
        - $ref: '#/components/parameters/RetrieveType'
        # Projection / Pagination
        - name: projections
          in: query
          schema:
            type: string
          description: |
            Comma-separated field names to include in each feed object (list, list-latest).
            Default set includes 35+ core fields. `feed_key` is always included.
            Additional available fields: `transaction_key`, `feed_owner`, `ext_link_info`,
            `dept_id`, `end_date_utc`, `additional_attributes`, `watch_flag`, `feed_params`, etc.
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            minimum: 1
            maximum: 100
          description: Max records per page (list only; clamped to 1-100)
        - name: starting_after
          in: query
          schema:
            type: string
          description: Forward pagination cursor — use `next_cursor` from previous response (list only)
        - name: ending_before
          in: query
          schema:
            type: string
          description: Backward pagination cursor — use `previous_cursor` from previous response (list only)
        # count-only required params
        - name: start_date
          in: query
          schema:
            type: string
          description: "Start date in YYYYMMDD format. **Required** for `count` retrieve-type."
        - name: end_date
          in: query
          schema:
            type: string
          description: "End date in YYYYMMDD format. **Required** for `count` retrieve-type."
        # list-latest specific
        - name: today_from
          in: query
          schema:
            type: integer
            format: int64
            default: 0
          description: Epoch ms for today reference point (list-latest only)
        - name: from_time
          in: query
          schema:
            type: integer
            format: int64
            default: 0
          description: Epoch ms of last fetch time — validated against max refresh interval (list-latest only)
        - name: feed_keys
          in: query
          schema:
            type: string
          description: Comma-separated feed keys to check for updates (list-latest only)
        # Common filter params
        - name: selected_dates
          in: query
          schema:
            type: string
          description: "Comma-separated dates in YYYYMMDD format (e.g. 20260309,20260324). Applies to list, list-latest."
        - name: cut_off_time
          in: query
          schema:
            type: integer
            format: int64
            default: 0
          description: Cut-off time in epoch ms (list, count)
        - name: pin
          in: query
          schema:
            type: integer
            default: -1
          description: "Pin filter: -1=all, 0=not pinned, 1=pinned"
        - name: favorite
          in: query
          schema:
            type: integer
            default: -1
          description: "Favorite filter: -1=all, 0=not favorite, 1=favorite"
        - name: follow
          in: query
          schema:
            type: integer
            default: -1
          description: "Follow filter: -1=all"
        - name: message_type
          in: query
          schema:
            type: string
          description: Feed message type code (e.g. DOWNLOADFILEMSG, PROJECTEXTRACT, RWS41_ADVERTISE_SHIFT_RES_MANAGER_NOTIFICATIONS)
        - name: status
          in: query
          schema:
            type: string
          description: "Comma-separated status codes: N=New, R=Reviewed, P=In Progress, O=Overdue, C=Completed, F=Force-closed, E=Expired"
        - name: priority
          in: query
          schema:
            type: string
          description: Comma-separated priority integers (e.g. `4` or `1,2,3`)
        - name: feed_title
          in: query
          schema:
            type: string
          description: Text search on feed title (URL-encoded values are auto-decoded)
        - name: acknowledge_flag
          in: query
          schema:
            type: integer
            default: -1
          description: "Acknowledge filter: -1=all, 0=not acknowledged, 1=acknowledged"
        - name: promote_to_note_flag
          in: query
          schema:
            type: integer
            default: -1
          description: "Promote-to-note filter: -1=all"
        - name: com_attr_val
          in: query
          schema:
            type: string
          description: Communication attribute value filter
        - name: msg_attr_val
          in: query
          schema:
            type: string
          description: Message attribute value filter
        - name: view_type
          in: query
          schema:
            type: string
            default: MV
            enum: [MV, DV, SV]
          description: "View type: MV=My View, DV=Department View, SV=Store View"
        - name: task_view
          in: query
          schema:
            type: string
            default: P
            enum: [P, T]
          description: "Display view: P=Project View, T=Task View"
        - name: return_type
          in: query
          schema:
            type: string
          description: Return type filter (e.g. CALENDAR)
        - name: feed_type_id
          in: query
          schema:
            type: string
          description: Feed type ID filter (e.g. CL0)
        - name: tags
          in: query
          schema:
            type: string
          description: Tags filter
        - name: filter_id
          in: query
          schema:
            type: string
          description: System filter ID — when provided, uses MwFilterConfig for data retrieval (list, list-latest)
        - name: week_dates
          in: query
          schema:
            type: string
          description: "Comma-separated week dates in YYYYMMDD format (e.g. 20260322,20260323,...,20260328)"
        # list-only sort/format params
        - name: sort_by
          in: query
          schema:
            type: string
          description: "Comma-separated sort columns (list only): profileId, endDateTime, priority, startDateTime, feedTitle, feedTypeId"
        - name: sort_order
          in: query
          schema:
            type: string
          description: "Comma-separated sort directions matching sort_by (list only): A=ascending, D=descending"
        - name: return_format
          in: query
          schema:
            type: string
            default: J
          description: "Return format (list only): J=JSON"
      responses:
        '200':
          description: |
            **list** → `{feed_details[], previous_cursor, next_cursor, has_more, last_fetch_time}` — or E404 no data.
            **count** → `{count_data: {priorities[], total}}`.
            **list-latest** → `{feed_list_latest[], status}`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
              example:
                status: OK
                feed_details: []
                previous_cursor: null
                next_cursor: eyJza2lwIjoyMH0=
                has_more: true
                last_fetch_time: 1774373200310
        '400':
          description: |
            - E111 — invalid retrieve-type
            - E112 — both starting_after and ending_before provided
            - E114 — missing start_date for count
            - E115 — missing end_date for count
            - E116 — refresh interval exceeded for list-latest
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/feeds/list/tasks:
    get:
      tags: [MyWorkFeeds]
      summary: Task-view feeds with cursor pagination (forces view_type=TV)
      operationId: retrieveFeedsTasks
      description: |
        Retrieves a paginated list of **task-only** feeds. Identical to `retrieve-type=list` but
        `view_type` is **automatically set to `TV` (Task View)** server-side, regardless of any
        value sent by the client. Sending `view_type` is harmless but it will be overridden.

        Supports cursor-based pagination (same rules as `/feeds/list`), sorting, projections,
        and all standard feed filters.

        ## Cursor-Based Pagination

        1. Initial: `GET /task/v1/feeds/list/tasks?status=N&limit=20`
        2. Next page: add `starting_after=<next_cursor from response>`
        3. Prev page: add `ending_before=<previous_cursor from response>`
        4. Use only **one** of `starting_after` / `ending_before` per request (both → E112)
        5. `limit` clamped to 1–100 (below 1 defaults to 20, above 100 caps at 100)

        ---

        ## Projections — Default Fields

        When `projections` is omitted, the following fields are returned per feed object:

        `feed_key`, `feed_title`, `message_type`, `status`, `priority`, `feed_type`, `feed_type_id`,
        `cluster_id`, `cluster_child_id`, `start_date_time`, `end_date_time`, `display_launch_date`,
        `create_dtm`, `last_updated_time`, `task_count`, `overdue_task_count`, `pin`, `favorite_flag`,
        `acknowledged_flag`, `is_confidential`, `has_survey`, `title_css`, `panel_config`,
        `assign_to_desc`, `has_comments`, `enable_comment`, `future_feed`, `show_why_url`,
        `has_action`, `enable_action`, `show_how_url`, `has_history`, `has_user_notes`,
        `has_actions`, `has_contents`, `has_key_attributes`

        ## Projections — Additional Available Fields

        `transaction_key`, `feed_owner`, `feed_type_id_desc`, `ext_link_info`, `dept_id`,
        `end_date_utc`, `display_start_date`, `last_action_time_in_millis`, `profile_id`,
        `display_date`, `has_predecessor`, `show_acknowledge`, `last_updated_time_in_millis`,
        `event_date`, `additional_attributes`, `show_claim`, `promote_to_note_flag`,
        `update_all_mul_asg_task_attr`, `flag`, `is_edited`, `allow_future_quick_links`,
        `thread_flag`, `acknowledge_flag`, `txn_dtm`, `lock_status`, `start_date_utc`,
        `unit_id`, `last_action_time`, `action_taken_flag`, `time_to_act`, `feed_description`,
        `feed_params`, `event_end_date`, `watch_flag`, `follow`, `user_id`, `feed_task_count`,
        `display_end_date`

        ---

        ## Error Scenarios

        | Scenario | HTTP | Error Code | Message |
        |---|---|---|---|
        | Missing / invalid `X-reflexis-csrf-token-X` | 401 | `E202` | `User session is invalid` |
        | Both `starting_after` and `ending_before` | 400 | `E112` | `Cannot use both starting_after and ending_before simultaneously.` |
        | No data found | 200 | `E404` | `No data found` |

        ## Error Codes Reference

        | Code | Description |
        |---|---|
        | `E112` | Both pagination cursors provided simultaneously |
        | `E202` | Invalid or expired authentication token |
        | `E404` | No data found for the given filter criteria |
      parameters:
        - name: projections
          in: query
          schema:
            type: string
          description: Comma-separated field names to include in each feed object
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            minimum: 1
            maximum: 100
          description: Max records per page (clamped to 1-100)
        - name: starting_after
          in: query
          schema:
            type: string
          description: Forward pagination cursor (use next_cursor from previous response)
        - name: ending_before
          in: query
          schema:
            type: string
          description: Backward pagination cursor (use previous_cursor from previous response)
        - name: selected_dates
          in: query
          schema:
            type: string
          description: Comma-separated dates in YYYYMMDD format
        - name: cut_off_time
          in: query
          schema:
            type: integer
            format: int64
            default: 0
          description: Cut-off time in epoch ms
        - name: pin
          in: query
          schema:
            type: integer
            default: -1
          description: "Pin filter: -1=all, 0=not pinned, 1=pinned"
        - name: favorite
          in: query
          schema:
            type: integer
            default: -1
          description: "Favorite filter: -1=all, 0=not favorite, 1=favorite"
        - name: follow
          in: query
          schema:
            type: integer
            default: -1
          description: "Follow filter: -1=all"
        - name: message_type
          in: query
          schema:
            type: string
          description: Feed message type code
        - name: status
          in: query
          schema:
            type: string
          description: "Comma-separated status codes: N, R, P, O, C, F, E"
        - name: priority
          in: query
          schema:
            type: string
          description: Comma-separated priority integers
        - name: feed_title
          in: query
          schema:
            type: string
          description: Text search on feed title (URL-encoded, auto-decoded)
        - name: acknowledge_flag
          in: query
          schema:
            type: integer
            default: -1
          description: "Acknowledge filter: -1=all, 0=not acknowledged, 1=acknowledged"
        - name: promote_to_note_flag
          in: query
          schema:
            type: integer
            default: -1
          description: "Promote-to-note filter"
        - name: com_attr_val
          in: query
          schema:
            type: string
          description: Communication attribute value filter
        - name: msg_attr_val
          in: query
          schema:
            type: string
          description: Message attribute value filter
        - name: task_view
          in: query
          schema:
            type: string
            default: P
            enum: [P, T]
          description: "Display view: P=Project View, T=Task View"
        - name: return_type
          in: query
          schema:
            type: string
          description: Return type filter
        - name: sort_by
          in: query
          schema:
            type: string
          description: Comma-separated sort columns
        - name: sort_order
          in: query
          schema:
            type: string
          description: "Comma-separated sort directions: A=ascending, D=descending"
        - name: feed_type_id
          in: query
          schema:
            type: string
          description: Feed type ID filter
        - name: return_format
          in: query
          schema:
            type: string
            default: J
          description: "Return format: J=JSON"
        - name: tags
          in: query
          schema:
            type: string
          description: Tags filter
        - name: filter_id
          in: query
          schema:
            type: string
          description: System filter ID
        - name: week_dates
          in: query
          schema:
            type: string
          description: Comma-separated week dates in YYYYMMDD format
      responses:
        '200':
          description: |
            Success — `{feed_details[], previous_cursor, next_cursor, has_more, last_fetch_time}`

            **list response fields:**

            | Field | Type | Description |
            |---|---|---|
            | `feed_details[]` | Array | Feed objects (fields controlled by `projections`) |
            | `has_more` | Boolean | `true` if more records available after current page |
            | `next_cursor` | String | Opaque cursor for next page — use with `starting_after`. `null` if no more pages. |
            | `previous_cursor` | String | Opaque cursor for previous page — use with `ending_before`. `null` if on first page. |
            | `last_fetch_time` | Long | Epoch ms when data was fetched |

            **count response fields:**

            | Field | Type | Description |
            |---|---|---|
            | `count_data.priorities[]` | Array | Each: `name` (priority), `id`, `value` (count as String) |
            | `count_data.total` | Integer | Total count across all priorities |

            **list-latest response fields:**

            | Field | Type | Description |
            |---|---|---|
            | `feed_list_latest[]` | Array | Feed objects changed/added since `from_time` |
            | `status` | String | `OK` on success |
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
              example:
                status: OK
                feed_details:
                  - feed_key: 44814719
                    feed_title: Your%20request%20for%20download
                    status: R
                    priority: 1
                    message_type: DOWNLOADFILEMSG
                    cluster_id: SYSADMIN_1773851291103
                    cluster_child_id: "-1"
                    start_date_time: "2026-03-18 11:28:13"
                    end_date_time: "2026-03-25 11:28:08"
                    pin: 0
                    favorite_flag: false
                    has_survey: false
                    enable_action: true
                previous_cursor: null
                next_cursor: eyJza2lwIjoyMH0=
                has_more: true
                last_fetch_time: 1774373200310
        '400':
          description: |
            **E111** — Invalid retrieve-type (allowed: list, count, list-latest).
            **E112** — Both starting_after and ending_before provided simultaneously.
            **E114** — start_date required for count.
            **E115** — end_date required for count.
            **E116** — Refresh interval exceeded for list-latest.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                status: ER
                errorCode: E112
                response: Cannot use both starting_after and ending_before simultaneously.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/feeds/{cluster_id}/cluster-list:
    get:
      tags: [MyWorkFeeds]
      summary: All feeds for a project cluster (no pagination)
      operationId: retrieveClusterFeeds
      description: |
        Returns **all** feeds belonging to a specific project cluster in one call.
        Does **not** support cursor-based pagination.
        `cluster_id` must not be blank or `"-1"` (→ E108).
        Empty results → E117 (not an empty array).

        ## Projections — Default Fields

        When `projections` is omitted, the following fields are returned per feed:
        `feed_key`, `feed_title`, `message_type`, `status`, `priority`, `feed_type`, `feed_type_id`,
        `cluster_id`, `cluster_child_id`, `start_date_time`, `end_date_time`, `display_launch_date`,
        `create_dtm`, `last_updated_time`, `task_count`, `overdue_task_count`, `pin`, `favorite_flag`,
        `acknowledged_flag`, `is_confidential`, `has_survey`, `title_css`, `panel_config`,
        `assign_to_desc`, `has_comments`, `enable_comment`, `future_feed`, `show_why_url`,
        `has_action`, `enable_action`, `show_how_url`, `has_history`, `has_user_notes`,
        `has_actions`, `has_contents`, `has_key_attributes`

        ## Projections — Additional Available Fields

        `transaction_key`, `feed_owner`, `feed_type_id_desc`, `ext_link_info`, `dept_id`,
        `end_date_utc`, `display_start_date`, `last_action_time_in_millis`, `profile_id`,
        `display_date`, `has_predecessor`, `show_acknowledge`, `last_updated_time_in_millis`,
        `event_date`, `additional_attributes`, `show_claim`, `promote_to_note_flag`,
        `update_all_mul_asg_task_attr`, `flag`, `is_edited`, `allow_future_quick_links`,
        `thread_flag`, `acknowledge_flag`, `txn_dtm`, `lock_status`, `start_date_utc`,
        `unit_id`, `last_action_time`, `action_taken_flag`, `time_to_act`, `feed_description`,
        `feed_params`, `event_end_date`, `watch_flag`, `follow`, `user_id`, `feed_task_count`,
        `display_end_date`

        ## Path Parameters

        | Parameter | Type | Required | Description |
        |---|---|---|---|
        | `cluster_id` | String | Yes | Project cluster identifier. Must not be blank or `"-1"`. |

        ## Error Scenarios

        | Scenario | HTTP | Error Code | Message |
        |---|---|---|---|
        | Missing / invalid `X-reflexis-csrf-token-X` | 401 | `E202` | `User session is invalid` |
        | `cluster_id` is blank or `"-1"` | 400 | `E108` | `Cluster Id is mandatory` |
        | No feeds found for the cluster | 200 | `E117` | `No project record found for the given cluster_id.` |

        ## Error Codes Reference

        | Code | Description |
        |---|---|
        | `E108` | Invalid or missing `cluster_id` path parameter |
        | `E117` | No feeds found for the given cluster |
        | `E202` | Invalid or expired authentication token |
      parameters:
        - $ref: '#/components/parameters/ClusterId'
        - name: view_type
          in: query
          schema:
            type: string
            default: MV
            enum: [MV, DV, SV]
          description: "View type: MV=My View, DV=Department View, SV=Store View"
        - name: status
          in: query
          schema:
            type: string
          description: "Comma-separated status codes to filter (e.g. N,R,P,C)"
        - name: projections
          in: query
          schema:
            type: string
          description: Comma-separated field names to include in each feed object
      responses:
        '200':
          description: Success — `cluster_feed_list[]` or E117 no-project error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
              example:
                status: OK
                cluster_feed_list: []
        '400':
          description: E108 — cluster_id is mandatory (blank or -1)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/feeds/{feed_key}/key-attributes:
    get:
      tags: [MyWorkFeeds]
      summary: Key attributes and extra attributes for a feed
      operationId: getFeedKeyAttributes
      description: |
        Retrieves key attributes for a feed in two groups: `key_attr[]` (display-worthy attributes)
        and `extra_attr[]` (internal configuration flags).
        Empty/null result → E404. Result is always wrapped in an array with one element.

        ## Path Parameters

        | Parameter | Type | Required | Description |
        |---|---|---|---|
        | `feed_key` | Integer | Yes | Unique numeric feed identifier |

        ## Response Structure

        The `response[]` array contains one element with two named arrays:

        ```json
        [
          { "key_attr": [ {"id","type","key","desc","value","resource_key?"} ] },
          { "extra_attr": [ {"type","key","desc","value"} ] }
        ]
        ```

        **Attribute fields:**

        | Field | Type | Description |
        |---|---|---|
        | `id` | String | Attribute sequence identifier (present in `key_attr`) |
        | `type` | String | `FEED` (feed-level) or `I` (instance-level) |
        | `key` | String | Attribute key name (e.g. `displayStartDate`, `IN_MSG_Originator_Name`) |
        | `desc` | String | Human-readable label (translated when available) |
        | `value` | String | Attribute value; URL-encoded for non-ASCII content; empty string if not set |
        | `resource_key` | String | i18n resource key; absent when not configured |

        ## Error Scenarios

        | Scenario | HTTP | Error Code | Message |
        |---|---|---|---|
        | Missing / invalid `X-reflexis-csrf-token-X` | 401 | `E202` | `User session is invalid` |
        | Domain ID not resolvable | 400 | `E101` | `Domain id is mandatory` |
        | No key attributes found | 500 | `E404` | `No data found` |
        | Unexpected server-side error | 500 | `E500` | `Unexpected server error.` |

        ## Error Codes Reference

        | Code | Description |
        |---|---|
        | `E101` | Domain ID is mandatory |
        | `E202` | User session is invalid |
        | `E404` | No data found |
        | `E500` | Unexpected server error |
      parameters:
        - $ref: '#/components/parameters/FeedKeyUnderscore'
      responses:
        '200':
          description: Success — `{status, response[{key_attr[]}, {extra_attr[]}]}`
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/feeds/{feed_key}/history:
    get:
      tags: [MyWorkFeeds]
      summary: Feed audit thread / history (most recent first)
      operationId: getFeedHistory
      description: |
        Returns feed audit history ordered by `action_time` descending (most recent first).
        If `transaction_key` is not provided, it is extracted from the feed record automatically
        (an extra feed lookup is required when omitted).
        Empty history → `NO_DATA_FOUND` error (not an empty array).

        ## Path Parameters

        | Parameter | Type | Required | Description |
        |---|---|---|---|
        | `feed_key` | Integer | Yes | Unique feed identifier (→ E105 if ≤ 0 or missing) |

        ## Response Fields — `feed_threads[*]`

        | Field | Type | Description |
        |---|---|---|
        | `feed_key` | Integer | Feed identifier |
        | `action_seq` | String | Action label (e.g. "Reviewed", "Event Viewed") |
        | `user_id` | String | ID of the user who performed the action |
        | `user_name` | String | Display name |
        | `user_level` | Integer | Permission level at time of action |
        | `creation_time` | String | Formatted timestamp |
        | `result` | String | Outcome description |
        | `action_id` | String | Action type code (e.g. `VIEW_EVENT`); may be absent |
        | `comments` | String | Comments attached (empty string if none) |
        | `attachments` | String | Comma-separated attachment IDs (empty string if none) |
        | `attach_names` | String | Attachment display names (empty string if none) |
        | `comment_flag` | String | `"1"` if comments exist, `"0"` otherwise |
        | `form_flag` | String | `"1"` if form data attached |
        | `attach_flag` | String | `"1"` if attachments present |
        | `request_params` | String | JSON string of request parameters |
        | `context_params` | String | JSON string of context parameters |
        | `param_params` | String | Additional parameter data |
        | `form_params` | String | Form-related parameters |

        ## Error Scenarios

        | Scenario | HTTP | Error Code | Message |
        |---|---|---|---|
        | Missing / invalid `X-reflexis-csrf-token-X` | 401 | `E202` | `User session is invalid` |
        | Missing or invalid `feed_key` (≤ 0) | 400 | `E105` | `Please provide valid feedKey.` |
        | No thread data found | 200 | `NO_DATA_FOUND` | `No data found` |
        | DB connection error (AuditActionDao null) | 500 | `E500` | `AuditActionDao is not initialized` |
        | Unexpected server-side error | 500 | `E500` | `Unexpected server error.` |

        ## Error Codes Reference

        | Code | Description |
        |---|---|
        | `E105` | Invalid or missing feedKey parameter |
        | `E202` | User session is invalid |
        | `E500` | Unexpected server error |
        | `NO_DATA_FOUND` | No thread data available |
      parameters:
        - $ref: '#/components/parameters/FeedKeyUnderscore'
        - name: transaction_key
          in: query
          schema:
            type: string
            default: '0'
          description: Transaction key for filtering specific thread history. Auto-extracted from feed if omitted.
      responses:
        '200':
          description: Success — `feed_threads[]` or NO_DATA_FOUND
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
              example:
                feed_threads:
                  - feed_key: 42893020
                    action_seq: Event Viewed
                    user_id: SYSADMIN
                    user_name: System Administrator
                    user_level: 0
                    creation_time: "10-03-2026 04:31 AM"
                    result: Event viewed by the user
                    action_id: VIEW_EVENT
                    comments: ""
                    attachments: ""
                    comment_flag: ""
                    form_flag: ""
                    attach_flag: ""
        '400':
          description: E105 — invalid or missing feed_key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/feeds/{feed_key}/pre-requisites:
    get:
      tags: [MyWorkFeeds]
      summary: Feed prerequisites / other attributes
      operationId: getFeedPrerequisites
      description: |
        Retrieves pre-requisite definitions and values for a feed.
        Response key is `pre_requisites[]`.
        Empty/null → NO_DATA_FOUND error.
      parameters:
        - $ref: '#/components/parameters/FeedKeyUnderscore'
      responses:
        '200':
          description: Success — `pre_requisites[]`
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
              example:
                pre_requisites:
                  - type: FEED
                    value: "11ccsc"
                    key: Q1
                    desc: Q1
        '400':
          description: E105 — invalid or missing feed_key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/feeds/{feed_key}/content:
    get:
      tags: [MyWorkFeeds]
      summary: Feed HTML file-backed description content
      operationId: getFeedContent
      description: |
        Retrieves the HTML description content for a feed. Only feeds with description
        type `"FILE"` return content. The `contents` field contains raw HTML with dynamic
        token replacements applied by the service layer.

        **Processing steps:**
        1. Validates `feed_key` > 0
        2. Retrieves feed record
        3. Parses `feedDescription` JSON: `{"type":"FILE","fileKey":"...","entity":"filename.html"}`
        4. If type ≠ `"FILE"` or parsing fails → E404
        5. Fetches file content via `FeedProcessService.getFeedDescription()`
        6. Applies token replacements (see below)
        7. Returns content in `{status: OK, contents: "..."}` wrapper

        **Token replacements applied to content:**

        | Token | Replaced with |
        |---|---|
        | `$$authToken$$` | Authentication token |
        | `$Session_userId$` | User ID from session |
        | `$Session_userName$` | User name from session |
        | `$Session_unitId$` | Unit ID from session |
        | `$Param_taskId$` | Feed's cluster child ID |
        | `$Param_status$` | Feed's status |
        | `$Param_initiativeId$` | Feed's cluster ID |
        | `$Session_parentUnitId$` | Feed's parent unit ID |

        ## Path Parameters

        | Parameter | Type | Required | Description |
        |---|---|---|---|
        | `feed_key` | Integer | Yes | Unique numeric feed identifier (→ E105 if ≤ 0) |

        ## Error Scenarios

        | Scenario | HTTP | Error Code | Message |
        |---|---|---|---|
        | Missing / invalid `X-reflexis-csrf-token-X` | 401 | `E202` | `User session is invalid` |
        | Missing or invalid `feed_key` (≤ 0) | 400 | `E105` | `Please provide valid feed_key.` |
        | Feed record not found | 200 | `E404` | `Feed not found` |
        | Feed description is null or empty | 500 | `E404` | `No data found` |
        | Feed description type is not `"FILE"` | 500 | `E404` | `No data found` |
        | Feed description is invalid JSON | 500 | `E404` | `No data found` |
        | File content retrieval returns empty/null | 500 | `E404` | `No data found` |
        | Unexpected server-side error | 500 | `E500` | `Unexpected server error.` |

        ## Error Codes Reference

        | Code | Description |
        |---|---|
        | `E105` | Invalid or missing feed_key |
        | `E202` | User session is invalid |
        | `E404` | No data found / Feed not found |
        | `E500` | Unexpected server error |
      parameters:
        - $ref: '#/components/parameters/FeedKeyUnderscore'
      responses:
        '200':
          description: 'Success — `{status: OK, contents: "<html>..."}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
              example:
                status: OK
                contents: "<p>Task instructions go here...</p>"
        '400':
          description: E105 — invalid or missing feed_key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/feeds/{feed_key}/notes:
    get:
      tags: [MyWorkFeeds]
      summary: List all notes on a feed
      operationId: getFeedNotes
      description: |
        Retrieves all notes associated with the specified feed.
        Returns `feed_notes_arr[]` — an **empty array** is a valid OK response (no notes).
        Service null → E303. Requires `FEED_ACCESS` line-of-sight authorization.

        ## Path Parameters

        | Parameter | Type | Required | Description |
        |---|---|---|---|
        | `feed_key` | Integer | Yes | Numeric key identifying the feed item |

        ## Response Fields — `feed_notes_arr[*]`

        | Field | Type | Description |
        |---|---|---|
        | `domain_id` | Integer | Domain ID |
        | `feed_key` | Integer | Feed key the note belongs to |
        | `notes_id` | Integer | Unique note identifier |
        | `unit_id` | String | Unit identifier |
        | `cluster_id` | String | Cluster identifier |
        | `cluster_child_id` | String | Cluster child identifier |
        | `creator_id` | String | User ID of the note creator |
        | `creator_name` | String | Display name of the note creator |
        | `notes_content` | String | Text content of the note |
        | `creation_time` | String | Formatted creation timestamp |
        | `last_updated_time` | String | Formatted last-update timestamp |

        ## Error Scenarios

        | Scenario | HTTP | Error Code | Message |
        |---|---|---|---|
        | Missing / invalid `X-reflexis-csrf-token-X` | 401 | `E202` | `User session is invalid` |
        | Service returned null | 200 | `E303` | `Unable to fetch notes` |
        | Unexpected server-side error | 500 | `E302` | `Internal server error` |

        ## Error Codes Reference

        | Code | Description |
        |---|---|
        | `E202` | User session is invalid |
        | `E302` | Internal server error |
        | `E303` | Unable to fetch notes |
      parameters:
        - $ref: '#/components/parameters/FeedKeyUnderscore'
      responses:
        '200':
          description: 'Success — `{status: OK, feed_notes_arr[]}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
              example:
                status: OK
                feed_notes_arr:
                  - notes_id: 42
                    feed_key: 101
                    unit_id: UNIT_01
                    cluster_id: CLUSTER_A
                    cluster_child_id: CHILD_B
                    creator_id: SYSADMIN
                    creator_name: System Administrator
                    notes_content: Sample note content
                    creation_time: "2024-01-15 10:00:00"
                    last_updated_time: "2024-01-15 11:00:00"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

    post:
      tags: [MyWorkFeeds]
      summary: Add a note to a feed
      operationId: addFeedNote
      description: |
        Adds a new note to the specified feed.
        Requires `FEED_ACCESS` line-of-sight authorization.
        Returns the newly created note under `feed_note`.
      parameters:
        - $ref: '#/components/parameters/FeedKeyUnderscore'
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required: [cluster_id, cluster_child_id, notes_content]
              properties:
                cluster_id:
                  type: string
                  description: "Cluster identifier (mandatory — E108 if missing)"
                cluster_child_id:
                  type: string
                  description: "Cluster child identifier (mandatory — E109 if missing)"
                notes_content:
                  type: string
                  description: "Text content of the note (mandatory — E110 if missing)"
      responses:
        '200':
          description: 'Success — `{status: OK, feed_note: {...}}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '400':
          description: "E108 cluster_id mandatory / E109 cluster_child_id mandatory / E110 notes_content mandatory"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/feeds/{feed_key}/notes/{notes_id}:
    put:
      tags: [MyWorkFeeds]
      summary: Update a feed note
      operationId: updateFeedNote
      description: |
        Updates the content of an existing note on the feed.
        Requires `FEED_ACCESS` line-of-sight authorization.
      parameters:
        - $ref: '#/components/parameters/FeedKeyUnderscore'
        - $ref: '#/components/parameters/NotesId'
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required: [notes_content]
              properties:
                notes_content:
                  type: string
                  description: "Updated text content for the note (mandatory — E110 if missing)"
      responses:
        '200':
          description: 'Success — `{status: OK, feed_note: {...}}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '400':
          description: E110 — notes_content is mandatory
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

    delete:
      tags: [MyWorkFeeds]
      summary: Delete a feed note
      operationId: deleteFeedNote
      description: |
        Deletes the specified note from the feed.
        Requires `FEED_ACCESS` line-of-sight authorization.
      parameters:
        - $ref: '#/components/parameters/FeedKeyUnderscore'
        - $ref: '#/components/parameters/NotesId'
      responses:
        '200':
          description: 'Success — `{status: OK, message: "Feed note deleted successfully."}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/feeds/{feed_key}/details:
    get:
      tags: [MyWorkFeeds]
      summary: Unified feed details — one call, multiple section projections
      operationId: getFeedDetails
      description: |
        Returns complete feed detail data for a single feed shaped by the `projection` query parameter.
        The client requests only the sections it needs, avoiding multiple round-trips.
        Each section is fetched independently — a failure in one section does not abort others.
        Unrecognised projection names are silently ignored.
        Omitting `projection` (or leaving it empty) returns **only** the `basic` section.

        **Response wrapper:** All sections appear under `feed_details`. Feed not found → entire
        response returns `NO_DATA_FOUND` (not per-section).

        ---

        ## Path Parameters

        | Parameter | Type | Required | Constraints | Description |
        |---|---|---|---|---|
        | `feed_key` | Integer | Yes | ≥ 1 | Unique feed identifier (→ E105 if ≤ 0 or missing) |

        ---

        ## Projection → Response Key Mapping

        | `projection` value | Response key under `feed_details` | Type | Notes |
        |---|---|---|---|
        | `basic` | `feed_basic` | Object | Core feed + cluster/CSS/completion data. Always fetched if feed not found → NO_DATA_FOUND |
        | `contents` | `feed_contents` | String (HTML) | FILE-type descriptions only; absent if no file-based content |
        | `history` | `feed_history` | Array | Audit trail, most recent first |
        | `key_attributes` | `feed_key_attributes` | Array | Two groups: `{key_attr[]}` and `{extra_attr[]}` |
        | `notes` | `feed_notes` | Array | Omitted entirely when no notes (not an empty array) |
        | `actions` | `feed_actions` | Array | Available action panels/buttons for current user |
        | `survey` | `feed_survey` | Array | Empty/omitted for COMPLEX and FORM survey types |
        | `comments` | `feed_comments` | Array | Only for feeds with a `cluster_id` (project feeds) |

        **Key presence rules:**

        | State | Key in response |
        |---|---|
        | Projection not requested | Key **absent** |
        | Projection requested, no data | Key present with empty value (`[]` or `""`) |
        | Projection requested, data found | Key present with populated value |

        Exception: `feed_notes` is absent entirely (not `[]`) when there are no notes.

        ---

        ## `feed_basic` — Supplementary Fields

        Standard feed record fields plus:

        | Field | Type | Present when | Description |
        |---|---|---|---|
        | `last_fetch_time` | Long | Feed exists | Epoch ms timestamp |
        | `allow_completion` | Object | Always | `{complete: Boolean, message: String, panel?: ...}` |
        | `allow_completion_flag` | Boolean | Always | `true` if current user can complete the feed |
        | `feed_css` | Object | Domain CSS configured | CSS tokens: `BG_COLOR`, `FONT_COLOR` |
        | `task_image` | String | Feed has a type image | Base64-encoded task icon |
        | `store_status[]` | Array | Feed belongs to a project | Per-store status; see sub-fields below |
        | `cluster_count` | Integer | Feed belongs to a project | Task count filtered by `message_type`/`status` params |

        **`store_status[*]` fields:** `cluster_id`, `cluster_child_id`, `message_type`, `stores[]`

        **`stores[*]` fields:** `store_id`, `status`, `dept_id`, `profile_id`, `assign_user`, `last_update_time`

        ---

        ## `feed_history` — Field Reference

        | Field | Type | Description |
        |---|---|---|
        | `feed_key` | Integer | Feed identifier |
        | `action_seq` | String | Action label (e.g. "Event Viewed", "Reviewed") |
        | `user_id` | String | User who performed the action |
        | `user_name` | String | Display name |
        | `user_level` | Integer | Permission level at time of action |
        | `creation_time` | String | Formatted timestamp |
        | `result` | String | Action outcome description |
        | `action_id` | String | Action type code (e.g. `VIEW_EVENT`); may be absent |
        | `comments` | String | Comments attached; empty string if none |
        | `attachments` | String | Comma-separated attachment IDs; empty string if none |
        | `comment_flag` | String | `"1"` if comments attached, `"0"` otherwise |
        | `form_flag` | String | `"1"` if form data attached |
        | `attach_flag` | String | `"1"` if attachments present |

        ---

        ## `feed_actions` — Field Reference

        | Field | Type | Description |
        |---|---|---|
        | `panel_id` | String | Panel identifier |
        | `seq_no` | Integer | Display order |
        | `display_text` | String | URL-encoded action label |
        | `take_action` | String | `Y`=triggers a status update, `N`=other type |
        | `button_id` | String | Button identifier |
        | `panel_category` | String | Category code |
        | `service_data` | String | JSON-encoded metadata (`buttonName`, `buttonId` pairs) |
        | `default_flag` | String | `"1"`=default action, `"0"` otherwise |
        | `display_image` | String | Relative path to action icon |

        ---

        ## Error Scenarios

        | Scenario | HTTP | Error Code | Message |
        |---|---|---|---|
        | Missing / invalid `X-reflexis-csrf-token-X` | 401 | `E202` | `User session is invalid` |
        | `feed_key` ≤ 0 or missing | 400 | `E105` | `Please provide valid feedKey.` |
        | All requested projections empty | 200 | `E404` | `No data found` |
        | Unknown projection name | 200 | — | Section silently omitted |
        | Individual projection fetch fails | 200 | — | Section omitted; others continue |
        | Unexpected server error | 500 | `E302` | `Internal server error` |

        ## Error Codes Reference

        | Code | Description |
        |---|---|
        | `E105` | Invalid or missing `feed_key` |
        | `E202` | User session is invalid |
        | `E302` | Internal server error |
        | `E404` | No data found |
      parameters:
        - $ref: '#/components/parameters/FeedKeyUnderscore'
        - name: projection
          in: query
          schema:
            type: string
          description: |
            Comma-separated sections to include. Valid: `basic`, `contents`, `history`,
            `key_attributes`, `notes`, `actions`, `survey`, `comments`.
            Omit or leave empty for `basic` only.
        - name: view_type
          in: query
          schema:
            type: string
            default: MV
            enum: [MV, TV]
          description: "View type affecting feed ownership/action eligibility in basic: MV=My View, TV=Task View"
        - name: message_type
          in: query
          schema:
            type: string
            default: PROJECTEXTRACT
          description: Message type filter for cluster task count inside basic (no effect for standalone feeds)
        - name: status
          in: query
          schema:
            type: string
          description: Optional status filter for cluster task count inside basic
        - name: btn_status
          in: query
          schema:
            type: string
            default: C
            enum: [C, F]
          description: "Survey action type for survey projection: C=completion survey (default), F=force-complete survey"
      responses:
        '200':
          description: 'Success — `{status: OK, feed_details: {feed_basic?, feed_contents?, feed_history?, ...}}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
              example:
                status: OK
                feed_details:
                  feed_basic:
                    feed_key: 45739193
                    feed_title: Weekly Store Check
                    status: O
                    priority: 1
        '400':
          description: E105 — invalid or missing feed_key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/feeds/{feed_key}/survey:
    get:
      tags: [MyWorkFeeds]
      summary: Retrieve simple-type survey questions for a feed
      operationId: getFeedSurvey
      description: |
        Retrieves simple-type survey questions attached to a feed for the given button status.
        **Simple surveys only** — COMPLEX and FORM types return E338. 

        ---

        ## Feed Identification Modes

        | Mode | Condition | Required Parameters |
        |---|---|---|
        | **Mode A** | `feed_key > 0` | Positive `feed_key` in path; others optional context overrides |
        | **Mode B** | `feed_key ≤ 0` (use `-1`) | Both `requested_unit_id` **and** `cluster_id` required (→ E129 if either missing) |

        ---

        ## Path Parameters

        | Parameter | Type | Required | Constraints | Description |
        |---|---|---|---|---|
        | `feed_key` | Integer | Yes | Any integer | Use a positive value for Mode A; pass `-1` for Mode B. |

        ---

        ## Language Resolution Priority

        1. `requested_lang_code` (if provided in request)
        2. Locale from `requested_user_id` kernel user-details lookup (if `requested_lang_code` absent and `requested_user_id` present)
        3. Session `langCode` as fallback (always available)

        > Language lookup failure (bad `requested_user_id`) is **non-fatal** — logs a warning and falls back to session langCode.
        > Error messages to the client always use **session** `langCode`, regardless of the resolved service language.

        ---

        ## Response Fields — `form_array[*]`

        | Field | Type | Description |
        |---|---|---|
        | `question_id` | Integer | Unique question identifier |
        | `question_text` | String | Question displayed to the user |
        | `question_type` | String | Input type: `RADIO`, `CHECKBOX`, `TEXT`, `NUMBER`, `DATE`, `DROPDOWN` |
        | `mandatory` | Boolean | `true` if the question must be answered before status change |
        | `options[]` | Array | For choice-type questions only (`RADIO`, `CHECKBOX`, `DROPDOWN`). Each: `option_id` (Integer), `option_text` (String) |

        ---

        ## Error Scenarios

        | Scenario | HTTP | Error Code | Message |
        |---|---|---|---|
        | Missing / invalid `X-reflexis-csrf-token-X` | 401 | `E202` | `User session is invalid` |
        | `btn_status` is blank or absent | 400 | `E127` | `btn_status is mandatory` |
        | `feed_key ≤ 0` and `requested_unit_id` or `cluster_id` missing | 400 | `E129` | `Either feed_key (> 0) or both unit_id and cluster_id must be provided.` |
        | Service returned null (feed not found / internal error) | 200 | `E404` | `No data found` |
        | Service returned empty array (no simple survey / complex/form type) | 200 | `E338` | `No survey data available. Either survey is Complex type, Form type, or no survey is attached.` |
        | Unexpected server-side error | 500 | `E302` | `Internal server error` |

        ## Error Codes Reference

        | Code | Description |
        |---|---|
        | `E127` | `btn_status` is mandatory |
        | `E129` | Feed identifier mode conflict (Mode B missing required params) |
        | `E202` | User session is invalid |
        | `E302` | Internal server error |
        | `E338` | No simple survey available (complex/form type or none attached) |
        | `E404` | No data found |
      parameters:
        - $ref: '#/components/parameters/FeedKeyUnderscore'
        - name: btn_status
          in: query
          required: true
          schema:
            type: string
            enum: [C, F]
          description: "Action trigger type: C=Completion survey, F=Force-Close survey (mandatory — E127 if missing)"
        - name: cluster_id
          in: query
          schema:
            type: string
          description: "Cluster identifier. **Required when feed_key ≤ 0** (Mode B)"
        - name: cluster_child_id
          in: query
          schema:
            type: string
          description: Cluster child identifier (Mode B optional context)
        - name: requested_unit_id
          in: query
          schema:
            type: string
          description: "Unit ID of the target user. **Required when feed_key ≤ 0** (Mode B)"
        - name: requested_lang_code
          in: query
          schema:
            type: string
          description: Language code for service response — overrides session language when present
        - name: requested_user_id
          in: query
          schema:
            type: string
          description: User ID of the data owner — used for locale resolution and service context
        - name: requested_profile_id
          in: query
          schema:
            type: string
          description: Profile ID of the target user
        - name: requested_dept_id
          in: query
          schema:
            type: string
          description: Department ID of the target user
      responses:
        '200':
          description: |
            Success — `{status: OK, form_array[]}`.
            No data → E404. No simple survey (complex/form type or none) → E338.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
              example:
                status: OK
                form_array:
                  - question_id: 1
                    question_text: Was the task completed satisfactorily?
                    question_type: RADIO
                    mandatory: true
                    options:
                      - option_id: 1
                        option_text: "Yes"
                      - option_id: 2
                        option_text: "No"
        '400':
          description: |
            - E127 — btn_status is mandatory
            - E129 — feed_key ≤ 0 and required_unit_id or cluster_id missing
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

    post:
      tags: [MyWorkFeeds]
      summary: Submit survey answers and change feed status
      operationId: submitFeedSurvey
      description: |
        Submits survey answers and atomically changes the feed status to `feed_status`.
        Survey answer fields (e.g. `q_1001`, `q_1002`) are passed transparently to the service.
        File attachments are supported via multipart.

        **Feed identification modes** same as GET survey (Mode A: positive feed_key; Mode B: feed_key=-1).

        **Response variants:**
        - Success → `{status: OK, message: "Survey submitted successfully."}`
        - Validation failure (answer-level) → HTTP 200 with `{status: ER, response: "...", error_list: {q_xxx: "..."}}`
        - Server error → HTTP 500

        **Language resolution** same as GET survey endpoint.
      parameters:
        - $ref: '#/components/parameters/FeedKeyUnderscore'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [feed_status]
              properties:
                feed_status:
                  type: string
                  enum: [C, F]
                  description: "Target feed status: C=Complete, F=Force-Close (mandatory — E128 if missing)"
                cluster_id:
                  type: string
                  description: "Cluster identifier. **Required when feed_key ≤ 0** (Mode B)"
                cluster_child_id:
                  type: string
                  description: Cluster child identifier for Mode B
                requested_unit_id:
                  type: string
                  description: "Unit ID of target user. **Required when feed_key ≤ 0** (Mode B)"
                requested_lang_code:
                  type: string
                  description: Language code override for service processing
                requested_user_id:
                  type: string
                  description: User ID of the data owner (also used as userId in service call)
                requested_profile_id:
                  type: string
                  description: Profile ID of target user
                requested_dept_id:
                  type: string
                  description: Department ID of target user
              additionalProperties:
                type: string
                description: Survey answer fields (e.g. q_1001, q_1002) forwarded verbatim to service
      responses:
        '200':
          description: |
            Success → `{status: OK, message: "Survey submitted successfully."}`.
            Validation error → `{status: ER, response: "...", error_list: {field: message}}`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '400':
          description: |
            - E128 — feed_status is mandatory
            - E129 — feed_key ≤ 0 and required_unit_id or cluster_id missing
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'


  # ---------------------------------------------------------------------------
  # Task — comments / messaging
  # ---------------------------------------------------------------------------
  /task/v1/comments/configs:
    get:
      tags: [MyWorkComments]
      summary: Available comment / message reason codes
      operationId: getCommentCodes
      description: |
        Retrieves available comment codes for the authenticated user.
        Returns `comment_codes` with `sent_to[]` (recipient targets) and `reason_code[]` arrays.
        Requires `ROS_UNIT_DOMAIN` line-of-sight authorization.
      parameters:
        - name: cluster_id
          in: query
          schema:
            type: string
            default: '-1'
          description: Filter codes by cluster; `-1` or absent = domain-wide codes
        - name: reassign
          in: query
          schema:
            type: string
            default: 'N'
            enum: ['Y', 'N']
          description: "`Y` to retrieve reassignment codes; `N` (default) for standard message codes"
      responses:
        '200':
          description: 'Success — `{status: OK, comment_codes: {sent_to[], reason_code[]}}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
              example:
                status: OK
                comment_codes:
                  sent_to:
                    - seq_no: "2036"
                      display_name: "0010 - REE_10 - 0010 (dist_mgr)"
                      value: '[{"USER_INFO":[],"UNIT":"0010","PROFILE":"DIST_MGR"}]'
                  reason_code:
                    - label: Damaged Product
                      key: "1605803554243"
                    - label: Missing Information
                      key: MI
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/comments/list:
    get:
      tags: [MyWorkComments]
      summary: Comment list (full paginated or MSG two-phase load)
      operationId: getCommentList
      description: |
        Retrieves the full paginated comment list for the authenticated user.

        **Always-injected from session (not overridable):**
        `domain_id`, `user_id`, `store_id`, `dept_id`, `profile_id`, `time_zone_long`.

        **Two paths:**
        - **`on_load_call=MSG`** — two-phase load: returns feed summaries + `count_data[]` per cluster.
          `skip_records` is absent from the response.
        - **Default (flat paginated)** — pages through comments via `skip_records`/`no_records`.
          `count_data` is absent.

        ⚠️ If `feed_status` contains `A` but `msg_status` is blank → service returns null → E404.

        Requires `ROS_UNIT_DOMAIN` line-of-sight authorization.
      parameters:
        - name: view_type
          in: query
          schema:
            type: string
          description: |
            `SV`=Store View, `MV`=My Work View, `DV`=Dept View.
            Session fallback only when key is **entirely absent** (sending `view_type=` preserves empty string).
        - name: unit_category
          in: query
          schema:
            type: string
            enum: [C, S]
          description: "`C`=Corporate, `S`=Store; defaults to session unit category if omitted"
        - name: message_type
          in: query
          schema:
            type: string
            default: PROJECTEXTRACT
          description: Feed/message type token (default PROJECTEXTRACT)
        - name: cluster_id
          in: query
          schema:
            type: string
          description: Filter by cluster; `-1` or absent = all clusters (general messages)
        - name: selected_dates
          in: query
          schema:
            type: string
          description: "Comma-separated start/end dates in yyyyMMdd (e.g. 20240115,20240120). Service uses first as fromDate and last as toDate."
        - name: on_load_call
          in: query
          schema:
            type: string
          description: "Send `MSG` for the initial two-phase load; omit or send any other value for flat paginated path"
        - name: feed_title
          in: query
          schema:
            type: string
          description: Filter by feed title text
        - name: feed_type_id
          in: query
          schema:
            type: string
          description: Filter by feed type ID
        - name: msg_text
          in: query
          schema:
            type: string
          description: Server-side text filter on comment body
        - name: msg_status
          in: query
          schema:
            type: string
          description: "CSV active-status filter — N=Unread, R=Read. **Required when feed_status contains A.**"
        - name: feed_status
          in: query
          schema:
            type: string
          description: "CSV lifecycle filter — A=Active feeds, I=Inactive/closed. **When A is present, msg_status must also be provided.**"
        - name: skip_records
          in: query
          schema:
            type: integer
            default: 0
          description: DAO pagination offset (flat paginated path only)
        - name: no_records
          in: query
          schema:
            type: integer
            default: 0
          description: "DAO page size; 0=all records (flat paginated path only)"
        - name: feed_key
          in: query
          schema:
            type: integer
          description: Feed/project key — forwarded but NOT used by getCommentList (thread scoping is cluster_id only)
        - name: cut_off_time
          in: query
          schema:
            type: integer
            format: int64
          description: Legacy cutoff timestamp — forwarded but has no effect on the query
      responses:
        '200':
          description: |
            Success — `comment_data_list[]`, `last_fetch_time`, optionally `skip_records` and `count_data[]`.

            **Response shape depends on the path:**

            **Flat paginated path (default):**
            - `comment_data_list[]` — individual comment/message objects (shape below)
            - `last_fetch_time` — epoch ms; always present
            - `skip_records` — echoes the `no_records` page-size value (NOT the offset); absent for MSG path

            **`on_load_call=MSG` path:**
            - `comment_data_list[]` — feed/project summary objects (different shape)
            - `count_data[]` — per-cluster unread summary; each: `feed_key`, `cluster_id`, `count`, `unread` (Boolean), `unread_msg_data[]`

            **`comment_data_list[*]` fields (flat path):**
            `domain_id`, `feed_key`, `cluster_id`, `msg_id`, `msg_parent_id`, `msg_main_id`,
            `store_id`, `user_id`, `profile_id`, `dept_id`, `reason_code`, `reason_text`,
            `assign_store`, `assign_profile`, `assign_dept`, `assign_user`, `comment` (HTML),
            `plain_comment`, `link`, `attachment_names`, `message_status` (N/R/C/F), `message_type`,
            `creation_time` (Long), `last_update_time` (Long), `key_description`, `internal` (Y/N),
            `display_date`, `last_update_date`, `creator_id`, `created_by`, `show_reply` (Boolean),
            `show_unread` (Boolean), `attributes` (optional Object)

            No data → E404.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
              example:
                status: OK
                comment_data_list:
                  - feed_key: 42465943
                    cluster_id: "4286147"
                    msg_id: 101
                    msg_parent_id: 0
                    msg_main_id: 100
                    store_id: UNIT_01
                    user_id: SYSADMIN
                    comment: "<p>Please review the schedule update.</p>"
                    plain_comment: Please review the schedule update.
                    message_status: N
                    creation_time: 1705312800000
                    show_reply: true
                    show_unread: true
                last_fetch_time: 1705312800000
                skip_records: 20
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          description: |
            **E302** — Internal server error.
            **E312** — Refresh interval exceeded (list/latest only).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /task/v1/comments/list/latest:
    get:
      tags: [MyWorkComments]
      summary: Latest comments since last poll (incremental refresh)
      operationId: getLatestComments
      description: |
        Retrieves only comments that have changed since the last poll (`from_time`).
        Used for incremental refresh without re-fetching the full list.
        `from_time` is validated against the maximum refresh interval — exceeded → E312.
        Requires `ROS_UNIT_DOMAIN` line-of-sight authorization.
      parameters:
        - name: today_from
          in: query
          schema:
            type: integer
            format: int64
            default: 0
          description: Epoch ms — today start anchor timestamp (maps to `changeTime`)
        - name: from_time
          in: query
          schema:
            type: integer
            format: int64
            default: 0
          description: Epoch ms — timestamp of last successful poll (maps to `fromTime`)
        - name: selected_dates
          in: query
          schema:
            type: string
          description: Comma-separated dates in yyyyMMdd to scope the query
        - name: msg_type
          in: query
          schema:
            type: string
          description: Feed/message type token (default PROJECTEXTRACT)
        - name: view_type
          in: query
          schema:
            type: string
          description: "`SV`, `MV`, `DV`; defaults to session current view if omitted"
        - name: unit_category
          in: query
          schema:
            type: string
          description: Filter by unit category
        - name: project_criteria
          in: query
          schema:
            type: string
          description: Filter by project criteria
      responses:
        '200':
          description: |
            Success — `{comment_data_list[], proj_data_list[], count_data[], last_fetch_time}`.
            No data → E404. Refresh interval exceeded → E312 (500).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/comments/list/unread:
    get:
      tags: [MyWorkComments]
      summary: Retrieve unread messages for the authenticated user
      operationId: getUnreadMessages
      description: |
        Returns the full list of unread messages assigned to the authenticated user.
        Identity fields are always from session. `message_type` is hardcoded to PROJECTEXTRACT
        by the service internally (not client-configurable for this endpoint).
        Requires `ROS_UNIT_DOMAIN` line-of-sight authorization.
      parameters:
        - name: view_type
          in: query
          schema:
            type: string
          description: "SV, MV, or DV — forwarded as-is; omit to use session current view"
        - name: from_date
          in: query
          schema:
            type: string
          description: "Start of date range in yyyyMMdd (e.g. 20240115)"
        - name: to_date
          in: query
          schema:
            type: string
          description: "End of date range in yyyyMMdd (e.g. 20240120)"
      responses:
        '200':
          description: |
            Success — `{comment_list[], project_list[], count}`.
            count=0 is a valid response. Service null → E404.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
              example:
                status: OK
                comment_list: []
                project_list: []
                count: 0
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/comments/list/unread/count:
    get:
      tags: [MyWorkComments]
      summary: Unread message IDs and last-fetch timestamp
      operationId: getUnreadMessageCount
      description: |
        Returns IDs of currently unread messages and the server-side fetch timestamp.
        Lightweight polling endpoint suitable for badge-count refresh.
        `unread_msg_ids` is absent when there are no unread messages.
        Requires `ROS_UNIT_DOMAIN` line-of-sight authorization.
      parameters:
        - name: view_type
          in: query
          schema:
            type: string
          description: "SV, MV, or DV; defaults to session current view if omitted"
        - name: unit_category
          in: query
          schema:
            type: string
          description: Unit category filter; defaults to session unit category if omitted
        - name: message_type
          in: query
          schema:
            type: string
            default: PROJECTEXTRACT
          description: Feed/message type token (default PROJECTEXTRACT)
        - name: selected_dates
          in: query
          schema:
            type: string
          description: Comma-separated dates in yyyyMMdd; absent = system default date range
      responses:
        '200':
          description: |
            Success — `{status: OK, last_fetch_time, unread_msg_ids?[]}`.
            `last_fetch_time` is always present; `unread_msg_ids` present only when unread messages exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
              example:
                status: OK
                unread_msg_ids: [401, 402]
                last_fetch_time: 1705276800000
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/comments/add:
    post:
      tags: [MyWorkComments]
      summary: Add a new comment (with optional file attachments)
      operationId: addComment
      description: |
        Adds a new comment to a feed/cluster. Attachment file extensions are validated against
        the domain-configured `ATTACHMENT_TYPES` before the service is called.

        **Always-injected from session (not overridable):**
        `domain_id`, `user_id`, `store_id`, `dept_id`, `profile_id`, `time_zone_long`.

        Both snake_case and camelCase param names are accepted (e.g. `feed_key` or `feedKey`).

        **Auth header note:** Use `X-reflexis-csrf-token-X` (NOT the legacy `x-authtoken`).
        Requires `ROS_UNIT_DOMAIN` line-of-sight authorization.
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [comment, plain_text]
              properties:
                comment:
                  type: string
                  description: "HTML-formatted comment body (URL-encoded, e.g. %3Cp%3EText%3C%2Fp%3E) — mandatory"
                plain_text:
                  type: string
                  description: "Plain-text version of the comment — mandatory (used for ETL/notifications)"
                cluster_id:
                  type: string
                  default: '-1'
                  description: "Feed cluster ID; -1=general message; required when commenting on a project thread"
                feed_key:
                  type: integer
                  default: 0
                  description: "Feed/project key; 0 or absent = no specific feed"
                message_type:
                  type: string
                  default: M
                  enum: [M, R, F, RA]
                  description: "M=main, R=reply, F=reassign, RA=reply-all"
                message_status:
                  type: string
                  default: N
                  enum: [N, R]
                  description: "Initial read status: N=not-read, R=read"
                reason_code:
                  type: string
                  description: Reason code key from /task/v1/comments/configs
                reason_text:
                  type: string
                  description: Display label for the reason code
                assign_store:
                  type: string
                  default: '-1'
                  description: "Target unit/store ID to assign the comment to"
                assign_profile:
                  type: string
                  default: '-1'
                  description: Target profile ID to assign to
                assign_dept:
                  type: string
                  default: '-1'
                  description: Target department ID to assign to
                assign_user:
                  type: string
                  default: '-1'
                  description: Target user ID to assign to
                assign_text:
                  type: string
                  description: Display text for the assignment (e.g. user name + store)
                assign_details:
                  type: string
                  description: "JSON string of assignment detail metadata (e.g. [{\"USER_INFO\":[],...}])"
                msg_parent_id:
                  type: integer
                  default: 0
                  description: Parent message ID for reply chain positioning
                msg_main_id:
                  type: integer
                  default: 0
                  description: Root/thread message ID
                link:
                  type: string
                  description: URL to embed in the comment
                internal:
                  type: string
                  default: '-1'
                  description: "Internal-only flag: Y=internal, -1=not set"
                from_external:
                  type: string
                  description: Source indicator for externally originated comments
                login_auth_token:
                  type: string
                  default: '-1'
                  description: Login auth token override
              additionalProperties: false
      responses:
        '200':
          description: |
            Success — `{status: OK, comment_data[]}` for normal add/reply.
            For `message_type=RA` (reply-all) → `{status: OK, message: "Message added successfully"}`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '400':
          description: "E125 — invalid attachment type"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/comments/reply:
    post:
      tags: [MyWorkComments]
      summary: Reply to an existing comment thread
      operationId: replyComment
      description: |
        Replies to an existing comment thread. `message_type` **must** be `R` (case-insensitive);
        any other value → E126 before reaching the service.
        Response shape is identical to `/add`.
        Requires `ROS_UNIT_DOMAIN` line-of-sight authorization.
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [message_type, msg_main_id, comment, plain_text]
              properties:
                message_type:
                  type: string
                  enum: [R]
                  description: "Must be R (case-insensitive) — mandatory (E126 if missing or different value)"
                msg_main_id:
                  type: integer
                  description: "Root/thread message ID being replied to — mandatory"
                comment:
                  type: string
                  description: "HTML-formatted reply body (URL-encoded) — mandatory"
                plain_text:
                  type: string
                  description: "Plain-text version of the reply — mandatory"
                cluster_id:
                  type: string
                  default: '-1'
                  description: Cluster context of the thread
                feed_key:
                  type: integer
                  default: 0
                  description: Feed/project key
                msg_parent_id:
                  type: integer
                  default: 0
                  description: Immediate parent message ID within the thread
                reason_code:
                  type: string
                  description: Reason code key
                reason_text:
                  type: string
                  description: Reason code display label
                assign_store:
                  type: string
                  default: '-1'
                  description: Target store to assign the reply to
                assign_profile:
                  type: string
                  default: '-1'
                  description: Target profile to assign to
                assign_dept:
                  type: string
                  default: '-1'
                  description: Target department to assign to
                assign_user:
                  type: string
                  default: '-1'
                  description: Target user to assign to
                assign_text:
                  type: string
                  description: Display text for the assignment
                assign_details:
                  type: string
                  description: JSON assignment detail metadata
                link:
                  type: string
                  description: URL to embed in the reply
                internal:
                  type: string
                  default: '-1'
                  description: "Internal-only flag: Y=internal, -1=not set"
              additionalProperties: false
      responses:
        '200':
          description: 'Success — `{status: OK, comment_data[]}` (same shape as /add)'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '400':
          description: "E126 — invalid message_type (must be R) / E125 — invalid attachment type"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/comments/close:
    put:
      tags: [MyWorkComments]
      summary: Close a comment thread
      operationId: closeComment
      description: |
        Closes (or changes the status of) a comment thread via a two-phase service call.
        Phase 1 collects ETL messages and dispatches socket notifications.
        Phase 2 commits the DB update. Both phases are mandatory.

        Session-derived defaults (client can override via snake_case):
        `time_zone` defaults to session short TZ; `local_code` defaults to session langCode.
        Requires `MSG_ACCESS` line-of-sight authorization.
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required: [msg_id]
              properties:
                msg_id:
                  type: string
                  description: "ID of the message/thread to close — mandatory integer (E120 if missing or non-numeric)"
                cluster_id:
                  type: string
                  default: '-1'
                  description: Cluster context of the thread
                feed_key:
                  type: string
                  default: '-1'
                  description: Feed key associated with the comment
                status:
                  type: string
                  description: "New comment status code (default: CLOSE_COMMENT constant)"
                local_code:
                  type: string
                  description: "Locale/language code for ETL datetime formatting (defaults to session langCode)"
                msg_date_time:
                  type: string
                  description: URL-encoded message datetime override
                time_zone:
                  type: string
                  description: "Timezone string for datetime resolution — short (UTC) or long (America/Los_Angeles) accepted (defaults to session short TZ)"
      responses:
        '200':
          description: 'Success — `{status: OK, message: "Comment closed successfully."}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '400':
          description: "E120 — msg_id is mandatory / must be a valid integer"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/comments/unread/update:
    put:
      tags: [MyWorkComments]
      summary: Mark all unread messages in a thread as read
      operationId: updateAllUnreadMessages
      description: |
        Marks all unread messages (`message_status=N`) in a thread as read for the authenticated
        user's store. Updates only messages with `assign_store=session.unitId`.

        Response variants:
        - Unread messages found and updated → `{status: OK, unread_update: {msg_ids[], cluster_id, msg_main_id}}`
        - No unread messages → `{status: OK, message: "Unread messages updated successfully."}`

        Requires `MSG_ACCESS` line-of-sight authorization.
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required: [msg_main_id]
              properties:
                msg_main_id:
                  type: string
                  description: "Root/thread message ID — mandatory integer (E121 if missing or non-numeric)"
      responses:
        '200':
          description: |
            Success with updated messages → `{status: OK, unread_update: {...}}`.
            No unread messages → `{status: OK, message: "..."}`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '400':
          description: "E121 — msg_main_id is mandatory / must be a valid integer"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/comments/transfer:
    put:
      tags: [MyWorkComments]
      summary: Transfer comment ownership between users
      operationId: transferOwnerComments
      description: |
        Transfers all comment records for a cluster from one user to another.
        Updates both `assignUser` and `userId` fields in all matching records.
        Requires `ROS_UNIT_DOMAIN` line-of-sight authorization.
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required: [cluster_id, new_owner_id, old_owner_id]
              properties:
                cluster_id:
                  type: string
                  description: "Project cluster ID whose comments are being transferred — mandatory (E108)"
                new_owner_id:
                  type: string
                  description: "User ID of the new comment owner — mandatory (E123)"
                old_owner_id:
                  type: string
                  description: "User ID of the current/old comment owner — mandatory (E124)"
      responses:
        '200':
          description: 'Success — `{status: OK, message: "Comments transferred successfully."}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '400':
          description: "E108 cluster_id mandatory / E123 new_owner_id mandatory / E124 old_owner_id mandatory"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/comments/unread/count:
    put:
      tags: [MyWorkComments]
      summary: Update read/unread status for a single message
      operationId: updateMessageStatus
      description: |
        Updates the read/unread status of a single message.
        When `msg_parent_id=0` (top-level), cascades the update to all child messages.

        Session-derived defaults (client can override):
        `time_zone` → session short TZ; `local_code` → session langCode;
        `logged_unit_id` → session unitId.

        `userId` is always from session (prevents identity spoofing).
        Blank `msg_status` → defaults to `R` (read) inside the service.
        Requires `MSG_ACCESS` line-of-sight authorization.
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required: [msg_id]
              properties:
                msg_id:
                  type: string
                  description: "ID of the message to update — mandatory integer (E120 if missing or non-numeric)"
                msg_parent_id:
                  type: string
                  description: "Parent message ID; 0 = cascade to all children in thread (default 0)"
                msg_status:
                  type: string
                  enum: [N, R]
                  description: "New status: N=unread, R=read. Blank defaults to R (read) in service."
                local_code:
                  type: string
                  description: Locale/language code for ETL datetime formatting (defaults to session langCode)
                time_zone:
                  type: string
                  description: Timezone string for datetime resolution (defaults to session short TZ)
                logged_unit_id:
                  type: string
                  description: "Store/unit ID for assignStore WHERE clause (defaults to session unitId)"
      responses:
        '200':
          description: 'Success — `{status: OK, message: "Status updated successfully."}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '400':
          description: "E120 — msg_id is mandatory / must be a valid integer"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  # ---------------------------------------------------------------------------
  # Task execution — feed actions (base path task/v1/actions)
  # ---------------------------------------------------------------------------
  /task/v1/actions/{feed-key}/list:
    get:
      tags: [MyWorkFeedActions]
      summary: Feed action list — panels and button metadata
      operationId: getFeedActionList
      description: |
        Returns feed action metadata (`action_list[]`) for the feed — panels, buttons, and display config.
        Service: `FeedService#getFeedActionList`.

        ## Path Parameters

        | Parameter | Type | Required | Description |
        |---|---|---|---|
        | `feed-key` | Integer | Yes | Feed identifier |

        ## Response Fields — `action_list[*]`

        | Field | Type | Description |
        |---|---|---|
        | `panel_id` | String | Panel identifier (e.g. `PANEL-50519`) |
        | `seq_no` | Integer | Display order |
        | `box_id` | String | Box identifier (e.g. `1-PROJECTEXTRACT`) |
        | `take_action` | String | `Y`=triggers a status update, `N`=other type |
        | `display_text` | String | URL-encoded action label |
        | `mobile_handler` | String | Mobile handler identifier |
        | `domain_id` | Integer | Domain identifier |
        | `panel_type` | String | Panel type code |
        | `button_id` | String | Button identifier |
        | `panel_category` | String | Category code (`S`, etc.) |
        | `service_data` | String | JSON-encoded metadata (`buttonName`, `buttonId` pairs) |
        | `default_flag` | String | `"1"`=default action, `"0"` otherwise |
        | `display_image` | String | Relative path to action icon |

        ## Error Scenarios

        | Scenario | HTTP | Error Code | Message |
        |---|---|---|---|
        | Missing / invalid `X-reflexis-csrf-token-X` | 401 | `E202` | `User session is invalid` |
        | Uncaught server failure | 500 | `E500` | `Unexpected server error.` |
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
      responses:
        '200':
          description: 'Success — `{status: OK, action_list[]}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/status-buttons:
    get:
      tags: [MyWorkFeedActions]
      summary: Status buttons for RTM
      operationId: statusButtons
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
        - name: show_force_close
          in: query
          schema:
            type: string
          description: Whether to include force-close button (e.g. Y or N)
        - name: status
          in: query
          schema:
            type: string
          description: Current feed status for button rendering context
      responses:
        '200':
          description: 'Success — `{status: OK, status_buttons[]}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/updated-feed:
    get:
      tags: [MyWorkFeedActions]
      summary: Updated single feed payload after an action
      operationId: getUpdatedFeed
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
        - name: view_type
          in: query
          schema:
            type: string
          description: View mode for feed refresh (e.g. MV)
        - name: feed_status
          in: query
          schema:
            type: string
          description: Feed status filter
        - name: feed_user_id
          in: query
          schema:
            type: string
          description: User scope for the feed snapshot
        - name: feed_profile_id
          in: query
          schema:
            type: string
          description: Profile scope
        - name: feed_dept_id
          in: query
          schema:
            type: string
          description: Department scope
      responses:
        '200':
          description: 'Success — `{status: OK, feed_details[]}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/reassign:
    post:
      tags: [MyWorkFeedActions]
      summary: Cluster reassignment (legacy handleFeedUpdate)
      operationId: reassignFeedCluster
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required: [cluster_id]
              properties:
                cluster_id:
                  type: string
                  description: Cluster identifier (mandatory in controller validation)
                cluster_child_id:
                  type: string
                  description: Child cluster identifier
                where_feed_status:
                  type: string
                  description: Current status filter for update
                feed_status:
                  type: string
                  description: Target status
                panel_id:
                  type: string
                  description: Panel identifier
                reset_status_flag:
                  type: string
                  description: Reset status flag
      responses:
        '200':
          description: 'Success — `{status: OK, response: "Reassignment done successfully"}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/status:
    post:
      tags: [MyWorkFeedActions]
      summary: Change feed/task status (multipart; file uploads supported)
      operationId: changeFeedStatus
      description: |
        Changes feed status. Supports file attachments via multipart upload.
        File keys use the uploaded original filename in the internal map.
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                feed_status:
                  type: string
                  description: New or target status
                from_shortcut:
                  type: string
                  description: Shortcut origin flag (e.g. N)
                panel_id:
                  type: string
                  description: Panel identifier
              additionalProperties: true
      responses:
        '200':
          description: 'Success — `{status: OK, response: "Status updated successfully"}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/suggested-date:
    post:
      tags: [MyWorkFeedActions]
      summary: Update suggested start/end dates for a feed
      operationId: updateSuggestedDate
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                sugg_start_date_val:
                  type: string
                  description: Suggested start date value (e.g. 20260301)
                sugg_end_date_val:
                  type: string
                  description: Suggested end date value (e.g. 20260331)
      responses:
        '200':
          description: 'Success — `{status: OK, response: "Suggested Start/End Date updated successfully"}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/watch-flag:
    post:
      tags: [MyWorkFeedActions]
      summary: Update watch flag and watch context
      operationId: updateWatchFlag
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required: [watch_flag]
              properties:
                watch_flag:
                  type: string
                  description: Watch flag value (mandatory)
                watch_user_id:
                  type: string
                  description: User to associate with watch
                watch_unit_id:
                  type: string
                  description: Unit for watch context
      responses:
        '200':
          description: 'Success — `{status: OK, response: {panel_id, action_type, message, action_data, status}}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/attributes:
    post:
      tags: [MyWorkFeedActions]
      summary: Update extra project/task attributes
      operationId: updateExtraAttributes
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                project_id:
                  type: string
                  description: Project identifier
                task_id:
                  type: string
                  description: Task identifier
                parent_task_id:
                  type: string
                  description: Parent task identifier (mapped for legacy service)
      responses:
        '200':
          description: 'Success — `{status: OK, response: "Extra Attributes updated successfully"}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/predecessors:
    post:
      tags: [MyWorkFeedActions]
      summary: Process predecessors CSV upload
      operationId: processPredecessors
      description: |
        Processes predecessor rows from an uploaded CSV file.
        CSV columns (in order): `clusterId`, `clusterChildId`, `storeId`, `predecessorStatus`.
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
                  description: CSV file with predecessor rows (required)
              additionalProperties: true
      responses:
        '200':
          description: 'Success — `{status: OK, response: "Predecessors processed Successfully"}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/reassign-feed:
    post:
      tags: [MyWorkFeedActions]
      summary: Reassign feed (v1 path)
      operationId: reassignFeedV1
      description: Reassigns the feed record via `reassignFeedRecord`.
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                assign_user_id:
                  type: string
                  description: User to assign
                requested_user_id:
                  type: string
                  description: Requested assignee user ID for handoff flow
                requested_user_name:
                  type: string
                  description: Requested assignee display name
                where_feed_status:
                  type: string
                  description: Current status filter
                feed_status:
                  type: string
                  description: Target status
                panel_id:
                  type: string
                  description: Panel identifier
                reset_status_flag:
                  type: string
                  description: Reset status flag
                cluster_id:
                  type: string
                  description: Cluster identifier
                cluster_child_id:
                  type: string
                  description: Child cluster identifier
      responses:
        '200':
          description: 'Success — `{status: OK, response: "Action initiated"}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/v2/reassign:
    post:
      tags: [MyWorkFeedActions]
      summary: Reassign feed (v2 path — adjusted assignee/dept/profile defaults)
      operationId: reassignFeedV2
      description: |
        Same as v1 reassign but when `assign_user_id` is non-blank and not `-1`,
        the server forces `assign_dept_id` and `assign_profile_id` to `-1`.
        Otherwise forces `assign_user_id` to `-1`.
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                assign_user_id:
                  type: string
                  description: User to assign (v2 path adjusts related fields)
                requested_user_id:
                  type: string
                  description: Requested assignee user ID
                requested_user_name:
                  type: string
                  description: Requested assignee display name
                where_feed_status:
                  type: string
                  description: Current status filter
                feed_status:
                  type: string
                  description: Target status
                panel_id:
                  type: string
                  description: Panel identifier
                reset_status_flag:
                  type: string
                  description: Reset status flag
                cluster_id:
                  type: string
                  description: Cluster identifier
                cluster_child_id:
                  type: string
                  description: Child cluster identifier
      responses:
        '200':
          description: 'Success — `{status: OK, response: "Action initiated"}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/monitor:
    post:
      tags: [MyWorkFeedActions]
      summary: Update monitor disposition
      operationId: updateMonitor
      description: The server injects the current feed key for the monitor service context.
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                disposition_id:
                  type: string
                  description: Monitor disposition value
                monitor_id:
                  type: string
                  description: Monitor record identifier
      responses:
        '200':
          description: 'Success — `{status: OK, response: "Record is updated successfully"}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/claim:
    post:
      tags: [MyWorkFeedActions]
      summary: Claim or unclaim a feed
      operationId: claimFeed
      description: |
        Claims or unclaims the feed for a transaction.
        `flag=C` (case-insensitive) = claim; any other value = unclaim.
        Returns an updated feed snapshot on success.
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required: [transaction_key]
              properties:
                flag:
                  type: string
                  description: "C (case-insensitive)=claim; any other value=unclaim"
                transaction_key:
                  type: string
                  description: Transaction key (long) for the claim operation (mandatory)
      responses:
        '200':
          description: 'Success — `{status: OK, feed_details[]}` (updated feed snapshot)'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/feed:
    post:
      tags: [MyWorkFeedActions]
      summary: Update feed (status, acknowledge, thread effects)
      operationId: updateFeedAction
      description: |
        Updates feed status, acknowledgment, and related thread side effects.
        On success may append feed thread rows (acknowledge/reopen/reviewed events).
        Status `R` also sets `where_feed_status` to `N` for the update path.
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                status:
                  type: string
                  description: "When set, mapped to internal feed status; R also sets where_feed_status=N"
                acknowledge_flag:
                  type: string
                  description: Drives acknowledge/reopen thread entries when present
                transaction_key:
                  type: string
                  description: Used for thread/history when acknowledging or reviewing
                panel_id:
                  type: string
                  description: Panel identifier
                reset_status_flag:
                  type: string
                  description: Reset status flag
                cluster_id:
                  type: string
                  description: Cluster identifier
                cluster_child_id:
                  type: string
                  description: Child cluster identifier
      responses:
        '200':
          description: 'Success — `{status: OK, response: "Action initiated"}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/task:
    post:
      tags: [MyWorkFeedActions]
      summary: Update task (v1 path)
      operationId: updateTaskV1
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                status:
                  type: string
                  description: Task/status code for update pipeline
                requested_user_id:
                  type: string
                  description: Delegated user ID for audit/history
                requested_user_name:
                  type: string
                  description: Delegated user display name
                cluster_id:
                  type: string
                  description: Cluster identifier
                cluster_child_id:
                  type: string
                  description: Child cluster identifier
      responses:
        '200':
          description: 'Success — `{status: OK, response: "Action initiated"}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/v2/task:
    post:
      tags: [MyWorkFeedActions]
      summary: Update task (v2 path)
      operationId: updateTaskV2
      description: Same handler as v1 task endpoint.
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                status:
                  type: string
                  description: Task/status code for update pipeline
                requested_user_id:
                  type: string
                  description: Delegated user ID for audit/history
                requested_user_name:
                  type: string
                  description: Delegated user display name
                cluster_id:
                  type: string
                  description: Cluster identifier
                cluster_child_id:
                  type: string
                  description: Child cluster identifier
      responses:
        '200':
          description: 'Success — `{status: OK, response: "Action initiated"}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/mark-favorite:
    post:
      tags: [MyWorkFeedActions]
      summary: Mark feed as favorite
      operationId: markFavorite
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                send_message:
                  type: string
                  description: Message / side-channel flag (legacy; e.g. N)
                user_unit_id:
                  type: string
                  description: User unit scope
                cluster_id:
                  type: string
                  description: Cluster identifier
      responses:
        '200':
          description: 'Success — `{status: OK, response: "Favorite marked successfully"}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/unmark-favorite:
    post:
      tags: [MyWorkFeedActions]
      summary: Unmark feed as favorite
      operationId: unmarkFavorite
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                send_message:
                  type: string
                  description: Message / side-channel flag (legacy; e.g. N)
                user_unit_id:
                  type: string
                  description: User unit scope
                cluster_id:
                  type: string
                  description: Cluster identifier
      responses:
        '200':
          description: 'Success — `{status: OK, response: "Favorite unmarked successfully"}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /task/v1/actions/{feed-key}/viewed:
    post:
      tags: [MyWorkFeedActions]
      summary: Record feed viewed / audit trail
      operationId: viewedFeed
      description: |
        Records that the current user viewed the feed. No form/query payload is accepted.
        Always returns HTTP 200 (even "Feed record not found" is an OK response).
      parameters:
        - $ref: '#/components/parameters/FeedKeyHyphen'
      responses:
        '200':
          description: |
            Success — `{status: OK, response: "Event viewed by the user"}`.
            "Error while processing" and "Feed record not found" also return status OK.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonObject'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'


