Breadcrumbs

Release Notes - Product Delivery - 26.18 - Apr 29 13:42

How to use this page:

Find your selected Jira issues in the table below. Select the expand to use them as your source of truth to write release notes.

Release

https://fuseuniversal.atlassian.net/projects/PD/versions/20854

Date

Version

26.18

Description

4.2 Launch

Contributors

@User@User@User@User@User@User@User@User

Issues in this release

Before you share the page, review the contents of each Jira issue and remove any sensitive data.

Issue

Summary

Description

Acceptance Criteria

Epic Link

Epic Name

Assigned Team

PD-12945

Fix CoordinatorJob infinite loop caused by non-advancing StackOne pagination cursor

Summary

Fix two bugs in FuseliteStackOne::CoordinatorJob that cause an infinite loop. This happens when StackOne returns a non-advancing pagination cursor, flooding the Sidekiq queue with thousands of duplicate PageJobs.

Context

The external_courses sync job has been failing since April 9. This was due to the cursor column being too small (varchar(255)) for StackOne's base64-encoded cursors. The job fails with Mysql2::Error: Data too long for column 'cursor' and ends up in the Sidekiq dead set. As a result, courses added to Go1 after the last successful sync were not picked up. After widening the column to varchar(1024) (PD-12840) and re-running the sync, it successfully picked up 325 active courses.

The infinite loop occurs because StackOne cursors are base64-encoded JSON blobs. The ts (timestamp) field changes on every response, making simple string equality ineffective for detecting a non-advancing cursor. The actual page position is in the pc field. If StackOne's Go1 connector fails to paginate correctly, it returns p: -1 and the same pc value, leading to an indefinite loop of enqueuing duplicate PageJobs.

Acceptance criteria

  • CoordinatorJob#discover_and_enqueue! detects a non-advancing cursor by comparing the decoded pc field inside the base64 cursor JSON.

  • The coordinator raises a clear error message when a non-advancing cursor is detected, instead of looping.

  • sidekiq_retries_exhausted clears the cursor to nil (with pages_total: 0, pages_done: 0).

  • Graceful shutdown resumability is preserved; a Sidekiq-interrupted coordinator resumes from the last stored cursor.

  • Falls back to string equality if cursor decoding fails.

  • All existing specs pass.


PD-12639



PD-12908

Update DB with missing data for GoodStart

Summary

A rake task is needed to enqueue jobs. These jobs will generate the missing available_at records for GoodStart LP.

Context

GoodStart LP has an ID of 6418. There are missing available_at records that need to be addressed.

Acceptance criteria

  • Create a rake task.

  • The rake task should enqueue jobs.

  • Jobs must generate the missing available_at records for GoodStart LP (ID 6418).

Other information

N/A





PD-12887

FE: Change to Icon and Title for main overview page

In order to support translation and make a smoother and clearer user journey, the ‘Main overview page’ button needs to be changed, along with the icon used.


Story…

As a user…

  • I click on the overview overlay, I can see the button, ‘Learning plan overview’.

  • I can see the icon next to the ‘Learning plan overview’.


Design note: For the icon, use the Learning Plans icon as found in the left side bar for Learning Plans on Pink Fuse.

Given I am on a page with the overview overlay
When I open the overview overlay
Then I see the button labeled, ‘Learning plan overview’

Given I am on a page with the overview overlay
When I open the overview overlay
Then I see the icon next to the, ‘Learning plan overview’ button

PD-11108



PD-12882

As a user I want to be able to answer a question with an image

Story

As a user…

  • When I am answering a question with an image, I can clearly see the question.

  • I can clearly see the image.

  • I can clearly see the possible answers, and I am able to interact with them.

AC 1: Question text is clearly visible

  • Given I am a user taking a quiz/assessment that contains a question with an image

  • When the question is displayed on screen

  • Then the question text is clearly visible and legible above or alongside the image

AC 2: Image is clearly displayed

  • Given I am viewing a question that includes an image

  • When the question loads

  • Then the image is fully rendered, clearly visible, and appropriately sized for the screen/device

  • And the image does not obstruct the question text or the answer options

AC 3: Answer options are clearly visible

  • Given I am viewing a question with an image

  • When the question and image have loaded

  • Then all possible answer options are clearly displayed and legible below or alongside the image

  • And each answer option is visually distinct from the others

AC 4: User can select an answer

  • Given I can see the question, the image, and the answer options

  • When I tap or click on an answer option

  • Then the selected answer is visually highlighted to confirm my selection

  • And I am able to change my selection before submitting

AC 5: User can submit their answer

  • Given I have selected an answer to the image-based question

  • When I confirm/submit my answer

  • Then my response is recorded and I am progressed to the next question or shown the result

PD-12199



PD-12870

Bump stackone_client gem and replace Faraday bypass for list_assignments with SDK

Summary

The task is to update the stackone_client gem and replace the Faraday bypass for list_assignments and list_user_assignments with proper SDK calls. This is due to a recent fix in the StackOne Ruby SDK that addresses a type crash issue.

Context

The list_assignments method was using a raw Faraday bypass because the API returned "source_value": 0 (Integer), which conflicted with the SDK's Sorbet type. This led to a TypeError in Crystalline. The existing workaround can be found in LmsGateway#list_assignments.

Acceptance criteria

  • Bump stackone_client to the version with the fix for source_value: 0.

  • Replace the raw Faraday bypass in LmsGateway#list_assignments and LmsGateway#list_user_assignments with SDK calls:

    • Use @client.lms.list_assignments

    • Use @client.lms.list_user_assignments

  • Remove the RawResponse struct and lms_faraday helper from LmsGateway if they are no longer needed.

  • Update ResponseParser if the SDK response shape for assignments differs from the raw Faraday shape.

  • Verify and document the intentional omission of updated_after for assignments at the SDK call level.

Other information

Related: PD-12639


PD-12639



PD-12840

Widen cursor column to varchar(1024) in content_provider_sync_cursors

Summary

The issue involves the cursor column in the content_provider_sync_cursors table. It is currently defined as varchar(255), which leads to a Mysql2::Error: Data too long for column 'cursor' error in production. This occurs when StackOne returns pagination cursors longer than 255 characters.

Context

The cursor column was originally defined with a length that is insufficient for the data being stored. The error arises from base64-encoded JSON blobs exceeding the 255-character limit. The table was introduced in the current branch and has not yet been merged into the main branch.

Acceptance criteria

  • Update the cursor column definition to varchar(1024) in the content_provider_sync_cursors table.

  • Ensure no separate migration is needed since the table is new and not yet in the main branch.

Other information

  • Original migration file: 20260327200000_create_content_provider_sync_tables.rb

  • Error message: Mysql2::Error: Data too long for column 'cursor'


PD-12639



PD-12833

As a user I can see a progress indicator as I move through the formal assessment

As a user I must be able to clearly see my progress as I move through a formal assessment.


Story

As a user…

  • Above each question I can see a progress bar indicating now far I am through the assessment.

  • The bar should be grey by default, and as I progress through the assessment it updates and displays progress in accordance to the percentage I am through the assessment. For example, in a 10 question assessment, if I am on the first question, 10% of the progress bar is populated with company colours. If I am on the 5th question, then 50% of the bar is populated with company colours.

  • Progress should be depicted with company colours.

  • If I am on the last question, then the whole bar should be populated with company colours, as I am 100% through the assessment.

QA Note: Please note that the design shows a segmented progress bar. Ignore this, we are expecting to see a solid bar.

AC1: Progress bar is visible above each question

  • Given I am a user taking a formal assessment

  • When I view any question in the assessment

  • Then I can see a progress bar displayed above the question

AC2: Progress bar default state

  • Given I have not yet started progressing through the assessment

  • When the progress bar is rendered

  • Then the bar displays the company colours of the percentage comprised of the first question

AC3: Progress bar updates based on current position

  • Given I am on question N of a total of T questions in the assessment

  • When the progress bar is displayed

  • Then the bar is filled to (N / T) × 100% using the company colours, and the remaining portion remains grey

AC4: Progress bar reflects correct percentage (example: first question)

  • Given I am taking a 10-question assessment

  • When I am on the 1st question

  • Then 10% of the progress bar is filled with company colours

AC5: Progress bar reflects correct percentage (example: midway)

  • Given I am taking a 10-question assessment

  • When I am on the 5th question

  • Then 50% of the progress bar is filled with company colours

AC6: Progress bar at 100% on the last question

  • Given I am taking a formal assessment

  • When I am on the last question of the assessment

  • Then the entire progress bar (100%) is filled with company colours

AC7: Company colours are used for progress

  • Given the organisation has company colours configured

  • When the progress bar fills as I advance through the assessment

  • Then the filled portion of the bar is rendered using the company colours

PD-12199



PD-12831

As a user I can clearly see which question I am on out of x amount

As a user I must be able to see clearly which question I am on out of the number of questions within the formal assessment.

Story

As a user…

  • I can clearly see in the top left the information regarding which question I am on out of the number of questions within the formal assessment. This will be displayed in the format ‘Question ‘x’ of ‘y’’ (this 'y' being the total number of questions in the formal assessment). For example ‘Question 1 of 9’.

  • Given I am taking a formal assessment that contains multiple questions

  • When I view any question in the assessment

  • Then I can see a question progress indicator in the top left of the screen in the format "Question X of Y" (e.g. "Question 1 of 9")

  • Given I am on question, for example 3 of a 9-question formal assessment

  • When I navigate to the next question

  • Then the progress indicator updates, for example to "Question 4 of 9"

  • Given a formal assessment has been configured with a specific number of questions

  • When I begin the assessment and view any question

  • Then the total number shown in the indicator matches the actual number of questions in the assessment

  • Given I have started a formal assessment

  • When the first question is displayed

  • Then the progress indicator reads "Question 1 of Y", where Y is the total number of questions

  • Given I am taking a formal assessment with Y questions

  • When I reach the final question

  • Then the progress indicator reads "Question Y of Y"

PD-12199



PD-12803

[New Content Pages] Article links cause infinite reload loop when clicked

Description

Links added to articles on the new content pages send the user into an infinite loop of page reloads when clicked directly.

The links work as expected when right-clicking and selecting "Open in new tab", but clicking them normally triggers a continuous reload cycle.

Steps to reproduce

  1. Navigate to the affected article: https://fuse.fuseuniversal.com/communities/6479/contents/725765 or https://fuse.fuseuniversal.com/communities/6479/contents/726821

  2. Click on any link within the article content

  3. Observe the page enters an infinite reload loop

Expected behaviour

Clicking a link within an article should navigate the user to the linked destination without triggering a page reload loop.

Workaround

Right-click the link and select "Open in new tab" — the link resolves correctly.

Instance affected

https://fuse.fuseuniversal.com


PD-12110



PD-12802

Task 12 - Sync content metadata (tags, description, thumbnail) from Stack One into fuselite

Summary

Sync content metadata from Stack One into fuselite. This includes tags, descriptions, and thumbnails for mirror Content records.

Context

This task is part of the metadata improvements epic (PD-10626). The Stack One API offers richer metadata than is currently stored. This implementation will sync that metadata into the shared database for FuseTube consumers. Language mapping is not included in this task.

Acceptance criteria

  • Tags from Stack One (categories, skills, tags fields) are stored on the mirror Content record and update correctly on re-sync.

  • Description and thumbnail sync correctly on both create and update.

  • ExternalContent.languages stores a clean JSON array of locale codes.

  • All specs pass.

Other information

  • Included:

    • Sync tags, categories, and skills from Stack One into Fuse content tags via a new ContentTagSync service.

    • Sync description from Stack One into the mirror Content record.

    • Sync thumbnail from Stack One into the mirror Content record via ContentTagSync.

    • Add Tag and Tagging AR models to fuselite.

    • Full RSpec coverage.

  • Not included:

    • Syncing languages to the contents table (pending clarification).

    • Any FuseTube changes.

  • Implementation notes:

    • Tags are a union of row["tags"] + row["categories"] + row["skills"].

    • ContentTagSync writes directly to the shared tags/taggings tables without acts-as-taggable-on gem.


PD-12639



PD-12794

[Growth Squad][Transcription]Copy transcription message fails to appear in user set language.

When the user sets their language to something other than English and clicks on the copy button to copy the transcripts. The message “Transcript copied to clipboard” appears in English.

Ideally, it should appear in the same language that the user has set.

Tested these scenarios on the German, French, and Spanish languages.


PD-11762



PD-12790

Results Screen - fail

Story

As a User…


  • Once I answer the last question in a formal assessment and click ‘Submit’, then I am navigated to the results screen.

  • On the results screen, I can see my score, and the pass criteria.

  • I can see the buttons 'Retake assessment' - provided further attempts are available.

  • I can see the relevant messaging indicating I have failed the assessment.

  • I can only see the results from the session I have completed. Prior scores are not displayed, e.g., If I pass an assessment, then retake it and fail, I will see the result of the fail as it is the most recent session I completed.

Given I have answered the last question in a formal assessment, and failed to meet the pass criteria
When I click "Submit"
Then I am navigated to the results screen
And I can see my score, and the pass criteria.
And I can see the “Retake assessment" button - provided further attempts are available.
And I can see the relevant messaging Informing me I have failed.


Given I have NOT met the pass criteria and failed the assessment
When I see the relevant messaging
Then it says ‘Not quite there. You did not meet the pass criteria this time'

Given I am on the results screen
When there are no other attempts available
Then I see the ‘no attempts left banner already utilised on the splash screen’. ( PD-12345 )


Given I have just completed a formal assessment session
And I am viewing the results screen
When I view my assessment results
Then I can only see the results from the session I have just completed
And prior scores from earlier sessions are not displayed
And if I previously passed the assessment but then retake it and fail, I see the result of the failed attempt because it is the most recent completed session

PD-12199



PD-12786

The top bar navigation is stuck in a loop

Impact

The top bar navigation gets stuck in a loop. This occurs when there are duplicate contents in the learning plan. Users are unable to navigate effectively.

Expected behaviour

The top bar navigation should function smoothly without looping. Users should be able to access different sections of the learning plan without issues.

Actual behaviour

The top bar navigation is stuck in a loop when duplicate contents are present in the learning plan.

Steps to reproduce

  • Create a learning plan with duplicate contents.

  • Attempt to use the top bar navigation.

Environment

N/A

Workarounds

N/A

Other information

N/A


PD-11108



PD-12776

[FE][Article] Images revert to 100% size on publish — editor resize not retained

Description

When an article is published, images that have been manually resized in the article editor revert to 100% width. The resized dimensions set by the author are not retained on the published content page.

Expected behaviour

Images should retain the size they were adjusted to in the article editor view when the article is published. The published article should reflect the same image dimensions the author set during editing.

Acceptance Criteria

  • When an author resizes an image in the article editor (e.g. to 50% or a specific pixel width), the published article displays the image at that same size

  • Image size persists correctly across save, publish, and subsequent page loads

Steps to reproduce

  1. Create or edit an article

  2. Insert an image

  3. Resize the image to a size smaller than 100% (e.g. 50%)

  4. Save and publish the article

  5. View the published article

  6. Observe that the image has reverted to 100% width

Example

https://fuse.fuseuniversal.com/communities/6117/contents/725752


PD-12110



PD-12769

Task 11 — Download and store Stack One content thumbnails into shared assets table

Summary

This issue involves downloading and storing Stack One content thumbnails into a shared assets table used by FuseTube and fuselite. The goal is to ensure that fuselite can write to the same table so that FuseTube can serve images seamlessly.

Context

FuseTube and fuselite utilize the same MySQL database and S3 assets bucket (ASSETS_BUCKET). Currently, LearningObjectsSync stores image URLs directly without creating the necessary asset rows. This leads to missing thumbnails, as noted in a previous comment on PD-12639.

Acceptance criteria

  • contents.thumbnail_id is populated for Stack One content rows with a cover_url/thumbnail_url.

  • The assets row has:

    • type = 'Asset::ContentAsset'

    • Correct asset_uid S3 key

    • Valid asset_data JSON

  • FuseTube serves the image through its existing pipeline without changes.

  • Re-syncing the same content with the same image URL is idempotent.

  • Content without an image URL results in no asset row and thumbnail_id = NULL.

Other information

Approach

  • New service: FuseliteStackOne::ContentThumbnailSync

    • Accepts a thumbnail_url string and company_id.

    • Downloads the image via Net::HTTP (following redirects).

    • Uploads binary to S3 under uploads/{company_id}/stack_one/{sha256_of_url}.{ext}.

    • Finds or creates an Asset::ContentAsset with asset_uid = S3 key and asset_data JSON (matching the format used by ThumbnailHelper).

    • Returns the asset.

  • LearningObjectsSync#upsert_mirror_content calls ContentThumbnailSync and assigns content.thumbnail = asset.

  • Skip if thumbnail_url is blank or S3 key already exists (idempotent).

  • Errors are logged and swallowed; a failed image download must not abort the content sync.


PD-12639



PD-12766

Task 10 - Update URL for dashboard

Summary

The task is to update the URL for the dashboard.

Context

The current URL needs to be changed to improve accessibility.

Acceptance criteria

  • The dashboard URL should be updated to /smartconnectors.

Other information

N/A


PD-12639



PD-12763

Results Screen - pass

Story

As a User…

  • Once I answer the last question in a formal assessment and click ‘Submit’, then I am navigated to the results screen.

  • On the results screen, I can see my score, and the pass criteria.

  • I can see the button 'Retake assessment' - provided further attempts are available.

  • I can see the relevant messaging indicating I have passed the assessment.

  • I can only see the results from the session I have completed. Prior scores are not displayed, e.g., If I pass an assessment, then retake it and fail, I will see the result of the fail as it is the most recent session I completed.

Given I have answered the last question in a formal assessment
When I click "Submit"
Then I am navigated to the results screen
And I can see my score, and the pass criteria.
And I can see the "Retake assessment" button - provided further attempts are available
And I can see the relevant messaging informing me I have passed

Given I am on the results screen
When there are no other attempts available
Then I see the ‘no attempts left banner already utilised on the splash screen’. ( PD-12345 )


Given I am on the results screen
When I see the results
Then they should be the latest results, not the highest result I have ever scored for this formal assessment

Given I have met the pass criteria and passed the assessment
When I see the relevant messaging
Then it says ‘Congratulations! You passed the formal assessment’

Given I have just completed a formal assessment session
And I am viewing the results screen
When I view my assessment results
Then I can only see the results from the session I have just completed
And prior scores from earlier sessions are not displayed
And if I previously passed the assessment but then retake it and fail, I see the result of the failed attempt because it is the most recent completed session

Note: Ignore the View Breakdown button in the design. This will be future development work, and is not part of this story.

PD-12199



PD-12737

FE: Update Assessment Button State Based on Retake Eligibility

Description:
As a user, I want the assessment action button to clearly reflect whether I can retake an assessment, so that I understand my available options without confusion.

Acceptance Criteria:

  1. Retake Label:

    • If the user has already completed the formal assessment but is still eligible for additional attempts, the button label should display “Retake Assessment.”

  2. Disabled State:

    • If the user is not eligible to retake the assessment, then they will see the information box detailing as such, and the “Retake Assessment” button is not visible.

Given I have completed the formal assessment, but I am eligible for additional attempts
When I see the button
Then the button will state ‘Retake Assessment’

Given I am not eligible to retake the assessment (e.g., no attempts remaining or restricted)
When I see page
Then the button will not be visible and an information box is present.

PD-12199



PD-12713

Change the "you" German translation on instance from Sie to "Ich"

Impact

The German translation of "you" in the side menu is incorrect. Users see "Sie" instead of "Ich". This affects user experience for German-speaking clients.

Expected behaviour

The side menu should display "Ich" as the translation for "you" in German.

Actual behaviour

Currently, the side menu shows "Sie" instead of "Ich".

Steps to reproduce

  • Navigate to the side menu on the affected instance.

  • Observe the translation of "you".

Environment

The bug is present in the following instance:

Workarounds

N/A

Other information

This change is part of efforts to retain VAT as a client.



As a user when I look at my side menu I see the correct translation of “you” displayed as “Ich” in German.

PD-11800



PD-12704

Top bar navigation previous next buttons are not working

Impact

The previous and next buttons in the top bar navigation are not functioning. This affects user navigation, making it difficult to move between pages.

Expected behaviour

The previous and next buttons should allow users to navigate to the previous or next page smoothly.

Actual behaviour

The buttons do not respond when clicked, preventing navigation.

Steps to reproduce

  • Open the application.

  • Locate the top bar navigation.

  • Click on the previous button.

  • Click on the next button.

Environment

N/A

Workarounds

N/A

Other information

N/A


PD-11108



PD-12701

Set up Workspaces on Gooddata via API

GoodData Workspaces will be manually created via the GoodData API.

The goal of this ticket is to document this process.


Included in creating a workspace will be:

  • Creating the relevant user groups for the company

  • Assigning permissions to the user groups


Workspace naming:

ID = {stack_name}_{company_id}

Name = {Customer name or domain name}


User group naming:

ID = {stack_name}_{company_id}_{usergroup_name}

Name = {domain name or customer name + the name of the role (like community admin or manager)}


PD-12617



PD-12648

Task 9 — SDK compatibility documentation

Summary

This issue focuses on documenting the FuseLite Stack One SDK sync feature. The goal is to provide comprehensive documentation that helps engineers understand, operate, and troubleshoot the feature.

Context

The documentation will be based on a reference PR and implementation. It aims to clearly explain the end-to-end functionality of the Stack One sync feature and how it differs from the previous FuseTube integration.

Acceptance criteria

  • Feature overview clearly explains:

    • What the Stack One sync does.

    • The problems it solves.

    • How it differs from the previous FuseTube integration.

  • End-to-end flow is documented, including:

    • Scheduled sync flow (RecurringSync → ScheduleSyncJob → CoordinatorJob → PageJob).

    • On-demand sync flows (rake tasks and per-user completion sync).

    • Behavior of different sync types (memberships, contents, courses, completions).

  • Architecture and key components are described:

    • Job hierarchy and fan-out model.

    • LmsGateway and ResponseParser responsibilities.

    • Resumability and cursor persistence strategy.

    • Idempotent upsert approach and fault tolerance model.

  • Data model and side effects are documented:

    • Tables written to and the reasons.

    • Mapping of external data to internal models (e.g., ExternalContent, ExternalMembership).

    • Logging and observability via ContentProviderSyncLog.

  • Operational behavior is covered:

    • Scheduling and cadence.

    • Retry behavior and failure handling.

    • Handling unsupported providers and API inconsistencies.

    • Environment/config requirements (e.g., STACK_ONE_* vars, Sidekiq setup).

  • Key implementation decisions and trade-offs are explained:

    • Use of raw Faraday responses in some cases.

    • SDK limitations and workarounds.

    • Cursor-based pagination and resumability design.

  • Setup and usage instructions are documented:

    • How to trigger syncs locally (rake tasks).

    • How to run/debug jobs.

    • How to verify sync results.

  • Guidance for future changes:

    • How to add a new sync type.

    • How to extend existing sync logic safely.

    • Sensitive or tightly coupled areas.

  • PR documentation (or equivalent doc) includes:

    • High-level summary.

    • Architecture overview.

    • Rollout / production cut-over considerations.


PD-12639



PD-12647

Task 8 — Tests

Approach: Port spec/integration/stack_one_sync_pipeline_spec.rb from the reference branch as a final validation pass once Stories 1–7 are complete. This spec exercises the full pipeline end-to-end against a real test database and should pass without modification if the implementation is correct.

Goal: All sync behaviour is covered by automated tests and the three correctness bugs found during development cannot regress.

Acceptance criteria:

  • All sync services, jobs, and dashboard endpoints have unit specs

  • End-to-end integration spec exercises the full pipeline against a real test database

  • Explicit regression cases for:

    • Concurrent workers on the same content row do not raise RecordNotUnique on CommunityItem

    • Re-syncing an already-known completion does not enqueue redundant downstream jobs

    • SyncUserCompletionsJob finds a completion that falls beyond the first page of results

  • 84 examples, 0 failures, 0 rubocop offenses

Key files: spec/jobs/fuselite_stack_one/, spec/services/fuselite_stack_one/, spec/requests/api/v10/sync_dashboard*, spec/integration/stack_one_sync_pipeline_spec.rb, spec/factories/

Depends on: Stories 1–7


PD-12639



PD-12646

Task 7 — Sync dashboard API

Approach: TDD. Port spec/requests/api/v10/sync_dashboard_spec.rb and sync_dashboard_stale_coordinator_spec.rb first.

Goal: Operators have real-time visibility into sync health and can trigger syncs without touching the Rails console or Sidekiq UI.

Acceptance criteria:

  • GET /api/v10/sync_dashboard — summary stats + per-provider status; shows in-progress syncs with ETA based on remaining pages and rolling average page duration

  • GET /api/v10/sync_dashboard/logs — filterable by provider, status, and sync type

  • GET /api/v10/sync_dashboard/queue — live Sidekiq queue, retry, and dead job counts

  • POST /api/v10/sync_dashboard/enqueue — triggers a sync for a specific provider + sync type

  • All endpoints require authentication and verify the user belongs to the company

  • Documented in swagger/v10/swagger_internal.json, accessible via Swagger UI

Key files: app/controllers/api/v10/sync_dashboard_controller.rb, swagger/v10/swagger_internal.json, config/routes.rb, public/docs/stack_one_sync_dashboard.html

Depends on: Story 3


PD-12639



PD-12645

Task 6 — Per-user on-demand completion check

Approach: TDD. Port spec/jobs/fuselite_stack_one/sync_user_completions_job_spec.rb first. Pay particular attention to the pagination regression case — the spec explicitly covers a completion that falls beyond the first page of results.

Goal: When a user engages with external content, their completion status is checked against the LMS immediately rather than waiting for the next scheduled batch.

Acceptance criteria:

  • ExternalContentProgressJob triggers SyncUserCompletionsJob for content backed by ExternalContent

  • SyncUserCompletionsJob paginates all pages of list_user_assignments until the matching assignment is found or all pages are exhausted

  • Writes ExternalContentCompleteness only when a completed assignment is confirmed

  • No-op if the user has no ExternalMembership for the provider or integration is disabled

Key files: app/jobs/external_content_progress_job.rb, app/jobs/fuselite_stack_one/sync_user_completions_job.rb

Depends on: Story 3


PD-12639



PD-12644

Story 5 — Recurring sync schedule

Approach: TDD. Port spec/jobs/fuselite_stack_one/recurring_sync_spec.rb first. These specs are simple delegation checks and will drive the four job subclasses and schedule config cleanly.

Goal: Each sync type runs automatically on a fixed cadence matching FuseTube's existing schedule, with no manual intervention required.

Acceptance criteria:

  • Memberships daily at 06:00, external contents at 06:30, courses at 07:30, completions hourly at :02

  • Schedule defined in config/sidekiq-schedule.yml, loaded at Sidekiq server startup

  • Not loaded in the test environment

  • Each RecurringSync job class delegates entirely to ScheduleSyncJob and contains no sync logic

Key files: app/jobs/fuselite_stack_one/recurring_sync/, config/sidekiq-schedule.yml, config/sidekiq.yml, config/initializers/sidekiq.rb

Depends on: Story 4


PD-12639



PD-12642

Task 3 — Sync services

Approach: TDD. Port spec/services/fuselite_stack_one/sync/ from the reference branch first. The specs are behavioural and cover all three sync types, the resumable mixin, and the three correctness bugs — use them to drive the implementation.

Goal: Each sync type is a self-contained, testable service that can be run, resumed after interruption, and safely re-run without duplicating or corrupting data.

Acceptance criteria:

  • MembershipsSync upserts ExternalMembership rows keyed by (source_id, content_provider_id)

  • LearningObjectsSync upserts ExternalContent + mirror Content + CommunityItem; publishes or deactivates the mirror content to match the active flag; concurrent execution by multiple workers on the same row does not raise or produce duplicates

  • CompletionsSync writes ExternalContentCompleteness using completed_at (not updated_at); triggers ExternalContentProgressJob only for newly created records, not re-syncs

  • All sync classes share a Resumable mixin: cursor persisted after every page, expired cursors (HTTP 400/404/410) detected and restarted from page 1, max_pages guard prevents runaway

  • All upserts are idempotent

Key files: app/services/fuselite_stack_one/sync/resumable.rb, app/services/fuselite_stack_one/sync/memberships_sync.rb, app/services/fuselite_stack_one/sync/learning_objects_sync.rb, app/services/fuselite_stack_one/sync/completions_sync.rb, app/jobs/fuselite_stack_one/concerns/builds_sync.rb

Depends on: Story 1, Story 2


PD-12639



PD-12641

Task 2 — Data model + schema

Approach: Implementation-first. Port the factories from the reference branch (spec/factories/) once models are defined — they will be needed by Stories 3–8.

Goal: All data produced by the sync has a well-defined, validated home in the database that is safe to run against the shared FuseTube/FuseLite DB.

Acceptance criteria:

  • content_provider_sync_cursors — one row per (provider, sync_class), stores pagination cursor, coordinator JID, and progress metadata for dashboard ETA

  • content_provider_sync_logs — append-only audit log per sync run with success / failed / skipped status and error detail

  • ExternalContent, ExternalMembership, ExternalContentCompleteness, ExternalContentTarget are fully modelled with validations and associations

  • LearningPlanItem STI hierarchy covers Content and ExternalContent item types

  • Company exposes stack_one_integration_enabled?; Company::Settings stores stack_one_integration_enabled and stack_one_external_content_owner_id

  • User exposes stack_one_learning_plan_ids covering community, audience, and assigned-membership visibility types

  • Migrations use if_not_exists — safe to run against a DB FuseTube may have already migrated

Key files: app/models/content_provider_sync_cursor.rb, app/models/content_provider_sync_log.rb, app/models/external_content.rb, app/models/external_membership.rb, app/models/external_content_completeness.rb, app/models/external_content_target.rb, app/models/learning_plan_item/, app/models/company.rb, app/models/company/settings.rb, app/models/user.rb, db/migrate/20260327*, db/migrate/20260331*


PD-12639



PD-12640

Task 1 — Stack One API integration layer

Approach: Implementation-first. SDK behaviour and compatibility issues can only be discovered by running against the real API. Consult docs/stack_one_sdk_issues.md in the reference branch for known issues and their workarounds before starting.

Goal: Provide a stable internal interface to the Stack One LMS API so the rest of the app is decoupled from the SDK and HTTP transport details.

Acceptance criteria:

  • All Stack One API calls go through FuseliteStackOne::LmsGateway — no direct SDK usage outside it

  • Supports: list_users, list_content, list_courses, list_assignments, list_user_assignments

  • Pagination cursors are correctly extracted and forwarded across all endpoints

  • Provider-unsupported endpoints (403 / 501) are surfaced as a consistent error type

  • All configuration (API URL, credentials, batch size, delta threshold) is env-driven with sensible defaults

Key files: app/services/fuselite_stack_one/client.rb, app/services/fuselite_stack_one/lms_gateway.rb, app/services/fuselite_stack_one/response_parser.rb, app/services/fuselite_stack_one/configuration.rb, config/initializers/stack_one_sdk.rb


PD-12639



PD-12633

[New Content][Hotfix]Clickable links formatting is not in order once the content is published.

It is observed that when the user adds multiple links with proper spacing between them in the description of new content pages, the formatting is disrupted and the links are published without any spaces in the description box.


PD-11700



PD-12520

Deleted tags are showing their search filters

Description:
Tags were mass deleted by DevOps upon request but they are still showing in search filters

Instance affected:
pmi.fuseuniversal.com

Path:
Example https://pmi.fuseuniversal.com/web_search?search-term=how+leader&page-number=1

Can this be Replicated on client instance?
Yes https://pmi.fuseuniversal.com/web_search?search-term=how+leader&page-number=1

Can this be Replicated on other stacks?
No - we have no instance where tags were mass deleted by DevOps to test this

Can this be Replicated on client stack?
No - we have no instance where tags were mass deleted by DevOps to test this

Steps To Replicate:
Search a term
View filtering options

Actual Result:
Deleted tags are present

Client Expected Result:
Deleted tags should not show up

Hypothesis:
Search indexing delay after deletion of tag

Documented Behaviour:
All tags were deleted and documented here:
https://fuseuniversal.atlassian.net/browse/FST-1031
Therefor they should not be visible anywhere on the instance

Additional information:

image-20260319-060616.png


PD-9397



PD-12499

FE: Place top bar navigation onto monolith SCORM page

Story

  • As a user I can see the top bar navigation at the top of the existing monolith pages for SCORM.

  • As a user I am able to see these when I navigate from the Learning Plan Overview page, or navigate to the SCORM page utilising the Next and Previous button in the top bar navigation

Given I am viewing a SCORM page
And I have navigated to the page from the Learning Plan Overview page
When the page loads
Then I can see the new top bar navigation rendered at the top of the page above the main SCORM content

Given I am viewing a SCORM page
And I have navigated to the page using the top bar navigation - either next or previous buttons
When the page loads
Then I can see the new top bar navigation rendered at the top of the page above the main SCORM content

PD-11108



PD-12497

As a user I want to be able to answer a multiple choice question - Image Answer type

User story

  • As a user, when I am answering a question that allows multiple answers, I want to be able to select more than one option so that I can accurately reflect all correct responses.

  • As a user, I want the UI to clearly show that I can choose multiple answers so that I am not misled into selecting only one.

Context

This issue involves the implementation of a multiple answer question format for Many correct multiple choice questions in assessments. The goal is to ensure that users can select multiple answers for a single question, with clear UI indications and consistent behaviour across different multiple choice answer formats, as defined in the Question creator in the Assessment tab:
Adding questions to the question pool in assessments

This story excludes assessment tools and only covers Image single answer questions.

Acceptance criteria

  • For Many correct multiple choice questions, the user can select one, or multiple answers at the same time (checkbox-style behaviour).

  • Each answer option is independently selectable and deselectable without affecting other selections.

  • The UI must clearly indicate that multiple answers may be selected (e.g., checkbox controls).

  • The behaviour must be distinct from One correct questions where only a single answer is allowed.

  • The question must behave correctly regardless of the multiple choice answer format - Image answers: shown as an image with a multiple-choice selector.

  • Aspect rations should be respected. The UI should be responsive, and where necessary, answers should be stacked.

Other information

N/A


PD-12199



PD-12493

As a user I want to be able to take a single answer question - Fraction Answer type

User story

  • As a user, when I am answering a question, I want to select only one answer so that I can provide a clear response.

  • As a user, when I change my answer, I want the previous selection to be automatically deselected so that there is no confusion about my choice.

Context

This issue involves the implementation of a single answer question format. The goal is to ensure that users can only select one answer at a time, with clear UI indications and consistent behaviour across different answer formats.

This story excludes assessment tools and only covers Fraction single answer questions.

Acceptance criteria

  • Only one answer can be selected at a time (radio-style behaviour).

  • Changing the selection automatically deselects any previously selected answer.

  • The behaviour must be distinct from Many correct questions.

  • The question must behave correctly - Fraction answers: shown as a fraction with a single-choice selector.

  • Aspect rations should be respected. The UI should be responsive, and where necessary, answers should be stacked.

Other information

N/A


PD-12199



PD-12466

Video - Transcript Chapters

As a learner viewing a video transcript, I want to click a chapter marker and jump to that section of the transcript, So that I can quickly navigate to relevant parts of the content.

AC1 — Create Chapters

  • Given an author of a piece of content has added ‘jump to’ positions in a video

  • When the transcript panel is open

  • Then the chapter headings are visible at the top of the transcript tab as per the design

AC2— Click scrolls to chapter

  • Given a learner clicks a chapter marker

  • When the transcript panel is open

  • Then the panel smooth-scrolls so that the matching chapter heading is positioned at the top of the visible area

AC3 — Edit Chapters

  • Given an author of a piece of content has edited the ‘jump to sections’

  • When the transcript panel is open

  • Then the updated chapter headings are visible at the top of the transcript tab as per the design

PD-11762



PD-12433

As a user I want to be able to answer a variation question

User story

  • As a user, when I am answering a variation question, I am able to see the question and then a free text field beneath it.

  • As a user I am able to click into the free text field and input my answer.

  • As a user, I am unable to click the ‘Next question’ button until I have input something into the free text field.

Context

The issue involves the implementation of a variation answer question format for Variation choice questions in assessments. The goal is to ensure that users can input their answer into the free text field, with clear UI indications and consistent behaviour, as defined in the Question Creator in the Assessments tab: Adding questions to the question pool in assessments

Variation assessments only allow text answer types - fractions and images are not included.

  • Users can click into the free text field and input an answer.

  • If a user has yet to click into the answer box, then they will see the words ‘Enter answer here’ within the free text field box.

  • If a user clicks into the free text field box, then the words ‘Enter answer here’ move above the box, and the text ‘Enter answer here’ and framing of the box become the company colours.

  • Should the user clear an answer in the free text field, then click outside the box, then the ‘Enter answer here’ text will display within the box again.

PD-12199



PD-12347

As a user I want to be able to answer a multiple choice question - Text answer type

User story

  • As a user, when I am answering a question that allows multiple answers, I want to be able to select more than one option so that I can accurately reflect all correct responses.

  • As a user, I want the UI to clearly show that I can choose multiple answers so that I am not misled into selecting only one.

Context

This issue involves the implementation of a multiple answer question format for Many correct multiple choice questions in assessments. The goal is to ensure that users can select multiple answers for a single question, with clear UI indications and consistent behaviour across different multiple choice answer formats, as defined in the Question creator in the Assessment tab:
Adding questions to the question pool in assessments

This story excludes assessment tools and only covers Text multiple choice answer questions.

Acceptance criteria

  • For Many correct multiple choice questions, the user can select one, or multiple answers at the same time (checkbox-style behaviour).

  • Each answer option is independently selectable and deselectable without affecting other selections.

  • The UI must clearly indicate that multiple answers may be selected (e.g., checkbox controls and/or helper text such as “Select all that apply”).

  • The behaviour must be distinct from One correct questions where only a single answer is allowed.

  • The question must behave correctly regardless of the multiple choice answer format configured in the Question creator:

    • Text answers: shown as text with a multiple-choice selector.

N/A


PD-12199



PD-12346

As a user I want to be able to take a single answer question - Text Answer type

User story

  • As a user, when I am answering a question, I want to select only one answer so that I can provide a clear response.

  • As a user, when I change my answer, I want the previous selection to be automatically deselected so that there is no confusion about my choice.

Context

This issue involves the implementation of a single answer question format. The goal is to ensure that users can only select one answer at a time, with clear UI indications and consistent behaviour across different answer formats.

This story excludes assessment tools

Acceptance criteria

  • Only one answer can be selected at a time (radio-style behaviour).

  • Changing the selection automatically deselects any previously selected answer.

  • The behaviour must be distinct from Many correct questions.

  • The question must behave correctly regardless of the answer format - Text answers: shown as text with a single-choice selector.

Other information

N/A


PD-12199



PD-12345

As a user taking a formal assessment in a learning plan I want to land on a splash page to introduce the assessment.

Description / Context (expanded)

When a learner navigates to a formal assessment from a learning plan, they should first see a dedicated splash page before any questions are shown.

This splash page should:

  • Clearly confirm that this is a formal assessment (not just casual practice/quiz).

  • Provide key information about the assessment (e.g. title, number of questions, pass criteria, time expectations where applicable).

  • Set a professional, consistent tone across all formal assessments in learning plans.

The page is read-only context; the only primary action is to take the assessment. Any secondary actions (e.g. return to learning plan) should be clearly labelled so that the learner doesn’t accidentally exit.
If the user has already completed the assessment they are able to retake (if the settings applies) or move to the next piece of content.

This story is focused on the user-facing experience of that splash page; data and configuration (e.g. pass mark, attempt limits) are assumed to already exist in backend / settings and are only being surfaced here.


Acceptance Criteria

  1. Entry point & triggering

    • When a learner navigates to the formal assessment from a learning plan

      • Via the learning plan overview page

      • Via the next button on a previous content in the learning plan

      • Via a direct link

      • They are taken to the splash page before any question is displayed

  2. Required content on the splash page

    • The splash page displays:

      • The assessment title (Right now the API throws always null as there’s no way to change the Assessment title, we will use “Formal Assessment” as default title) @User

      • The number of questions or an indication of approximate length (e.g. “10 questions”). - Only if available in the api. Cross out if not available.

      • The pass criteria (e.g. required score/percentage) if configured for the assessment. - Only if available in the api. Cross out if not available.

      • A short explanation of what happens on completion, aligned with the wiki:

        • That completion contributes to learning plan progress.

        • Whether retakes are allowed (if this information is already available/configured). Out of scope

  3. Actions on the splash page

    • The splash page provides a primary action button (e.g. “Take assessment”) that: → This is provided by API

      • Starts the assessment and displays the first question.

    • The splash page provides a clear way to go back without starting (Top Bar Navigation) which:

      • Returns the learner to the previous learning plan view.

      • Skips assessment (if sequential learning not enabled)

      • Does not create a partially-started attempt.

  4. Visual and UX consistency

    • The styling of the splash page is consistent with the current learning plan / assessment UI guidelines documented in Confluence (typography, spacing, button style, etc.).

    • The page clearly communicates that this is a formal assessment (e.g. using a label or subtitle), maintaining the “professional welcome” tone described in the epic.


PD-12199



PD-12285

UA2 - BE - Enable navigation to UA2 via community admin settings page

This story is about enabling navigation to UA2 through the community admin settings page.

  • As a community admin, when I access the admin settings page, I want to see the dashboard load and display the correct UA2 data when I navigate there.

  • Navigation to UA2 must be accessible from the community admin settings page.

  • On navigation to UA2, the backend fetches and returns the correct UA2 data for the current context, and the UI displays it without errors.

PD-11831



PD-12275

FE: Place top bar navigation onto monolith Events & Occurrence pages

Story

  • As a user I can see the top bar navigation at the top of the existing monolith pages for Events.

  • As a user I can see the top bar navigation at the top of the existing monolith pages for Occurrences.

  • As a user I am able to see these when i navigate from the Learning Plan Overview page, or navigate to the Event and Occurrences pages utilising the Next and Previous button in the top bar navigation.

Given I am viewing an Event page
And I have navigated to the page from the Learning Plan Overview page
When the page loads
Then I can see the new top bar navigation rendered at the top of the page above the main Event content

Given I am viewing an Occurrence page
And I have navigated to the page from the Learning Plan Overview page
When the page loads
Then I can see the new top bar navigation rendered at the top of the page above the main Occurrence content

Given I am viewing an Event page
And I have navigated to the page using the top bar navigation - either next or previous buttons
When the page loads
Then I can see the new top bar navigation rendered at the top of the page above the main Event content

Given I am viewing an Occurrence page
And I have navigated to the page using the top bar navigation - either next or previous buttons
When the page loads
Then I can see the new top bar navigation rendered at the top of the page above the main Occurrence content

PD-11108



PD-12074

UA2 - Automatic creation of users in GDC who don't already exist

As an analytics users
I want to be automatically created in GoodData Cloud with the permissions relevant to my role at the point that I try and access analytics
So that I do not need to be manually created

  • Given the user is a community admin of the community, if the user does not already exist in GDC when they try and access analytics from the community settings page > Analytics option, then we create them in GDC with the right access and the right workspace permissions i.e community admin = view communities dashboards only

  • Given the user is a community admin of the community, if the user already exists in GDC when they try and access analytics from the community settings page > Analytics option, then we simply permit them to access the page in accordance with their permissions

  • Given the user is a site admin, when the user accesses analytics from the community settings page > Analytics option, The UI should behave exactly the same for a site admin as it would for a standard user who is a community admin

PD-11831



PD-11458

FE: Update Start/Continue Buttons to Use Next Content Item API

Description:
Update the frontend to leverage the new nextContentItemId field from the GET /learning/plans/{id} API. This will ensure the Start and Continue buttons always navigate the user to the correct next content item in the learning plan.

Requirements:

  • Fetch the learning plan details using GET /learning/plans/{id}.

  • Use the nextContentItemId field to determine the target content item for navigation.

  • Button behavior:

    • Get started – Navigate to the nextContentItemId when the user hasn’t started the plan.

    • Continue – Navigate to the nextContentItemId when the user has partially completed the plan.

  • If all items are completed, the API will return the first item; buttons should navigate there.

  • Ensure navigation integrates with the existing content routing logic.


Notes:

  • Coordinate with the backend team to confirm API field name (nextContentItemId).

  • Ensure proper loading states while fetching the learning plan data.

  • Consider caching or updating local state to prevent unnecessary API calls on repeated button clicks.


  • Get started button navigates to the next content item for users who haven’t started the plan.

  • Continue button navigates to the next uncompleted content item, or first item if all completed.

  • Existing button UI and styling remain unchanged.

  • No regressions in navigation for other learning plan workflows.

PD-11156



PD-11457

BE: Add “Next Item” Field to GET Learning Plan API

Description:
Enhance the /learning_plans/{id} API to include information about the next item in the learning plan sequence. This will allow the client to identify what the user should engage with next.

Requirements:

  • Add a new field in the API response for the next item in the sequence of learning plan items.

  • The field should return the ID of the next item.

  • Add the item type.

Logic:

  • If there are uncompleted items, return the next uncompleted item based on sequence order.

  • If all items are completed, return the first item in the learning plan sequence.

  • Next item can be:
    - Event
    - Event Occurrence
    - SCORM (within a topic)
    - SCORM
    - All normal content types
    - Formal Assessment
    - External content

  • Do NOT return the topic or any other types of assessment

Acceptance Criteria:

  • API correctly returns the next uncompleted item when there are pending items, and only items from the list above.

  • API returns the first item if all items are completed.

  • Existing API functionality remains unchanged.

  • If a Learning Plan has reset, then the user will navigate to the first item in the learning plan sequence.

PD-11156



Summary

Release 26.18 (4.2 Launch) delivers three main streams of value:

  1. Formal Assessments UX & Logic – A complete, production-ready experience for taking formal assessments in learning plans: a proper splash page, clear progress indicators, flexible question/answer types (text, image, fraction, variation), and robust pass/fail results handling including retakes.

  2. Stack One / FuseLite integration & sync pipeline – A fully documented, production‑grade LMS content and completion sync layer (Stack One → FuseLite/FuseTube) with resilient scheduling, observability, metadata/thumbnails sync, and multiple correctness fixes.

  3. Experience & localisation fixes – A set of targeted UI/UX and localisation improvements across content pages, top bar navigation, GoodData analytics access, search filters, and translations.

This release contains a mix of net-new capabilities, significant improvements to existing features, and a number of bug fixes that remove friction for learners, admins, and operators.


New Features

1. Formal Assessments: End‑to‑End Experience

Assessment splash page in learning plans

  • PD-12345 – Introduces a dedicated formal assessment splash page when accessed from a learning plan (via overview, Next button, or deep link).

  • The splash screen:

    • Confirms this is a formal assessment, not a casual quiz.

    • Shows the assessment title (defaulting to “Formal Assessment” where necessary).

    • Where available via API, shows:

      • Number of questions.

      • Pass criteria (e.g. required %).

    • Provides a single primary action to start/take the assessment, plus a safe route back via top‑bar navigation (no partial attempts created).

Question progress indicators & progress bar

  • PD-12831 – Adds a clear question counter:

    • Shows “Question X of Y” in the top left on every question.

    • Updates as the learner navigates between questions.

    • Ensures the total number matches the actual number of questions.

  • PD-12833 – Adds a visual progress bar for formal assessments:

    • Displayed above each question.

    • Filled proportionally to progress, e.g. 10% on Q1 of 10, 50% on Q5 of 10.

    • Uses company colours for the filled portion, grey for the remainder.

    • Shows 100% filled on the last question.

    • Behaviour is continuous (solid bar), not segmented (design segmentation is intentionally ignored).

Question & answer types: single- and multi‑select

  • PD-12346Single-answer (Text):

    • Radio-style behaviour: only one text answer can be selected at a time.

    • Changing selection deselects the previous option.

  • PD-12493Single‑answer (Fraction):

    • Same radio‑style behaviour, but for fraction-based answer UI.

    • Ensures only one fraction answer is active at any time.

  • PD-12347Many‑correct (Text):

    • Checkbox-style behaviour for multiple correct text answers.

    • Users can select and deselect multiple options independently.

    • UI clearly indicates multi‑select (checkboxes and/or helper text like “Select all that apply”).

  • PD-12497Many‑correct (Image):

    • Checkbox-style multi‑select behaviour for image answer options.

    • Answer images respect aspect ratio, and layout is responsive/stacked where necessary.

    • Behaviour clearly distinguished from single‑answer flows.

  • PD-12882Image-based questions (general):

    • Ensures when a question includes an image:

      • Question text is clearly visible and legible.

      • Image renders cleanly at an appropriate size without blocking text or options.

      • All answer options remain visible and interactable.

      • Selected answers are clearly highlighted; users can change selection before submission.

Variation question free‑text answer type

  • PD-12433 – Adds variation question support:

    • Learner sees the question with a free‑text field beneath.

    • “Enter answer here” placeholder behaves like a modern floating‑label:

      • Shows inside the field initially.

      • Moves above in company colours when the field is focused.

      • Returns to placeholder position if the field is cleared and blurred.

    • The Next question button is disabled until the learner has entered a response.

Results screens (pass and fail) and retake behaviour

  • PD-12763Results Screen – Pass:

    • After submitting the final question and meeting pass criteria:

      • User is redirected to a results screen showing score and pass criteria.

      • A “Retake assessment” button is shown if more attempts are available.

      • Messaging confirms success: “Congratulations! You passed the formal assessment”.

    • Results always show the latest session:

      • If a user passes once and later fails, the fail attempt is shown, not the historic pass.

      • Only the current session’s result is visible; previous scores are hidden.

    • “No attempts left” banner reuses existing UI from PD-12345 when attempts are exhausted.

  • PD-12790Results Screen – Fail:

    • After submitting the last question and not meeting pass criteria:

      • User is taken to a fail results screen with score and pass criteria.

      • “Retake assessment” is shown only if additional attempts are available.

      • Failure message: “Not quite there. You did not meet the pass criteria this time”.

    • Same “latest attempt only” logic applies as above.

    • Reuses the “no attempts left” banner when no further attempts remain.

  • PD-12737Assessment button state / retake eligibility:

    • If the user has completed the assessment and still has attempts left:

      • The button reads “Retake Assessment”.

    • If the user is not eligible to retake (no attempts remaining or restricted):

      • The Retake button is hidden, and an information box is shown instead.


2. Stack One / FuseLite Integration & Sync Pipeline

This release substantially matures the Stack One → FuseLite/FuseTube integration, turning it into a resilient, observable sync platform.

API integration layer and data model foundations

  • PD-12640Stack One API integration layer:

    • Centralises all Stack One API access through FuseliteStackOne::LmsGateway.

    • Supports:

      • list_users

      • list_content

      • list_courses

      • list_assignments

      • list_user_assignments

    • Correctly extracts and forwards pagination cursors and normalises provider‑unsupported endpoints (403/501) into consistent error types.

    • All configuration is environment-driven (API URL, credentials, batch size, delta thresholds).

  • PD-12641Data model + schema:

    • Introduces core tables and models to safely store external LMS data in the shared DB:

      • content_provider_sync_cursors – one row per (provider, sync_class) with cursor, Sidekiq JID, and progress metadata.

      • content_provider_sync_logs – append‑only audit log of sync runs with status and error detail.

      • ExternalContent, ExternalMembership, ExternalContentCompleteness, ExternalContentTarget – fully modelled with validations and associations.

      • LearningPlanItem STI hierarchy covers content and external content.

      • Company/Company::Settings exposes stack_one_integration_enabled? and stack_one_external_content_owner_id.

      • User exposes stack_one_learning_plan_ids to reflect visibility via communities, audiences, and memberships.

    • Migrations are defensive (if_not_exists) to co‑exist safely with existing FuseTube migrations.

Sync services, resumability, and correctness

  • PD-12642Sync services:

    • Introduces dedicated sync services with a shared Resumable mixin:

      • MembershipsSync – upserts ExternalMembership keyed by (source_id, content_provider_id).

      • LearningObjectsSync – upserts ExternalContent, mirror Content, and CommunityItem; aligns publish/deactivate state to remote active flag; avoids duplicates even under concurrent workers.

      • CompletionsSync – writes ExternalContentCompleteness using completed_at (not updated_at), and triggers ExternalContentProgressJob only for new completions.

    • Resumable behaviour:

      • Cursor persisted after every page.

      • Expired cursors (HTTP 400/404/410) detected and reset to page 1.

      • max_pages guard prevents runaway jobs.

    • All upserts are idempotent to support safe re‑runs.

  • PD-12840Cursor column widening:

    • In content_provider_sync_cursors, cursor is expanded from varchar(255) to varchar(1024) to avoid Data too long for column 'cursor' when storing long, base64‑encoded cursors.

  • PD-12945CoordinatorJob infinite loop fix:

    • Fixes an infinite loop in FuseliteStackOne::CoordinatorJob when Stack One returns a non‑advancing cursor:

      • Correctly decodes cursors (base64‑encoded JSON) and compares the pc (page cursor) field, not raw strings.

      • Detects and raises clear errors for non‑advancing cursors instead of re‑enqueuing endlessly.

      • sidekiq_retries_exhausted now clears the cursor to nil with reset progress metadata.

      • Preserves graceful shutdown resumability (jobs resume from last stored cursor).

      • Falls back to simple string equality if decoding fails.

    • This closes a real incident where external_courses sync had been failing and flooding Sidekiq with duplicate PageJobs after cursor truncation issues (fixed separately in PD‑12840).

Scheduling, dashboard & observability, operational tooling

  • PD-12644Recurring sync schedule:

    • Adds Sidekiq schedule with cadences mirroring FuseTube:

      • Memberships – daily at 06:00.

      • External contents – daily at 06:30.

      • Courses – daily at 07:30.

      • Completions – hourly at :02.

    • Jobs under fuselite_stack_one/recurring_sync delegate entirely to ScheduleSyncJob and contain no sync logic.

    • Schedule is not loaded in test to keep tests deterministic.

  • PD-12646Sync dashboard API:

    • New internal endpoints provide real‑time visibility and control:

      • GET /api/v10/sync_dashboard – summary stats and per‑provider status, including in‑progress syncs with ETA based on remaining pages and rolling average page duration.

      • GET /api/v10/sync_dashboard/logs – filterable view of content_provider_sync_logs by provider, status, sync type.

      • GET /api/v10/sync_dashboard/queue – live Sidekiq queue/retry/dead job counts.

      • POST /api/v10/sync_dashboard/enqueue – on‑demand triggering of a sync for a given provider and sync type.

    • All endpoints are authenticated and company‑scoped and are documented in Swagger (swagger_internal.json and HTML docs).

  • PD-12648SDK compatibility documentation:

    • Comprehensive internal documentation of:

      • Feature overview and differences vs legacy FuseTube integration.

      • End‑to‑end flows: scheduled sync, on‑demand rake tasks, and per‑user completion checks.

      • Job hierarchy, fan‑out model, cursor persistence, idempotency, and fault tolerance.

      • Data model, tables and side‑effects.

      • Logging, metrics and operational behaviours (scheduling, retries, unsupported provider handling).

      • Environment & configuration requirements.

      • Guidance for future changes (adding new sync types, extending logic safely).

  • PD-12647Test coverage:

    • Full unit and integration tests for:

      • All sync services and jobs.

      • Sync dashboard endpoints.

      • End‑to‑end pipeline against a real test DB including regressions:

        • No RecordNotUnique on concurrent workers for the same content row.

        • No redundant downstream jobs on re‑sync of known completions.

        • SyncUserCompletionsJob correctly finds completions beyond the first page.

    • Target state: ~84 examples, 0 failures, 0 RuboCop offences.

Per‑user completion checks & Dashboard URL

  • PD-12645Per‑user on‑demand completion check:

    • ExternalContentProgressJob now triggers SyncUserCompletionsJob for content backed by ExternalContent.

    • SyncUserCompletionsJob:

      • Paginates through all list_user_assignments pages until the matching assignment is found or exhausted.

      • Writes ExternalContentCompleteness only when it confirms a completed assignment.

      • No‑ops if the user has no ExternalMembership or the integration is disabled.

  • PD-12766Dashboard URL update:

    • Standardises the sync dashboard URL to /smartconnectors for better discoverability and consistency.

Content metadata & thumbnails via Stack One

  • PD-12802Metadata sync (tags, description, thumbnail):

    • Introduces ContentTagSync:

      • Syncs tags, categories and skills from Stack One into shared tags/taggings tables (without acts-as-taggable-on).

      • Syncs description and thumbnail back into the mirror Content record.

      • Maintains ExternalContent.languages as a clean JSON array of locale codes.

    • Tags are the union of tags + categories + skills.

    • Language sync into contents itself is explicitly out of scope here.

  • PD-12769Thumbnail asset ingestion:

    • New service FuseliteStackOne::ContentThumbnailSync:

      • Downloads Stack One thumbnails and uploads them to S3:

        • uploads/{company_id}/stack_one/{sha256_of_url}.{ext}.

      • Creates or reuses Asset::ContentAsset rows with correct asset_uid and asset_data.

      • Populates contents.thumbnail_id for Stack One content.

    • Behaviour:

      • Idempotent on re‑sync (no duplicate assets).

      • Skips missing URLs without creating assets.

      • Logs and swallows errors so a failed image download doesn’t abort syncs.

Stack One SDK upgrade & cursor robustness

  • PD-12870SDK upgrade and Faraday removal:

    • Bumps the stackone_client gem to a version that fixes type issues (e.g. source_value: 0).

    • Replaces raw Faraday bypass for:

      • list_assignments

      • list_user_assignments

    • These now use official SDK methods:

      • @client.lms.list_assignments

      • @client.lms.list_user_assignments

    • Cleans up:

      • RawResponse struct.

      • lms_faraday helper.

    • Ensures ResponseParser is consistent with SDK response shapes.

    • Explicitly documents the omission of updated_after in assignment calls where intentional.


Improvements to Existing Features

1. Learning Plan Navigation & Top Bar

Cross‑experience top bar navigation

  • PD-12499 – Adds the new top bar navigation to monolith SCORM pages:

    • Visible when user navigates from the Learning Plan Overview OR via Next/Previous in the top bar.

  • PD-12275 – Extends top bar navigation to Events & Occurrences:

    • Renders above Event and Occurrence content when reached via overview or Next/Previous.

  • PD-12704 – Fixes top bar previous/next buttons not working:

    • Restores expected forward/backwards navigation through learning plan items.

  • PD-12786 – Fixes top bar navigation loop with duplicate contents:

    • Resolves an issue where duplicate contents in a learning plan caused an infinite navigation loop.

Start/Continue behaviour in learning plans

  • PD-11457Backend: “Next Item” field on GET /learning/plans/{id}:

    • Adds nextContentItemId + type:

      • Returns next uncompleted item in sequence.

      • Returns first item when all items are complete.

      • Supports:

        • Event

        • Event Occurrence

        • SCORM (including within topics)

        • Standard content

        • Formal Assessment

        • External content

      • Excludes topics and any non‑content assessment types.

    • Ensures reset plans navigate to the first item.

  • PD-11458Frontend: Start/Continue uses “Next Item”:

    • “Get started” and “Continue” buttons now:

      • Navigate to nextContentItemId for not‑started or in‑progress plans.

      • Navigate to the first item when everything is completed.

    • Maintains existing button UI and styles with improved correctness.

2. UA2 / GoodData analytics integration

  • PD-12285Navigation to UA2 from community admin:

    • Community admins can access UA2 directly from the community admin settings > Analytics.

    • Backend ensures the correct UA2 data is fetched and rendered.

  • PD-12074Automatic GoodData user provisioning:

    • Community admins accessing analytics from community settings will:

      • Be auto‑created in GoodData Cloud if they don’t exist, with community‑level workspace access.

      • Reuse existing permissions if already present.

    • Site admins see the same UI behaviour as community admins, aligning expectations.

3. Video Transcript & Transcription UX

  • PD-12466Video transcript chapters:

    • If an author defines “jump to” positions:

      • Chapter headings are displayed at the top of the transcript tab.

      • Clicking a chapter smoothly scrolls the transcript to the corresponding section.

      • Edits to chapter markers are reflected live in the transcript tab.

  • PD-12794Transcription copy message localisation:

    • “Transcript copied to clipboard” now appears in the user’s selected language (e.g. German, French, Spanish), not only in English.

  • PD-12776Article image sizing:

    • Image resize settings from the editor (e.g. 50% width) now persist to the published article.

    • Size is stable across save, publish, and reload; images no longer default back to 100%.

  • PD-12633New Content: clickable links spacing:

    • Fixes an issue where multiple links with spaces in the editor published without spaces.

    • Links now maintain their intended spacing and formatting on publish.


Bug Fixes

1. Content consumption & navigation issues

  • PD-12803New Content Pages: article links infinite reload loop:

    • Fixes a bug where clicking links inside new content articles caused the page to reload in an infinite loop.

    • Normal left‑click navigation now works; right‑click “Open in new tab” remains supported.

  • PD-12701GoodData Workspaces setup documentation:

    • Documents the manual process for creating GoodData workspaces via API, including:

      • Workspace ID and naming strategy.

      • User group naming and permissions.

    • Reduces ambiguity and error risk for analytics workspace provisioning.

2. Localisation and language correctness

  • PD-12713German “you” translation fix:

    • Changes the side menu translation of “you” from “Sie” to “Ich” on <https://vat.fuseuniversal.com/.>

    • Addresses a key localisation issue for an at‑risk client.

3. Search & tagging

  • PD-12520Deleted tags visible in search filters:

    • Resolves an issue where tags mass‑deleted by DevOps were still appearing in search filters for PMI.

    • Search now respects tag deletions so removed tags no longer appear as filter options.