Advanced Aircrew Academy → Docebo Migration · Back to Project Tracker
Symptom: Video players and images are rendered so small that text within them is illegible. Krista: "The visuals are far too small to be useful to the learner."
The player renders images/videos in a two-column layout (text left, media right). The media column is too narrow for content with fine detail. Need to either increase the media column width, add a click-to-enlarge lightbox for images, or make videos expand on play. Compare to Ascent where media takes up more horizontal space.
src/player/build-player.js — CSS layout for .page-content, image/video sizing
Symptom: Timer shows 167:33 remaining instead of 2:47:33 remaining. Confusing for long courses.
Format the timer display to show H:MM:SS when remaining time exceeds 60 minutes, and M:SS when under 60 minutes.
src/player/build-player.js — timer rendering JS, look for formatTime or the timer countdown function
Symptom: Attachment links are placed at the very bottom of the page content. On pages with lots of text, learners have to scroll past all content to find them. Easy to miss entirely.
Move the ATTACHMENTS section to the top of the page, or at least above the main text body. The attachments are reference docs that learners may want to open alongside the page content.
src/player/build-player.js — page rendering, look for attachments or refs section placement
Symptom: Clicking hyperlinks inside the Module Reference Card attachment triggers a browser "Open Web Page" confirmation dialog. This popup doesn't exist in the original Ascent version.
Two factors: (1) Old builds used HTML wrapper pages for references instead of direct PDF links. The QA-011 fix resolved this — rebuilt courses now link directly to .pdf files on S3. (2) The SCORM launcher iframe sandbox attribute lacked allow-popups-to-escape-sandbox, causing browsers to show confirmation dialogs when target="_blank" links opened from within the sandboxed iframe. Fixed by adding the flag to src/scorm/launcher.js.
Fixed in two parts: direct PDF links (QA-011 rebuild) and allow-popups-to-escape-sandbox added to launcher iframe sandbox attribute. Courses must be rebuilt and republished to pick up both fixes.
src/scorm/launcher.js — added allow-popups-to-escape-sandbox to iframe sandbox attribute
Symptom: The purple header bar styling shifts slightly between pages. Some pages show the header with bold italic text, others show it differently. Page 82 shows "Climb Performance" which appears to have "Performance" bolded differently.
The font-weight/style may be inheriting differently based on whether the source JSON has formatting tags in the title. Normalize header rendering to strip inline formatting from titles.
src/player/build-player.js — page title/header rendering
Symptom: When clicking an attachment link, a blank white page with an Adobe PDF icon briefly appears before the actual PDF loads. Happens on every attachment click. Not a blocker but looks unpolished.
The old pipeline uploaded reference files as HTML wrapper pages that contained embedded links to the actual PDF. Clicking an attachment opened the HTML wrapper first (blank flash with PDF icon), which then loaded the PDF. The QA-011 fix changed the pipeline to upload actual PDF files directly to S3 and set ref.url to the direct PDF URL. The deleteStaleRefFiles() function cleans up any leftover .html wrapper files from previous builds.
Fixed by the QA-011 rebuild. Attachment links now point directly to .pdf files on S3, so the browser opens the PDF natively in a new tab with no intermediate HTML page. Courses must be rebuilt to pick up the fix.
src/player/media-resolver.js — uploadReferenceToS3() and deleteStaleRefFiles()
Symptom: Shows "Video unavailable / ID: unknown" placeholder instead of a video. The video ID could not be resolved during the build.
Check the source JSON for page 134 of module 148275 (network 791). The video reference is likely missing a media ID or the media mapping doesn't have an entry for this video. May need to look up the video in Ascent and find its S3 path manually.
src/player/media-resolver.js — video ID lookup. Source data at s3://aaa-courses/root/json_data/module_148275.zip
Symptom: Page has a complex layout with a table/form (runway analysis data) plus a video. In Ascent, the table and video sit side-by-side in a compact layout. In our player, they're stacked vertically, making the page much taller and the relationship between elements less clear.
This page likely has structured HTML in the source JSON (table + media in a specific layout). The player may be stripping the original HTML structure and re-rendering elements linearly. Need to preserve the original layout for pages with embedded tables.
src/player/build-player.js — page content rendering, HTML passthrough vs restructuring
Symptom: Images in the two-column layout are clipped on the right edge. On page 33, the "ORM Process Flow" circular diagram is cut off. On page 42, the "Identifying Hazards" graphic is similarly truncated.
The image container has overflow: hidden or a fixed width that's narrower than the image's natural size. Images need to scale down to fit the available column width while preserving aspect ratio. Use max-width: 100%; height: auto; on images within the media column.
src/player/build-player.js — CSS for images in content area
Symptom: When selecting an incorrect answer on a review question, the feedback area shows a colored bar (yellow/orange) but no feedback text. Correct-answer feedback displays fine.
The feedback for incorrect answers (distractors) likely exists in the source JSON but isn't being rendered. The yellow bar is visible (container exists) but the text content is missing. Check how correct vs incorrect feedback is handled differently in the selftest renderer.
src/player/build-player.js — review question / selftest rendering, look for feedback, distractor, or incorrect handling
Symptom: Clicking an attachment opens a new tab showing the S3 URL but the page is blank with two broken image icons. Confirmed on both Chrome (Krista) and Safari/Mac (Knoll). Affects multiple courses: courses/297/89489/refs/ and courses/171/96865/refs/. Knoll notes all other course functionality works fine.
The reference HTML wrapper file on S3 contains image references that point to URLs that don't exist or weren't uploaded. Check the refs/ directory for this course on S3 and verify the HTML file's image/content references resolve correctly.
src/player/build-player.js — reference/attachment generation. src/player/media-resolver.js — URL resolution for ref content
Symptom: AccessDenied S3 XML error when launching any course. Blocked all course access for Knoll.
S3 bucket policy only allowed *.docebosaas.com referers. Docebo's SCORM launcher runs on CloudFront (d36spl5w3z9i0o.cloudfront.net), and some browsers send that as the Referer header through nested cross-origin iframes instead of stripping it.
Added https://d36spl5w3z9i0o.cloudfront.net/* to the AllowDoceboReferer bucket policy statement. Nick applied the change Mar 19.
Symptom: Exams showed blank questions. Questions were referencing bank IDs instead of displaying actual text.
Questions now resolve from the embedded bank data. Each exam attempt draws a random question per slot from the pool, matching original Ascent behavior.
Symptom: Learners could click Next without answering review/selftest questions.
Forward navigation now blocked until the learner selects an answer. Orange message appears: "Please answer the review question before continuing."
Symptom: Some video pages showed blank blocks (failed conversion), others showed the same video twice.
Video conversion redesigned. Blank blocks replaced with working player or "Video unavailable" placeholder. No more duplicates.
Symptom: Courses with minimum required time had no timer enforced.
Countdown timer displays in toolbar. Accumulates across sessions. Completion gated until minimum time met.
Symptom: Media URLs used presigned S3 URLs with expiration timestamps. After expiry, images and files returned 403 errors.
Media resolver now generates direct S3 URLs (no presigned params). Runtime URL fixer strips any remaining ?X-Amz-* params. S3 bucket policy with referer restrictions controls access instead. All 611 courses patched.
Symptom: Clicking an image opened a fullscreen lightbox, but the only visible close button was Docebo's course exit X. Users accidentally exited courses.
Lightbox now has a visible close button and hint text. Clicking the image no longer closes the lightbox.
Symptom: Completion modal's Close/OK button called SCORM Terminate immediately, which could interfere with Docebo recording the final status.
OK button now dismisses the modal only. SCORM session terminates naturally on window close, giving Docebo time to process the final commit.
Summary: When creating or populating Docebo course shells, several properties must be set beyond just the SCORM content: description, image_id (thumbnail), additional_fields (customization, part, duration type), valid_time (365 days), duration_minutes, can_subscribe (0), category, and assigned_certificate.
Krista attached Master Course Docebo Codes.xlsx containing description, thumbnail, and duration for all courses. Downloaded to /tmp/krista-feedback/Master_Course_Docebo_Codes.xlsx and should be copied to reference/.
Update src/deploy/docebo-publish.js to set these properties when creating/populating course shells. For existing Ascent shells (unpublished placeholders), all properties need to be set before they can go live. Parse the Master Course spreadsheet to get per-course metadata.
Symptom: Krista notes images are enlarged (QA-001 fix is working) but "still needs a little massaging." Page 9 has a "more dramatic" issue. Page 56 has odd spacing with the image. Images may be too large now or have incorrect aspect ratio/positioning after the column width change.
Review the image sizing CSS changes from QA-001 fix. The 45/55 column split and removal of fixed max-widths may have overcorrected on some pages. May need to add object-fit: contain or cap images at a reasonable max size while still being larger than before. Check pages 7, 9, 56 of ETOPS course.
src/player/build-player.js — CSS image sizing rules
Symptom: Page 27 of ETOPS course shows no text content. The page loads but the body is empty or content failed to render.
Source data faithfully reproduced. Page 27 ("Airline Approval", id 24447563) in module 146805 has sparse content in the original Ascent source: a blue header bar with "Approval" text and a two-column table where the left cell contains only <p><br></p> (empty) and the right cell has an image (iStock_000015610873_Medium.jpg, 14KB, HTTP 200). The html_body, body, and single revision all match — this is how the page was authored in Ascent. No content was lost in the conversion pipeline. The page renders correctly: header + image, no body text. Surrounding pages (24–26: "ETOPS Approval", "Manufacturer Approval 1 & 2") have full text. This appears to be an intentionally minimal page in the original curriculum.
data/modules/146805/pages/146805_24447563.json — source page data
Symptom: Image missing on page 76 of ETOPS course. Either the image URL failed to resolve or the media file wasn't uploaded to S3.
URL double-encoding bug in media resolver. Page 76 ("Fuel Scenarios", id 24447612) has image pilots%2002%20mask%20ng.jpg. The original filename in Ascent uses URL-encoded spaces (%20). The media resolver preserved these literally in the S3 key. The image IS on S3 (42KB), but the browser decodes %20 to spaces when fetching, which doesn't match the S3 key — resulting in HTTP 403. Affects 567 media files across 129 courses.
decodeURIComponent() so keys contain actual characters (spaces). uploadMediaToS3() and uploadReferenceToS3() now properly encode URL path segments with encodeURIComponent().fixEncodedMediaUrls() that uses onerror handlers to re-encode broken image/video URLs at runtime. This fixes already-deployed courses without rebuilding.To fully fix: Redeploy shared player (node scripts/deploy-shared-player.js) for immediate client-side fix on all existing courses. Rebuild affected courses for permanent server-side fix.
src/player/media-resolver.js — S3 key encoding fix
src/player/build-player.js — client-side URL fixer
Symptom: Every attachment clicked throughout the entire Runway Incursion course is not displaying correctly. Showed blank HTML page with broken images.
The QA-011 fix worked correctly. All 61 reference PDFs were downloaded and uploaded to S3 as .pdf files. The rebuilt index.html links to the .pdf versions. However, 42 stale .html login page files remain because the IAM user lacks s3:DeleteObject permission. Krista was seeing a browser-cached copy of the old index.html that linked to the stale .html refs. Added Cache-Control: no-cache to index.html uploads to prevent this.
Ask Nick to add s3:DeleteObject to IAM policy for external-runpoint-warpspeed. Then run scripts/fix-stale-refs.js to clean up ~5,107 stale .html files across all networks.
src/player/media-resolver.js — reference file resolution
Symptom: Various spacing/indent issues: a note on page 24 has incorrect indentation, page 143 has spacing issues on an exam question with an image, and page 56 of ETOPS has odd spacing with an image. These may be related to the CSS changes from QA-001/009 or may be pre-existing layout issues.
Review the specific pages and compare to Ascent. Check if inline styles from the source HTML are conflicting with the player CSS. May need targeted CSS fixes for notes, exam questions with images, and image-text flow.
src/player/build-player.js — CSS for notes, exam questions, image spacing
Symptom: Image on page 12 of Merck MEL course appears left-justified when it should be centered. The source HTML likely has text-align: center or margin: auto styling that the player CSS is overriding.
Check if the player CSS strips or overrides inline centering styles on images. The display: block; margin: auto; pattern may be getting overridden by the image sizing CSS rules. This is a pipeline-level CSS fix in the shared player.
src/player/build-player.js — CSS for image alignment in content area
Symptom: Page 43 of Merck MEL has non-standard layout with spacing issues. Krista flagged this as "probably a total edge case." May have a unique HTML structure in the source data that the player doesn't handle well.
Low priority. Investigate the source HTML for page 43 to see if it uses an unusual layout pattern. Fix in shared player CSS if a general rule covers it, otherwise note as a known limitation for non-standard pages.
src/player/build-player.js — CSS for edge case layouts
Symptom: Course navigation panel is open (learners can skip ahead freely) and review questions can be skipped without answering. Both should be gated/locked per Alvin.
Source data has navigation_lock: 0 and course_navigation: 0. This is a master module (101514). The master may have nav lock disabled while customer-specific variants (like network 90's copy) have it enabled in Ascent. The pipeline reads navigation_lock from the module JSON directly. Need to check if per-network variants override this setting, or if this should always default to locked for production courses.
Fixed: courseData.navigationLock = true injected into all 611 course HTML files on S3 via patcher + added to shared player HTML template for future builds. Browser-verified in Docebo sandbox: 95/96 sidebar items locked, review question on page 12 blocks Next (opacity 0.4, pointer-events none, gate message visible), clicking Next without answering does not advance.
Current behavior: learner must answer a review question to proceed, but does not need to answer correctly. Is this the intended behavior, or should learners be required to select the correct answer before moving on?
src/player/build-player.js:1284 — courseData.navigationLock = true in shared player HTML template
scripts/patch-existing-content.js — injects courseData.navigationLock = true into existing course HTML
Symptom: Table on page 9 looks weird. Text column is extremely narrow (5.7% width from inline style) while image column takes 94%.
Course was built Mar 19 with full inline CSS/JS. The !important fix was deployed to the shared player Mar 20, but inline CSS loaded in the same document overrode the external stylesheet. The shared player CSS was effectively dead code for all 609 pre-built courses.
Removed inline CSS/JS from all courses. Pipeline now uses generateSharedPlayerHtml() (thin shell with external CSS/JS refs). Ran patch-existing-content.js to rewrite all 609 sandbox courses on S3. The shared player's !important rules now correctly override inline style attributes on table cells. Verified: computed widths show 418px/418px (50/50 split) despite inline style="width: 5.6895%" still present in courseData HTML.
src/player/build-player.js:1402 — switched to generateIndexHtml(courseData, { sharedPlayer: true })
Symptom: Clicking reference document attachment buttons opens a white page with Ascent login markup instead of the actual PDF.
Early pipeline runs failed to download reference PDFs from Ascent (auth expired). The downloadHashFile() function received Ascent login pages (3,869 bytes of HTML) and uploaded them as .html files. The courseData reference URLs were set to these .html keys. Later runs uploaded the correct .pdf files alongside, but the courseData still pointed to .html. 157 stale .html files across all courses, 22 courses with .html ref URLs in courseData.
Updated patch-existing-content.js to detect and rewrite /refs/*.html URLs to /refs/*.pdf in courseData. Ran patcher — 22 courses fixed, 0 failures. The stale .html files remain on S3 (no DeleteObject permission) but are no longer linked.
scripts/patch-existing-content.js — added hasStaleRefUrls check + .html → .pdf rewrite
Symptom: Page 57 “Safety Assurance” is completely blank. The page contains only a title image, which fails to load (403).
The media resolver uploaded files with URL-encoded characters literally in the S3 key (e.g. safetymgmtsysSafety%2520Assurance.png instead of safetymgmtsysSafety%20Assurance.png). When the browser requests the URL with %20, S3 decodes it to a space and looks for a key with a space — which doesn’t exist. 555 double-encoded files found across all courses.
Wrote a scan-and-copy script that found all 555 double-encoded S3 keys and created correctly-decoded copies. 578 fixed, 0 failures. The decodeURIComponent fix in media-resolver.js:515 prevents this for future builds.
S3 bucket aaa-courses — 578 files copied to correctly-decoded keys
Symptom: Alvin reports being kicked out of a course partway through, then it resumes at a point he had already passed.
Browser-tested AAA-791-148275 in Docebo sandbox. Course shows as completed (03/18/2026). SCORM completion signaling is working correctly. The “kicked out” behavior is a Docebo session management issue, not our player code. Docebo may terminate SCORM sessions due to timeouts, concurrent session limits, or platform-level session handling.
Symptom: After using Docebo’s “Archive and Re-Enroll” feature, the course sometimes resumes where the learner left off instead of starting from the beginning. Behavior is inconsistent across courses.
Browser-tested “Retake the course” on AAA-791-148275. Course started on page 4 instead of page 1, confirming the SCORM bookmark (cmi.location) was not cleared by Docebo on re-enrollment. This is Docebo platform behavior: when it creates a new enrollment, it doesn’t always clear the SCORM suspend data from the previous attempt. Inconsistency matches Alvin’s description (works sometimes, not others). This is a Docebo-side issue, not our SCORM player.