feat: Implement LTI deep linking, live sessions, predictive analytics, and portfolios with associated UI and database migrations.

This commit is contained in:
2026-02-24 09:37:16 -03:00
parent 7f7ea3d70c
commit 04dbe05704
81 changed files with 4119 additions and 249 deletions
@@ -0,0 +1,53 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT \n u.id, \n u.full_name, \n u.email, \n 0.0::float4 as progress,\n (SELECT name FROM cohorts c JOIN user_cohorts uc ON c.id = uc.cohort_id WHERE uc.user_id = u.id LIMIT 1) as cohort_name,\n AVG(g.score)::float4 as average_score\n FROM users u\n JOIN enrollments e ON u.id = e.user_id AND e.course_id = $1\n LEFT JOIN user_grades g ON u.id = g.user_id AND g.course_id = $1\n WHERE e.organization_id = $2\n GROUP BY u.id, u.full_name, u.email\n ORDER BY u.full_name\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "full_name",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "email",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "progress",
"type_info": "Float4"
},
{
"ordinal": 4,
"name": "cohort_name",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "average_score",
"type_info": "Float4"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
false,
null,
null,
null
]
},
"hash": "17f05eb41a9b8c4fd37f1c47495546709658ff09ac8be7ad1c611039e55394da"
}
@@ -0,0 +1,66 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE course_submissions \n SET content = $1, updated_at = NOW() \n WHERE user_id = $2 AND lesson_id = $3\n RETURNING *\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "user_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "course_id",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "lesson_id",
"type_info": "Uuid"
},
{
"ordinal": 4,
"name": "content",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "submitted_at",
"type_info": "Timestamptz"
},
{
"ordinal": 6,
"name": "updated_at",
"type_info": "Timestamptz"
},
{
"ordinal": 7,
"name": "organization_id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Text",
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
false
]
},
"hash": "363c5ded702de620f7d55d9a28564a6cb07ab2123f6733eb9992ef29a0347a3f"
}
@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "SELECT user_id FROM course_submissions WHERE id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "user_id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
false
]
},
"hash": "48092c69f6c0c66fc843d31c65123dfbd6771c450e34d2f330a7cec4cad9e16e"
}
@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "SELECT cohort_id FROM announcement_cohorts WHERE announcement_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "cohort_id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
false
]
},
"hash": "5e0c0dd74a0fcb24eae0b69b46550cdb1fc0520f59ab24095319c844100696a8"
}
@@ -0,0 +1,67 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT s.* \n FROM course_submissions s\n LEFT JOIN peer_reviews pr ON s.id = pr.submission_id\n WHERE s.course_id = $1 \n AND s.lesson_id = $2\n AND s.user_id != $3\n AND s.organization_id = $4\n AND NOT EXISTS (\n SELECT 1 FROM peer_reviews my_pr \n WHERE my_pr.submission_id = s.id AND my_pr.reviewer_id = $3\n )\n GROUP BY s.id\n HAVING COUNT(pr.id) < 2\n ORDER BY s.submitted_at ASC\n LIMIT 1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "user_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "course_id",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "lesson_id",
"type_info": "Uuid"
},
{
"ordinal": 4,
"name": "content",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "submitted_at",
"type_info": "Timestamptz"
},
{
"ordinal": 6,
"name": "updated_at",
"type_info": "Timestamptz"
},
{
"ordinal": 7,
"name": "organization_id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid",
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
false
]
},
"hash": "60ddd0622ba9bdb70c661f9b8f755f4336017efa585e1f93ac848b1fed4835a1"
}
@@ -0,0 +1,35 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT ld.prerequisite_lesson_id, p.title as prereq_title, ld.min_score_percentage\n FROM lesson_dependencies ld\n JOIN lessons p ON ld.prerequisite_lesson_id = p.id\n LEFT JOIN user_grades ug ON ld.prerequisite_lesson_id = ug.lesson_id AND ug.user_id = $2\n LEFT JOIN lesson_interactions li ON ld.prerequisite_lesson_id = li.lesson_id \n AND li.user_id = $2 AND li.event_type = 'complete'\n WHERE ld.lesson_id = $1\n AND (\n (p.is_graded = true AND (ug.score IS NULL OR (ug.score * 100.0) < COALESCE(ld.min_score_percentage, 0.0)))\n OR\n (p.is_graded = false AND li.id IS NULL)\n )\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "prerequisite_lesson_id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "prereq_title",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "min_score_percentage",
"type_info": "Float8"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
true
]
},
"hash": "6744490d98f0f7b1d753e89dfe2cddef4e580c62954847940e5fa0d1ad6a7fcf"
}
@@ -0,0 +1,52 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT ld.* \n FROM lesson_dependencies ld\n JOIN lessons l ON ld.lesson_id = l.id\n JOIN modules m ON l.module_id = m.id\n WHERE m.course_id = $1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "organization_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "lesson_id",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "prerequisite_lesson_id",
"type_info": "Uuid"
},
{
"ordinal": 4,
"name": "min_score_percentage",
"type_info": "Float8"
},
{
"ordinal": 5,
"name": "created_at",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
false,
false,
false,
false,
true,
false
]
},
"hash": "82038007a13b07cdb912619ddefa10faa651a934e8dfb14be29226b85c614cae"
}
@@ -0,0 +1,28 @@
{
"db_name": "PostgreSQL",
"query": "SELECT id, name FROM grading_categories WHERE course_id = $1 ORDER BY name",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "name",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
false,
false
]
},
"hash": "af5539604d4c172890ce3f62de6dbe7952f027d6caf367ed0480b5f16274bd1f"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT id FROM peer_reviews WHERE submission_id = $1 AND reviewer_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": [
false
]
},
"hash": "bba15398004acf73d991751221eba784335db7d899c0601d216fc1703ff49d06"
}
@@ -0,0 +1,65 @@
{
"db_name": "PostgreSQL",
"query": "SELECT * FROM course_submissions WHERE user_id = $1 AND lesson_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "user_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "course_id",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "lesson_id",
"type_info": "Uuid"
},
{
"ordinal": 4,
"name": "content",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "submitted_at",
"type_info": "Timestamptz"
},
{
"ordinal": 6,
"name": "updated_at",
"type_info": "Timestamptz"
},
{
"ordinal": 7,
"name": "organization_id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
false
]
},
"hash": "bd51fbc3e8b3746722d88201f1937ffa3f2718790d55d4b9143bacaa6219173e"
}
@@ -0,0 +1,68 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO peer_reviews (submission_id, reviewer_id, score, feedback, organization_id)\n VALUES ($1, $2, $3, $4, $5)\n RETURNING *\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "submission_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "reviewer_id",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "score",
"type_info": "Int4"
},
{
"ordinal": 4,
"name": "feedback",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 6,
"name": "updated_at",
"type_info": "Timestamptz"
},
{
"ordinal": 7,
"name": "organization_id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid",
"Int4",
"Text",
"Uuid"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
false
]
},
"hash": "bf3c31d22790fe0eeec0234f97f920a3c077a443579c6184f09b95f9d078f593"
}
@@ -0,0 +1,34 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT \n g.user_id, \n l.grading_category_id, \n AVG(g.score)::float4 as avg_score\n FROM user_grades g\n JOIN lessons l ON g.lesson_id = l.id\n WHERE g.course_id = $1\n GROUP BY g.user_id, l.grading_category_id\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "user_id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "grading_category_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "avg_score",
"type_info": "Float4"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
false,
true,
null
]
},
"hash": "c1778b5abe6d4e799993ac6145d1c00bd5d73086e80b9e068010f29202b1f5a8"
}
@@ -0,0 +1,65 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT pr.* \n FROM peer_reviews pr\n JOIN course_submissions cs ON pr.submission_id = cs.id\n WHERE cs.user_id = $1 AND cs.lesson_id = $2\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "submission_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "reviewer_id",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "score",
"type_info": "Int4"
},
{
"ordinal": 4,
"name": "feedback",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 6,
"name": "updated_at",
"type_info": "Timestamptz"
},
{
"ordinal": 7,
"name": "organization_id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
false
]
},
"hash": "da54efaca96ea7a75198417d4ce1754aaad514c9877a264449807338a1f539b8"
}
@@ -0,0 +1,68 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO course_submissions (user_id, course_id, lesson_id, organization_id, content)\n VALUES ($1, $2, $3, $4, $5)\n RETURNING *\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "user_id",
"type_info": "Uuid"
},
{
"ordinal": 2,
"name": "course_id",
"type_info": "Uuid"
},
{
"ordinal": 3,
"name": "lesson_id",
"type_info": "Uuid"
},
{
"ordinal": 4,
"name": "content",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "submitted_at",
"type_info": "Timestamptz"
},
{
"ordinal": 6,
"name": "updated_at",
"type_info": "Timestamptz"
},
{
"ordinal": 7,
"name": "organization_id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid",
"Uuid",
"Uuid",
"Uuid",
"Text"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
false
]
},
"hash": "e0cf43306025c312338d7f507911fccb61f18ddd6bf8f9c90f368a296f346f4b"
}