Introduce admin CRUD and public version check APIs for Play Store/App Store releases with force or optional update policies, and update profile dropdown seed data for countries, regions, and learner profile fields.
Co-authored-by: Cursor <cursoragent@cursor.com>
Record playback heartbeats via POST /api/v1/videos/engagement/heartbeat and expose completion, replay, and drop-off rates on the analytics dashboard.
Co-authored-by: Cursor <cursoragent@cursor.com>
Store options in field_options with public /field-options and admin CRUD; validate learner profile values on update.
Co-authored-by: Cursor <cursoragent@cursor.com>
Use nullable sqlc.narg fields so empty strings are not written to team_role and other optional columns.
Co-authored-by: Cursor <cursoragent@cursor.com>
Introduces invite, verify, accept, resend, and revoke flows using team_members and invitation tokens, sends the branded invitation template, and requires account activation before team login.
Co-authored-by: Cursor <cursoragent@cursor.com>
Adds CRUD and preview APIs, RBAC permissions, seeded system templates, and migrates OTP email/SMS to template rendering.
Co-authored-by: Cursor <cursoragent@cursor.com>
Expose sort_order on CreateExamPrepUnitInput; insert applies explicit index with sibling shifting (aligned with LMS course create). Updated Swagger and LMS-Personas Postman collection.
Co-authored-by: Cursor <cursoragent@cursor.com>
Migration 000065 adds nullable gender text column; persona API and Postman expose it alongside profile_picture.
Co-authored-by: Cursor <cursoragent@cursor.com>
Introduce lms_personas table, repoint practice persona_id FKs off users, validate persona refs on LMS and exam-prep practice flows, personas.* RBAC permissions, and OpenAPI docs.
Co-authored-by: Cursor <cursoragent@cursor.com>
POST /practices and exam-prep practice create accept missing or null title; persist as empty string. Refresh OpenAPI and document the behavior.
Co-authored-by: Cursor <cursoragent@cursor.com>
Migration 000062 adds lessons.publish_status (DRAFT default for new rows; existing rows published). Editors see all lessons; learners see published-only lists and GET by id. Sequential prerequisites and completion counts ignore drafts. Course lesson_count counts published lessons only. Swagger documents publish_status on create/update bodies.
Co-authored-by: Cursor <cursoragent@cursor.com>
Accept sort_order on CreateLessonInput; SQL falls back to max+1. When set, shift sibling lessons and insert at that position (same pattern as module create). Regenerate sqlc and update Swagger.
Co-authored-by: Cursor <cursoragent@cursor.com>
Parses body sort_order, shifts sibling courses in-program, and inserts at the requested slot; omitting it keeps append-after-max behavior. Swagger/sqlc regenerated.
Co-authored-by: Cursor <cursoragent@cursor.com>
Sequential reorder uses a temporary negative id slot plus range shifts so UNIQUE constraints on programs, courses, modules, and lessons stay valid; replaces module pairwise swap-only behavior.
Co-authored-by: Cursor <cursoragent@cursor.com>
Expose POST /admin/roles/:role/bulk-deactivate and bulk-reactivate for platform users and team_members, mirroring deactivate/reactivate semantics and optional team member exclusions.
Co-authored-by: Cursor <cursoragent@cursor.com>
Expose GET /api/v1/admin/users/:user_id/recent-activity (progress.get_any_user) merging account creation and LMS completion milestones, with optional practice rows.
Co-authored-by: Cursor <cursoragent@cursor.com>
Expose GET /api/v1/admin/users/:user_id/lms-learning-activity for progress.get_any_user so admins see program/course/module/lesson completions and practices from stored completion rows.
Co-authored-by: Cursor <cursoragent@cursor.com>
Filtering matches user profile country/region (case-insensitive trim) and derived subscription state in SQL so pagination totals stay correct.
Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve practice hierarchy using module, lesson, or course linkage and only run module-level cascade when module context exists.
Co-authored-by: Cursor <cursoragent@cursor.com>
Implement public FAQ read endpoints and admin CRUD with RBAC, persistence, and migrations, then regenerate Swagger and add a complete Postman collection so frontend/admin teams can integrate and validate the feature end-to-end.
Co-authored-by: Cursor <cursoragent@cursor.com>
Expose has_practice booleans for LMS and pre-exam hierarchy entities, wire SQL/repository mappings, and regenerate SQLC/Swagger artifacts. Also update the Resend sender display name for outbound emails.
Co-authored-by: Cursor <cursoragent@cursor.com>
Return per-module lesson and practice aggregates under unit modules listing so clients can render module depth without additional queries.
Co-authored-by: Cursor <cursoragent@cursor.com>
Expose per-unit aggregate counts under catalog-course units listing so clients can display unit depth without extra chained requests.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add units, modules, and lessons aggregate counts per catalog course so clients can render hierarchy depth without extra API calls.
Co-authored-by: Cursor <cursoragent@cursor.com>
When updating a module sort_order to an occupied position in the same course, perform an atomic swap in a transaction instead of failing with a unique constraint error.
Made-with: Cursor
Update lesson and practice completion flows to cascade module/course/program progress only when both lesson completion and related published practice completion criteria are met, and align progress counters with the new rule.
Made-with: Cursor
Resolve false OTP already used/expired responses during registration by loading OTP rows using user_id plus submitted otp code and validating usage/expiry on the matched row.
Made-with: Cursor
Extend GetQuestionSetItems and GetPublishedQuestionsInSet queries to match
paginated fields; map audio answer join in repository instead of nils.
Made-with: Cursor