Commit Graph

319 Commits

Author SHA1 Message Date
c9f4a9c428 feat: auto-assign and return display_order for question set items
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-12 01:38:27 -07:00
c9a4bc1306 free/premium feature 2026-06-10 04:23:47 -07:00
26cf7d2908 feat: scope subscriptions by content type and make Duolingo plans lifetime
LEARN_ENGLISH plans unlock LMS only; IELTS and DUOLINGO unlock matching exam-prep catalog courses. Enable category subscription gating, restrict programs to Learn English, and treat Duolingo subscriptions as non-expiring one-time purchases.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-10 03:59:26 -07:00
dfdb2a52dc feat: add LMS lesson reorder endpoint within a module
Add PUT /api/v1/modules/:moduleId/lessons/reorder with lessons.reorder permission, matching the existing modules and exam-prep lesson reorder patterns.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-10 03:28:13 -07:00
e56bea3abf feat: add hierarchy publish status and resolve question type definition IDs
Extend DRAFT/PUBLISHED to programs, courses, modules, and exam-prep hierarchy entities with learner visibility gating and progress exclusion. Resolve question_type_definition_id in question responses for legacy system types and unlinked dynamic questions.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-10 02:40:16 -07:00
5c6cb1b8d3 feat: send in-app and push learner notifications for key milestones
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-09 05:11:16 -07:00
8dd1d40a16 feat: limit Learn English parents to one LMS practice each
Reject creating a second practice on the same course, module, or lesson with 409 Conflict, and enforce the rule in the database via unique partial indexes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-09 04:28:14 -07:00
b780db5307 feat: expire stale pending payments with background worker
Add a configurable cron worker to bulk-mark PENDING payments past expires_at as EXPIRED. Also remove obsolete integration docs and refresh Swagger/go.mod artifacts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-09 04:10:17 -07:00
2605877f12 Resolve question-set question-types to builder definitions.
Map legacy runtime types like AUDIO to catalog keys (e.g. audio_conversation_type) so the endpoint matches type-definitions API output.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 06:46:54 -07:00
a75700ffaa Add GET question-sets question-types endpoint for practice sets.
Returns distinct question_type values with per-type counts so clients can resolve types from question_set_id without loading full questions.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 06:35:46 -07:00
632371c3d0 apple sign in 2026-06-01 01:02:28 -07:00
c00ab684c5 Fix LMS sequential gating when sort_order has gaps.
Resolve the immediate predecessor by sort_order (and id) instead of requiring sort_order - 1, so learners cannot skip locked programs, courses, or modules when ordering numbers are non-consecutive.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 04:04:38 -07:00
fbad083ca4 Add admin payments list API with filters and fix /admin route conflict.
Expose GET /api/v1/admin/payments for filtered gateway transaction listing, constrain /admin/:id to integers so /admin/payments is not mistaken for an admin id, and grant payments.list_all to ADMIN.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-29 05:50:46 -07:00
853bd730bb Fix payment status update parameter typing for ArifPay verification.
Use explicit SQL casts and named sqlc args to avoid PostgreSQL 42P08 ambiguity during nonce/session status updates, and align repository bindings with regenerated sqlc types.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 02:07:18 -07:00
fc67de935d Publish question sets by default and backfill existing sets.
Set question_set creation fallback status to PUBLISHED and add a migration that publishes existing draft/inactive sets while updating the database default status for future records.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 00:41:31 -07:00
c77a97b40d Return learner-visible practices with access metadata.
Expose practices to learner roles based on practice shell publish state and include per-practice access fields derived from linked question set readiness so clients can manage completion/access UX explicitly.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 00:32:44 -07:00
ffbb885d06 Fix LMS practice visibility and completion publish checks.
Require question_sets.status to be PUBLISHED for learner-visible practices and reject completion for non-published practice sets so learner progress reflects only publish-ready content.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 00:11:48 -07:00
474bf3282a Fix hierarchical learner progress percentage rollups.
Compute program/course/module/lesson progress using lesson-completion rollups from completed practices, with direct module/course practice completion forcing parent completion as required.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 23:57:21 -07:00
a1c6b3c15a progress precentage fix 2026-05-27 09:18:25 -07:00
79fb95ce36 Add category-based subscription controls for LMS and exam prep.
Introduce plan and content categories across programs and exam-prep catalog roots, wire category-aware checkout and access checks, and keep learner gating temporarily bypassed until data migration is ready.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 06:20:49 -07:00
afdd07d65d Update learner progress to use practice completions only.
Remove lesson completion from learner progress percentages, access completion snapshots, and LMS rollups while keeping generated SQLC and Swagger artifacts in sync.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 03:27:54 -07:00
3f73afb4bf Add video engagement tracking and analytics metrics.
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>
2026-05-24 02:59:46 -07:00
56089fa8fd Add users by country to analytics dashboard.
Expose by_country breakdown on GET /api/v1/analytics/dashboard from users.country.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-24 01:47:41 -07:00
e957eacf80 Add profile field breakdowns to analytics dashboard.
Expose user counts by education_level, occupation, learning_goal, and language_challange on GET /api/v1/analytics/dashboard.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 09:54:47 -07:00
176f78515d Fix partial team member updates clearing team_role on invite accept.
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>
2026-05-22 07:54:44 -07:00
31bd1e3814 Add team member email invitations for admin panel onboarding
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>
2026-05-22 03:43:00 -07:00
14d94ec723 Honor optional sort_order when creating exam-prep units.
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>
2026-05-20 07:18:35 -07:00
5399d33af6 Add optional gender to LMS personas.
Migration 000065 adds nullable gender text column; persona API and Postman expose it alongside profile_picture.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-20 06:37:21 -07:00
6ab077b53d Rename LMS persona image field to profile_picture.
Add migration 000064 renaming avatar_url column; expose profile_picture in API, sqlc, and Swagger.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-20 06:17:15 -07:00
873be1b482 Add LMS personas catalog and CRUD API.
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>
2026-05-20 06:06:42 -07:00
bd1767d2a6 Add LMS lesson draft and publish visibility.
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>
2026-05-20 02:16:42 -07:00
fffdff1031 Honor optional sort_order on lesson create under a module.
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>
2026-05-20 01:56:15 -07:00
83db13bed0 Honor optional sort_order on module create under a course.
Accept sort_order in CreateModuleInput, shift siblings when set, and default to max+1 when omitted.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 04:15:18 -07:00
12ad59c409 Add draft vs published status for LMS and exam-prep practices.
Expose publish_status on create/update, filter learner-facing lists and gates, and add migration 000060.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 03:57:43 -07:00
37aef49e28 Honor optional sort_order on course create under a program.
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>
2026-05-19 02:54:17 -07:00
d28bddace1 Accept optional sort_order when creating LMS programs.
Preserve append-after-max ordering when omitting sort_order and keep global uniqueness enforced by DB.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 02:10:49 -07:00
ecad91d89e Add SUPER_ADMIN bulk deactivate and reactivate by role.
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>
2026-05-19 00:52:14 -07:00
a80db8afd9 Add admin recent-activity timeline for learner profile UIs.
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>
2026-05-18 01:13:21 -07:00
52effaa321 Add admin endpoint for nested user LMS completion activity.
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>
2026-05-18 00:58:49 -07:00
062b1f6151 Add country, region, and subscription_status filters to GET /users.
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>
2026-05-18 00:37:11 -07:00
49bcc22d0d Expose subscription_status on user profile responses instead of active_subscription.
Users see ACTIVE, PENDING, or Unsubscribed via new batch and single SQL helpers; Swagger refreshed.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 00:28:19 -07:00
f824c16c64 user list response fix 2026-05-18 00:09:26 -07:00
2883561525 Add monthly revenue trend for analytics when year is specified.
Exposes payments.revenue_monthly with Jan–Dec SUCCESS totals (UTC) per currency for dashboard charts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 23:32:36 -07:00
a1696bf1e0 Fix analytics dashboard course counts for LMS and exam_prep hierarchies.
Replace stub AnalyticsCourseCounts query and expose lms / exam_prep inventory in the courses section.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 22:34:25 -07:00
024a69b74b Add date-range filtering to analytics dashboard API.
Support all-time, year, year+month, and custom from/to query params with filtered metrics and time-series charts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-15 02:15:15 -07:00
bc2357374b Add practice-existence flags and refresh API contracts.
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>
2026-05-08 11:57:11 -07:00
3d1b3ad9b8 dynamic question type builder completion 2026-05-08 10:12:02 -07:00
b62d89574e Include nested lesson and practice counts in exam-prep modules list response.
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>
2026-05-05 07:05:35 -07:00
16c3f6b613 Include nested module, lesson, and practice counts in exam-prep units list response.
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>
2026-05-05 06:35:13 -07:00
4124f98160 Include nested content counts in exam-prep catalog list response.
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>
2026-05-05 06:13:01 -07:00