Internal Documentation internal
TalkIDE internal documentation

View and update the authenticated user’s sound preferences. Requires a valid JWT access token. Preferences are loaded as part of GET /me and saved individually via PUT /me/sound-preferences with auto-save on every change.

  • All 4 boolean toggles default to the values defined in the table below; master volume defaults to 50.
  • Each toggle and slider change triggers an immediate API call (debounced 300 ms for the slider).
  • Optimistic update: FE applies the change locally before the API response; on error it rolls back and shows a toast notification.
  • Sound files are served from public/sounds/{sound_id}.mp3 at master volume level.
  • Sound preferences are part of the preferences object returned by GET /me — see UC-01006 for the full response shape.
sequenceDiagram
    actor User

    %% --- GET preferences (via /me) ---
    User->>+FE: opens Sounds section in Settings

    FE->>+BE: GET /api/v1/users/me <br> Authorization: Bearer {accessToken}

    BE->>BE: validate JWT access token
    alt access token invalid or missing
        BE-->>FE: 401 Unauthorized <br> ErrorResponse
    end

    BE->>DB: find user by id (from token)

    BE->>-FE: 200 OK <br> UserProfileResponse (incl. preferences)

    FE->>-User: render 4 ToggleSwitches + master volume slider <br> pre-filled from preferences

    %% --- PUT sound preferences ---
    User->>+FE: toggles a switch or moves slider

    FE->>FE: optimistic update (apply change in local state immediately)
    FE->>FE: debounce 300 ms (slider only)

    FE->>+BE: PUT /api/v1/users/me/sound-preferences <br> Authorization: Bearer {accessToken} <br> UpdateSoundPreferencesRequest

    BE->>BE: validate JWT access token
    alt access token invalid or missing
        BE-->>FE: 401 Unauthorized <br> ErrorResponse
        FE-->>User: rollback optimistic update <br> show error toast
    end

    BE->>BE: validate request
    alt request is invalid
        BE-->>FE: 400 Bad Request <br> ErrorResponse
        FE-->>User: rollback optimistic update <br> show error toast
    end

    BE->>DB: update sound preferences for user

    BE->>-FE: 204 No Content

    FE->>-User: change confirmed (no additional UI feedback on success)

    %% --- Test sound button ---
    User->>+FE: clicks test sound button next to a toggle

    FE->>FE: play public/sounds/{sound_id}.mp3 <br> at current soundMasterVolume level (0-100 → gain 0.0-1.0)

    FE->>-User: audio plays in browser

UX Guidelines

Page Layout

The Sounds section appears as item 3 in the Settings sidebar (after Profile and Account). Sidebar icon: Volume2 from lucide-vue-next (or Bell — icon selection deferred to Sára).

Content area follows the same padding: 32px 32px 64px layout as other sections.

Sound Toggles

Four rows using the existing ToggleSwitch.vue component (ProfileScreen/components/ToggleSwitch.vue). Each row uses FieldRow.vue layout:

IDLabel (en)Label (cs)Default
sound_new_messageNew messageNová zprávaon
sound_send_messageSent messageOdeslaná zprávaoff
sound_task_completedTask completedDokončený úkolon
sound_task_errorTask failedSelhání úkoluon

Each row layout: label (13px, 500) + ToggleSwitch on the right + a small “Test” button (ghost, 12px, lucide Play icon) inline after the toggle. Clicking “Test” plays public/sounds/{sound_id}.mp3 at the current master volume level — no API call, purely client-side AudioContext or HTMLAudioElement.

border-bottom: 1px solid var(--line-1), padding: 20px 0

Master Volume Slider

Below the 4 toggle rows, a fifth FieldRow renders the master volume control:

  • Label: “Master volume” (en) / “Hlavní hlasitost” (cs)
  • HTML <input type="range" min="0" max="100" step="5">
  • Current value displayed as a numeric suffix: e.g. "50 %"
  • Debounce: 300 ms before firing PUT /me/sound-preferences
  • Changing the slider also affects the volume of any subsequent “Test” button clicks

Auto-save Behaviour

  • Toggle change → immediate API call (no debounce)
  • Slider change → debounced 300 ms
  • Optimistic update on FE before response arrives
  • On API error: roll back to previous value in local state + display toast "Could not save. Please try again." (var(--rose) background)
  • No explicit “Save” button — the section has no footer

Get Sound Preferences

Sound preferences are loaded via GET /api/v1/users/me — no separate endpoint. See UC-01006 — Get Profile for the full response shape.

Relevant fragment of 200 OK UserProfileResponse:

{
  "data": {
    "preferences": {
      "locale": "en",
      "soundNewMessage": true,
      "soundSendMessage": false,
      "soundTaskCompleted": true,
      "soundTaskError": true,
      "soundMasterVolume": 50
    }
  }
}

401 Unauthorized (missing or invalid access token) ErrorResponse:

{
  "status": 401,
  "code": "AUTHENTICATION_FAILED",
  "message": "Access token is missing or invalid"
}

Update Sound Preferences

PUT /api/v1/users/me/sound-preferences UpdateSoundPreferencesRequest:

{
  "soundNewMessage": true,
  "soundSendMessage": false,
  "soundTaskCompleted": true,
  "soundTaskError": true,
  "soundMasterVolume": 50
}

204 No Content (success, no body)

400 Bad Request (validation) ErrorResponse:

{
  "status": 400,
  "code": "VALIDATION_ERROR",
  "message": "Validation failed",
  "errors": [
    { "field": "soundMasterVolume", "message": "must be between 0 and 100" }
  ]
}

401 Unauthorized (missing or invalid access token) ErrorResponse:

{
  "status": 401,
  "code": "AUTHENTICATION_FAILED",
  "message": "Access token is missing or invalid"
}

Frontend

Validations

FieldConstraintsSizePatternNote
soundNewMessagenot_nullboolean; validated before sending API request
soundSendMessagenot_nullboolean; validated before sending API request
soundTaskCompletednot_nullboolean; validated before sending API request
soundTaskErrornot_nullboolean; validated before sending API request
soundMasterVolumenot_null0-100integer, step 5; slider enforces range client-side

Backend

Validations

FieldConstraintsSizePatternNote
soundNewMessagenot_nullboolean
soundSendMessagenot_nullboolean
soundTaskCompletednot_nullboolean
soundTaskErrornot_nullboolean
soundMasterVolumenot_null, min=0, max=100integer inclusive

Test Cases

GIVENWHENTHEN
authenticated userGET /me is called200 OK, preferences object contains all 5 sound fields
no Authorization headerGET /me is called401 AUTHENTICATION_FAILED error response is returned
authenticated user, all fields validPUT /me/sound-preferences is called204 No Content, preferences updated in DB
authenticated user, soundMasterVolume = 0PUT /me/sound-preferences is called204 No Content (boundary — valid)
authenticated user, soundMasterVolume = 100PUT /me/sound-preferences is called204 No Content (boundary — valid)
soundMasterVolume = -1PUT /me/sound-preferences is called400 VALIDATION_ERROR error response is returned
soundMasterVolume = 101PUT /me/sound-preferences is called400 VALIDATION_ERROR error response is returned
soundNewMessage field missing from request bodyPUT /me/sound-preferences is called400 VALIDATION_ERROR error response is returned
empty request bodyPUT /me/sound-preferences is called400 VALIDATION_ERROR error response is returned
no Authorization headerPUT /me/sound-preferences is called401 AUTHENTICATION_FAILED error response is returned
authenticated user saves preferences, then refreshes pageGET /me is called after savepreferences object reflects previously saved values

Was this page helpful?

Thanks for the feedback.