{"id":309,"date":"2026-04-15T16:19:00","date_gmt":"2026-04-15T16:19:00","guid":{"rendered":"https:\/\/medlearn.imperial.ac.uk\/innovation\/projects\/canvas-migration-bot\/"},"modified":"2026-04-15T16:31:51","modified_gmt":"2026-04-15T16:31:51","slug":"canvas-migration-bot","status":"publish","type":"page","link":"https:\/\/medlearn.imperial.ac.uk\/innovation\/projects\/canvas-migration-bot\/","title":{"rendered":"Canvas Migration Bot"},"content":{"rendered":"\n<div style=\"background:#001629;\">\n  <svg viewBox=\"0 0 1400 460\" style=\"width:100%;display:block;\">\n    <defs>\n      <linearGradient id=\"bg-grad-cmb\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n        <stop offset=\"0%\" stop-color=\"#001629\"\/><stop offset=\"100%\" stop-color=\"#00263D\"\/>\n      <\/linearGradient>\n      <radialGradient id=\"glow-cmb\" cx=\"75%\" cy=\"45%\" r=\"35%\">\n        <stop offset=\"0%\" stop-color=\"#29ABE2\" stop-opacity=\"0.15\"\/><stop offset=\"100%\" stop-color=\"#29ABE2\" stop-opacity=\"0\"\/>\n      <\/radialGradient>\n    <\/defs>\n    <rect width=\"1400\" height=\"460\" fill=\"url(#bg-grad-cmb)\"\/>\n    <rect width=\"1400\" height=\"460\" fill=\"url(#glow-cmb)\"\/>\n    <line x1=\"800\" y1=\"150\" x2=\"950\" y2=\"220\" stroke=\"#29ABE2\" stroke-width=\"1\" stroke-opacity=\"0.25\"\/>\n    <line x1=\"950\" y1=\"220\" x2=\"1100\" y2=\"170\" stroke=\"#29ABE2\" stroke-width=\"1\" stroke-opacity=\"0.25\"\/>\n    <line x1=\"950\" y1=\"220\" x2=\"1050\" y2=\"320\" stroke=\"#29ABE2\" stroke-width=\"1\" stroke-opacity=\"0.2\"\/>\n    <line x1=\"800\" y1=\"150\" x2=\"700\" y2=\"280\" stroke=\"#29ABE2\" stroke-width=\"1\" stroke-opacity=\"0.2\"\/>\n    <line x1=\"700\" y1=\"280\" x2=\"860\" y2=\"360\" stroke=\"#29ABE2\" stroke-width=\"1\" stroke-opacity=\"0.18\"\/>\n    <line x1=\"1100\" y1=\"170\" x2=\"1200\" y2=\"260\" stroke=\"#29ABE2\" stroke-width=\"1\" stroke-opacity=\"0.2\"\/>\n    <line x1=\"1050\" y1=\"320\" x2=\"1200\" y2=\"260\" stroke=\"#29ABE2\" stroke-width=\"1\" stroke-opacity=\"0.18\"\/>\n    <line x1=\"860\" y1=\"360\" x2=\"1050\" y2=\"320\" stroke=\"#29ABE2\" stroke-width=\"1\" stroke-opacity=\"0.15\"\/>\n    <line x1=\"700\" y1=\"130\" x2=\"800\" y2=\"150\" stroke=\"#29ABE2\" stroke-width=\"1\" stroke-opacity=\"0.18\"\/>\n    <line x1=\"1140\" y1=\"95\" x2=\"1100\" y2=\"170\" stroke=\"#29ABE2\" stroke-width=\"1\" stroke-opacity=\"0.15\"\/>\n    <line x1=\"1300\" y1=\"145\" x2=\"1200\" y2=\"260\" stroke=\"#29ABE2\" stroke-width=\"1\" stroke-opacity=\"0.15\"\/>\n    <rect x=\"870\" y=\"58\" width=\"165\" height=\"40\" rx=\"8\" fill=\"#29ABE2\" fill-opacity=\"0.07\" stroke=\"#29ABE2\" stroke-width=\"0.8\" stroke-opacity=\"0.4\"\/>\n    <rect x=\"882\" y=\"69\" width=\"62\" height=\"6\" rx=\"3\" fill=\"#29ABE2\" fill-opacity=\"0.3\"\/>\n    <rect x=\"882\" y=\"82\" width=\"100\" height=\"5\" rx=\"2.5\" fill=\"#29ABE2\" fill-opacity=\"0.18\"\/>\n    <rect x=\"900\" y=\"116\" width=\"145\" height=\"34\" rx=\"8\" fill=\"#29ABE2\" fill-opacity=\"0.1\" stroke=\"#29ABE2\" stroke-width=\"0.8\" stroke-opacity=\"0.35\"\/>\n    <rect x=\"912\" y=\"126\" width=\"80\" height=\"5\" rx=\"2.5\" fill=\"#29ABE2\" fill-opacity=\"0.25\"\/>\n    <rect x=\"912\" y=\"137\" width=\"52\" height=\"5\" rx=\"2.5\" fill=\"#29ABE2\" fill-opacity=\"0.15\"\/>\n    <circle cx=\"950\" cy=\"220\" r=\"18\" fill=\"#29ABE2\" fill-opacity=\"0.14\" stroke=\"#29ABE2\" stroke-width=\"1.5\" stroke-opacity=\"0.6\"\/>\n    <circle cx=\"950\" cy=\"220\" r=\"8\" fill=\"#29ABE2\" fill-opacity=\"0.55\"\/>\n    <circle cx=\"800\" cy=\"150\" r=\"12\" fill=\"#29ABE2\" fill-opacity=\"0.1\" stroke=\"#29ABE2\" stroke-width=\"1.2\" stroke-opacity=\"0.5\"\/>\n    <circle cx=\"800\" cy=\"150\" r=\"5\" fill=\"#29ABE2\" fill-opacity=\"0.42\"\/>\n    <circle cx=\"1100\" cy=\"170\" r=\"14\" fill=\"#29ABE2\" fill-opacity=\"0.1\" stroke=\"#29ABE2\" stroke-width=\"1.2\" stroke-opacity=\"0.5\"\/>\n    <circle cx=\"1100\" cy=\"170\" r=\"6\" fill=\"#29ABE2\" fill-opacity=\"0.45\"\/>\n    <circle cx=\"1050\" cy=\"320\" r=\"11\" fill=\"#29ABE2\" fill-opacity=\"0.1\" stroke=\"#29ABE2\" stroke-width=\"1\" stroke-opacity=\"0.4\"\/>\n    <circle cx=\"1050\" cy=\"320\" r=\"5\" fill=\"#29ABE2\" fill-opacity=\"0.35\"\/>\n    <circle cx=\"700\" cy=\"280\" r=\"10\" fill=\"#29ABE2\" fill-opacity=\"0.09\" stroke=\"#29ABE2\" stroke-width=\"1\" stroke-opacity=\"0.35\"\/>\n    <circle cx=\"700\" cy=\"280\" r=\"4\" fill=\"#29ABE2\" fill-opacity=\"0.3\"\/>\n    <circle cx=\"860\" cy=\"360\" r=\"9\" fill=\"#29ABE2\" fill-opacity=\"0.08\" stroke=\"#29ABE2\" stroke-width=\"1\" stroke-opacity=\"0.3\"\/>\n    <circle cx=\"860\" cy=\"360\" r=\"4\" fill=\"#29ABE2\" fill-opacity=\"0.25\"\/>\n    <circle cx=\"1200\" cy=\"260\" r=\"13\" fill=\"#29ABE2\" fill-opacity=\"0.1\" stroke=\"#29ABE2\" stroke-width=\"1.2\" stroke-opacity=\"0.45\"\/>\n    <circle cx=\"1200\" cy=\"260\" r=\"6\" fill=\"#29ABE2\" fill-opacity=\"0.4\"\/>\n    <circle cx=\"700\" cy=\"130\" r=\"6\" fill=\"#29ABE2\" fill-opacity=\"0.22\" stroke=\"#29ABE2\" stroke-width=\"1\" stroke-opacity=\"0.28\"\/>\n    <circle cx=\"1140\" cy=\"95\" r=\"7\" fill=\"#29ABE2\" fill-opacity=\"0.18\" stroke=\"#29ABE2\" stroke-width=\"0.8\" stroke-opacity=\"0.28\"\/>\n    <circle cx=\"1300\" cy=\"145\" r=\"8\" fill=\"#29ABE2\" fill-opacity=\"0.14\" stroke=\"#29ABE2\" stroke-width=\"0.8\" stroke-opacity=\"0.22\"\/>\n    <rect x=\"0\" y=\"0\" width=\"4\" height=\"460\" fill=\"#29ABE2\" opacity=\"0.85\"\/>\n    <text x=\"56\" y=\"158\" font-size=\"13\" font-weight=\"700\" letter-spacing=\"3\" fill=\"#29ABE2\" font-family=\"Arial, sans-serif\">CANVAS LMS \u00b7 AI PILOT<\/text>\n    <text x=\"56\" y=\"232\" font-size=\"58\" font-weight=\"800\" fill=\"#FFFFFF\" font-family=\"Arial, sans-serif\">Canvas<\/text>\n    <text x=\"56\" y=\"300\" font-size=\"52\" font-weight=\"800\" fill=\"#29ABE2\" font-family=\"Arial, sans-serif\">Migration Bot<\/text>\n    <text x=\"56\" y=\"348\" font-size=\"17\" fill=\"rgba(255,255,255,0.72)\" font-family=\"Arial, sans-serif\">AI-powered assistant for Imperial\u2019s Blackboard \u2192 Canvas transition<\/text>\n    <polyline points=\"0,390 100,390 130,372 150,408 170,362 190,418 210,390 350,390 380,382 400,398 420,377 440,404 460,390 620,390 680,388 740,390 800,390 950,390 1080,384 1100,396 1120,387 1140,393 1160,390 1400,390\" fill=\"none\" stroke=\"#29ABE2\" stroke-width=\"1.8\" stroke-opacity=\"0.18\"\/>\n  <\/svg>\n<\/div>\n\n\n\n<style>\n  .cmb h2{color:#002147;border-bottom:3px solid #29ABE2;padding-bottom:8px;margin-top:40px;}\n  .cmb h3{color:#003E74;margin-top:28px;}\n  .cmb table{width:100%;border-collapse:collapse;margin:16px 0 24px;font-size:14px;}\n  .cmb th{background:#002147;color:#fff;padding:10px 14px;text-align:left;}\n  .cmb td{padding:10px 14px;border-bottom:1px solid #E0E6EF;vertical-align:top;}\n  .cmb tr:last-child td{border-bottom:none;}\n  .cmb tr:nth-child(even) td{background:#F5F8FC;}\n<\/style>\n<div class=\"cmb\" style=\"max-width:860px;margin:0 auto;padding:32px 24px 60px;font-family:Arial,sans-serif;color:#222;line-height:1.7;\">\n\n  <p style=\"font-size:17px;color:#444;line-height:1.8;margin-bottom:32px;\">Imperial\u2019s Faculty of Medicine is moving from Blackboard to Canvas LMS. The process spans hundreds of courses and affects staff at every level, each with their own questions about what changes, when, and how. The Canvas Migration Bot is an AI assistant embedded on MedLearn that answers those questions in real time, drawing on a curated knowledge base built from Canvas documentation and DEO guidance.<\/p>\n\n  <h2>At a Glance<\/h2>\n  <table>\n    <tr><th>Field<\/th><th>Detail<\/th><\/tr>\n    <tr><td>Year<\/td><td>2025\u20132026<\/td><\/tr>\n    <tr><td>Audience<\/td><td>FoM staff, academics, and learning technologists navigating the Blackboard to Canvas migration<\/td><\/tr>\n    <tr><td>Access<\/td><td>Imperial SSO required, embedded on MedLearn (\/innovation\/canvas-migration-bot\/)<\/td><\/tr>\n    <tr><td>Backend<\/td><td>Supabase (PostgreSQL + full-text search), Vercel serverless API, Anthropic Claude AI<\/td><\/tr>\n    <tr><td>Knowledge base<\/td><td>337+ document chunks covering Canvas guides, DEO communications, student updates, and course decision guidance<\/td><\/tr>\n    <tr><td>Status<\/td><td>Live Pilot, DEO team access opened April 2026<\/td><\/tr>\n  <\/table>\n\n  <h2>The Challenge<\/h2>\n  <p>Migrating a large institutional VLE generates a significant volume of repetitive support queries: Which courses are moving? When is the deadline? How do I find my course decision? How do I set up gradebook in Canvas? The DEO team was fielding these individually while managing the technical migration across hundreds of courses. The bot was built to handle the long tail of common questions, freeing the team to focus on the course-specific work that requires human expertise.<\/p>\n\n  <h2>The Technology<\/h2>\n  <p>The bot is a custom retrieval-augmented generation (RAG) system, built without off-the-shelf chatbot platforms or plugin infrastructure:<\/p>\n  <table>\n    <tr><th>Component<\/th><th>Technology<\/th><th>Role<\/th><\/tr>\n    <tr><td>Knowledge base<\/td><td>Supabase PostgreSQL + full-text search (tsvector)<\/td><td>Stores 337+ chunked documents covering Canvas guides, DEO communications, student updates, and course decision guidance<\/td><\/tr>\n    <tr><td>API<\/td><td>Vercel serverless function (Node.js)<\/td><td>Accepts a question, retrieves relevant chunks via full-text search, calls Claude AI, returns a grounded answer<\/td><\/tr>\n    <tr><td>Frontend<\/td><td>Vanilla JavaScript in a WordPress custom HTML block<\/td><td>Chat interface embedded directly on MedLearn, with no plugin required<\/td><\/tr>\n    <tr><td>Auth gate<\/td><td>WordPress REST API session check<\/td><td>Confirms Imperial login before showing the bot, using the same pattern as the MedLearn headset booking page<\/td><\/tr>\n    <tr><td>Feedback layer<\/td><td>Supabase + thumbs up\/down UI<\/td><td>Captures per-answer ratings and optional comments for quality monitoring<\/td><\/tr>\n    <tr><td>Question logging<\/td><td>Supabase questions_log table<\/td><td>Logs every question with session ID and timestamp, used to identify knowledge gaps and track usage patterns<\/td><\/tr>\n  <\/table>\n\n  <h2>The Knowledge Base<\/h2>\n  <p>The bot\u2019s answers are grounded in a structured, curated knowledge base rather than general web knowledge. Sources include the official Canvas Instructor Guide, DEO migration guidance, the FoM April 2026 student communication, Blackboard course decision process documentation, and DEO contact and escalation information.<\/p>\n  <p>New sources are added as guidance evolves. Content is chunked and stored with full-text search indexing, optimised for retrieval speed without needing vector embeddings or an external embedding API.<\/p>\n\n  <h2>Safety and Access<\/h2>\n  <p>The bot sits behind Imperial\u2019s SSO, so only authenticated Imperial users can access it. It is scoped to migration-specific queries and directs users to named DEO contacts for anything requiring human judgement. No personal information is processed or stored. Question logs capture only the text of the question itself.<\/p>\n\n  <h2>The Team<\/h2>\n  <p>Designed and built by Adrian Cowell (Innovation Lead, Faculty of Medicine) in collaboration with the Digital Education Office, and deployed on MedLearn as part of the FoM\u2019s Blackboard to Canvas transition programme. The DEO team contribute subject-matter expertise and act as named escalation contacts within the bot\u2019s responses.<\/p>\n\n  <h2>Why It Matters<\/h2>\n  <p>Staff confidence during a migration often comes down to simply knowing where to go and what to expect. The bot provides a consistent, always-available point of first contact that doesn\u2019t require waiting for an email response.<\/p>\n  <p>The combination of question logging and thumbs-up\/down feedback also creates a clear picture of where guidance is genuinely unclear, giving the DEO team actionable data to improve the knowledge base as the migration evolves. The migration is a moving target with shifting deadlines and new guidance; the bot is built to keep pace with it.<\/p>\n\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>CANVAS LMS \u00b7 AI PILOT Canvas Migration Bot AI-powered assistant for Imperial\u2019s Blackboard \u2192 Canvas transition Imperial\u2019s Faculty of Medicine is moving from Blackboard to Canvas LMS. The process spans [&hellip;]<\/p>\n","protected":false},"author":16,"featured_media":0,"parent":7,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-309","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/medlearn.imperial.ac.uk\/innovation\/wp-json\/wp\/v2\/pages\/309","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/medlearn.imperial.ac.uk\/innovation\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/medlearn.imperial.ac.uk\/innovation\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/medlearn.imperial.ac.uk\/innovation\/wp-json\/wp\/v2\/users\/16"}],"replies":[{"embeddable":true,"href":"https:\/\/medlearn.imperial.ac.uk\/innovation\/wp-json\/wp\/v2\/comments?post=309"}],"version-history":[{"count":2,"href":"https:\/\/medlearn.imperial.ac.uk\/innovation\/wp-json\/wp\/v2\/pages\/309\/revisions"}],"predecessor-version":[{"id":312,"href":"https:\/\/medlearn.imperial.ac.uk\/innovation\/wp-json\/wp\/v2\/pages\/309\/revisions\/312"}],"up":[{"embeddable":true,"href":"https:\/\/medlearn.imperial.ac.uk\/innovation\/wp-json\/wp\/v2\/pages\/7"}],"wp:attachment":[{"href":"https:\/\/medlearn.imperial.ac.uk\/innovation\/wp-json\/wp\/v2\/media?parent=309"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}