Commit Graph

608 Commits

Author SHA1 Message Date
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
1e62510321 Always serialize active_subscription on profile responses.
Null encodes when there is no active plan so clients see explicit subscription state; Swagger regenerated and GET /users description updated accordingly.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 00:16:10 -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
7f8ef3373c Add paginated Vimeo video list API (GET /me/videos).
Exposes the Vimeo account library for admin workflows and syncs swagger docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 22:23:50 -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
8bba318372 Fix practice completion roll-up for non-module scopes.
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>
2026-05-13 03:58:39 -07:00
4ada908555 Allow completion for existing practice sets.
Treat existing PRACTICE sets as completable even when not published, while keeping sequence enforcement only for published practices.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-13 03:43:50 -07:00
86ab4e53d4 Fix practice completion lookup for progress endpoint.
Prioritize resolving lms_practices.id before falling back to question_set.id to avoid false 404 responses caused by cross-table ID collisions.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-13 03:36:39 -07:00
c711df68b9 Fix practice completion lookup for progress endpoint.
Accept either question-set IDs or LMS practice IDs and recognize LMS owner types so valid practice completions no longer return practice-not-found responses.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 02:57:05 -07:00
eae87b40b5 Add practice completion progress endpoint.
Expose POST /progress/practices/:id/complete so practice completions are recorded through the existing CompletePractice flow and included in learner progress tracking.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 11:20:33 -07:00
7e75d79dc8 Pass Firebase project_id explicitly from service account JSON.
Parse FCM_SERVICE_ACCOUNT_KEY, validate project_id, and provide firebase.Config{ProjectID} during FCM client initialization to prevent missing-project-id messaging failures.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 11:02:01 -07:00
4509fe2dc0 Initialize FCM client lazily during push send.
Add ensureFCMClient() so push APIs retry FCM initialization at request time and return actionable initialization errors when the service account key is empty or invalid.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 10:58:42 -07:00
6f1cb24c63 Add runtime config debug logging for test push flow.
Log DB_URL alongside FCM_SERVICE_ACCOUNT_KEY during test-push requests and keep compose env-file wiring aligned with current local debug setup.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 10:25:53 -07:00
cd0ae19d03 Log FCM env value on test-push requests.
Add request-time logging in the test push endpoint so FCM_SERVICE_ACCOUNT_KEY can be verified during each API call, not only at service startup.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 09:56:45 -07:00
75353f8bdd Log FCM service account env value at startup.
Add a notification-service startup log to print FCM_SERVICE_ACCOUNT_KEY for runtime verification during push notification troubleshooting.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 09:54:22 -07:00
b2a72c2f6e Fix device registration error mapping for invalid user IDs.
Validate device registration input and translate devices_user_fk violations into a clear bad-request response so invalid auth contexts no longer return opaque 500 errors.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 08:32:42 -07:00
6a4fe68628 Add full FAQ management APIs and integration assets.
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>
2026-05-11 07:58:17 -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
9da9eb77e5 fix dynamic builder runtime mapping for option responses
Allow builder-native response kinds like OPTION to resolve to DYNAMIC so schema-driven definition creation succeeds.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-08 10:56:41 -07:00
3d1b3ad9b8 dynamic question type builder completion 2026-05-08 10:12:02 -07:00
9a17f0b3c4 use descriptive top-level message for direct payments
Keep provider-specific details in data.message and return a stable, human-readable top-level success message for /payments/direct responses.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-07 09:26:07 -07:00
0983589e36 extend full-payload direct proxy flow to MPESA
Align MPESA direct payment with TELEBIRR_USSD by routing it through the provider's full checkout payload proxy endpoint for consistent gateway behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-07 09:21:43 -07:00
21ce61b910 telebirr-ussd direct payment fix 2026-05-07 09:08:43 -07:00
f906862676 partly implemented dynamic question builder + payment routes fix 2026-05-07 08:10:21 -07:00
73370633ce temporarily disabled subscription check 2026-05-06 05:10:36 -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
10954d88b0 subscription management fix + duolingo hierarchy implementation 2026-05-04 10:44:18 -07:00
eba2b87ed6 Use initial assessment description as normalized level.
Made-with: Cursor
2026-04-29 08:12:09 -07:00
60290e5c34 Swap module sort_order on conflict during update.
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
2026-04-29 03:36:45 -07:00
8430b82687 Fix partial question-set updates preserving existing values.
When PUT payload omits title, status, or shuffle_questions, reuse current persisted values so updates do not write invalid empty status values.

Made-with: Cursor
2026-04-29 03:02:13 -07:00
cdb0fa1bb3 Enforce strict initial assessment set validation.
Require INITIAL_ASSESSMENT titles to follow the Level Test A1/A2/B1/B2 format and ensure passing_score is always present on create and update.

Made-with: Cursor
2026-04-29 02:47:21 -07:00
9027b65011 Require lesson and practice completion for LMS rollups.
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
2026-04-28 09:56:53 -07:00
8c116f4a0b GET question sets API fix 2026-04-28 09:41:09 -07:00
87bf2ed609 data loss fix 2026-04-28 09:30:48 -07:00
9cfd6c524e Allow INITIAL_ASSESSMENT question sets without owner_type and owner_id
Made-with: Cursor
2026-04-27 10:46:33 -07:00
0d02eb1a24 add MinIO media URL refresh endpoint
Add POST /api/v1/files/refresh-url to issue fresh presigned URLs from object keys, minio:// references, or stale presigned URLs so clients can refresh media links before render.

Made-with: Cursor
2026-04-27 05:25:16 -07:00
78f231f222 fix OTP verification by submitted code
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
2026-04-25 05:07:19 -07:00
526426d9f9 course practice count fix 2026-04-25 02:41:34 -07:00
5857fce9a0 count data for course 2026-04-25 02:36:52 -07:00
7e26f15bed early otp expiration fix 2026-04-25 00:16:05 -07:00
bc68326a66 fix: return sample_answer_voice_prompt and audio_correct_answer_text in question set items list
Extend GetQuestionSetItems and GetPublishedQuestionsInSet queries to match
paginated fields; map audio answer join in repository instead of nils.

Made-with: Cursor
2026-04-24 03:11:47 -07:00
33d34f0dd2 fix: map default CEFR courses to Beginner/Intermediate/Advanced programs
Seed A1-A2, B1-B2, and C1-C2 only on their matching programs; add migration
000050 for existing databases. Document mapping in domain.

Made-with: Cursor
2026-04-24 01:14:50 -07:00
5b53929d92 learning progress implementation 2026-04-23 03:58:27 -07:00
6c672c4b20 static data for Courses 2026-04-23 02:07:32 -07:00
9db9c9899a module+lesson+practice implementations 2026-04-23 01:59:20 -07:00
152478a96c added program 2026-04-23 00:59:01 -07:00
9154dec067 fix: course-management practice detail without sub_module_practices row
- resolveCourseManagementPractice falls back to SUB_MODULE PRACTICE question_sets
- Synthetic practice uses id 0 and question_set_id for orphan sets
- Align GET practice and /detail with resolver; sync question_count after load

Made-with: Cursor
2026-04-21 09:59:41 -07:00
5fbca53534 fix: resolve practice by question set id; set Response flags on question-sets by-owner
- GetSubModulePracticeByID matches sub_module_practices.id or question_set_id
- Prefer primary id when both could match (ORDER BY + LIMIT 1)
- Set Success/StatusCode on practice GET/detail and GetQuestionSetsByOwner

Made-with: Cursor
2026-04-21 09:55:11 -07:00
6839d1aa0d fix: sub-module practices list excludes non-PRACTICE sets and bad Response flags
- Drop question_sets.set_type = PRACTICE filter so sub_module_practices rows list correctly
- Set Success and StatusCode on GET sub-modules/:id/practices response
- Return empty JSON array instead of null for no practices

Made-with: Cursor
2026-04-21 09:31:22 -07:00
72d1a0c3ed feat: list sub-categories by course category ID
- GET /api/v1/course-management/categories/:categoryId/sub-categories

- SQL GetCourseSubCategoriesByCategoryID; swagger refresh

Made-with: Cursor
2026-04-20 08:32:19 -07:00
de95c4d0d2 feat: practice detail API, inactive purge tracking, and related plumbing
- Add GET /api/v1/course-management/practices/:practiceId/detail with full question items

- Add migration 000040 for sub-module content inactive purge tracking

- Hierarchy queries, sqlc gen, config/app purge job, swagger refresh

Made-with: Cursor
2026-04-20 08:24:59 -07:00
90baa582be fix: load sub-module lesson by ID regardless of active flag
Course-management GET/PUT used GetSubModuleLessonByID with is_active=TRUE,
which returned no row for inactive lessons. Align with other ByID lookups
and allow admins to view and edit inactive lessons.

Made-with: Cursor
2026-04-20 00:48:13 -07:00
bbd919ca12 feat: optional include_inactive for sub-module lessons list
GET .../sub-modules/:id/lessons?include_inactive=true returns all lessons;
default remains active-only.

Made-with: Cursor
2026-04-18 03:25:28 -07:00
3e54b5039d fix: surface DB error when team login refresh token issuance fails
Return err.Error() in the response so operators see e.g. missing
team_refresh_tokens table instead of a generic message.

Made-with: Cursor
2026-04-18 03:13:34 -07:00
24f1aca97a fix: return updated lesson from UpdateSubModuleLesson after is_active false
GetSubModuleLessonByID filters is_active=true, so refetch failed with 500
after soft-deactivating. Use RETURNING row from the update instead.

Made-with: Cursor
2026-04-18 02:54:47 -07:00
ce1b827768 refresh token fix 2026-04-17 10:16:25 -07:00
886b62ed68 feat(levels): flexible cefr_level codes up to 64 chars
- Migration 000038 drops fixed A1-C3 check and widens cefr_level column
- CreateLevel validates length and NUL only; preserve client casing
- Regenerate Swagger docs

Made-with: Cursor
2026-04-17 09:24:34 -07:00
7ff0b639cf added more structure to submodules 2026-04-17 09:07:25 -07:00
c5d3935062 added more structure to levels 2026-04-17 08:33:58 -07:00
518c3ee751 added more structure to lessons 2026-04-17 08:27:40 -07:00
1026354c24 Expand course hierarchy read APIs and practice retrieval.
Add list/detail endpoints for courses, levels, modules, submodules, and submodule practices; extend course listing queries; add lesson update support and clean up removed route paths.

Made-with: Cursor
2026-04-17 07:52:22 -07:00
343ce470cc add lesson and subcategory retrieval/update endpoints
Introduce dedicated APIs for submodule lesson detail/update and subcategory listing (including Human Language), with SQL/query wiring and handler routing updates.

Made-with: Cursor
2026-04-17 01:40:47 -07:00
01914cb81e Add lesson detail retrieval endpoints.
Expose APIs to list lessons by submodule and fetch a single lesson by ID, including title, description, intro video URL, and question count.

Made-with: Cursor
2026-04-16 02:42:21 -07:00
a9c6966820 add legacy learning-path GET endpoint for flows compatibility
Expose GET /course-management/courses/:courseId/learning-path and build response from unified hierarchy tables so first-time Flows tab loads no longer fail with Cannot GET.

Made-with: Cursor
2026-04-14 10:05:53 -07:00
57f0db269a add legacy category courses GET endpoint for compatibility
Expose GET /course-management/categories/:categoryId/courses so legacy tab/API callers no longer fail with Cannot GET during initial content load.

Made-with: Cursor
2026-04-14 09:21:13 -07:00
83f5541650 add course category deletion endpoint
Expose delete support for top-level course categories and cascade removal of linked sub-categories/courses for content-management cleanup.

Made-with: Cursor
2026-04-14 06:22:36 -07:00
542a597f41 fix module removal to delete actual module records
Add a module delete API route and handler so level/module removal actions remove modules directly instead of only deleting sub-modules.

Made-with: Cursor
2026-04-14 05:58:37 -07:00
9123ff571d add sub-category deletion endpoint for course management
Introduce a compatibility delete route and handler for course sub-categories and cascade-delete their linked courses to support admin content cleanup flows.

Made-with: Cursor
2026-04-14 05:45:16 -07:00
0cc813d224 fix course creation linkage to sub-categories
Allow course creation payloads to include sub_category_id and persist it so newly created language paths appear in unified hierarchy views.

Made-with: Cursor
2026-04-14 05:23:24 -07:00
a4d1f395da add legacy human-language hierarchy route alias
Expose /course-management/human-language/hierarchy as an alias to the unified hierarchy handler so older admin clients continue working without 404s.

Made-with: Cursor
2026-04-14 05:15:42 -07:00
2ff1e89263 more course CRUD fix 2026-04-14 05:04:38 -07:00
5858aeb744 course CRUD fix 2026-04-14 04:06:49 -07:00
e3afadf2bb 404 errors fix 2026-04-14 03:56:49 -07:00
d9783310d1 Add legacy hierarchy fallback for pre-migration databases.
Handle missing course_sub_categories table by serving hierarchy data from legacy categories/courses queries so content pages keep loading until unified hierarchy migration is applied.

Made-with: Cursor
2026-04-14 01:02:31 -07:00
69d3d440d0 permissions data seed fix 2026-04-14 00:39:42 -07:00
894e18bcae removed all unnecessary data seed 2026-04-10 03:32:07 -07:00
7613eb583a new course management hierarchy 2026-04-10 03:06:30 -07:00
7918e62ca9 normalize human language module and sub-module grouping
Enhance hierarchy parsing to group Module-N and Module-N.M naming into stable module/sub-module structures under each CEFR level for consistent rendering.

Made-with: Cursor
2026-04-07 06:30:54 -07:00
4055ad46f6 add hierarchy endpoint and mobile integration guide
Expose a dedicated human-language hierarchy endpoint aligned to category/subcategory/course/level/module/sub-module structure and add a complete learner mobile integration guide.

Made-with: Cursor
2026-04-07 06:13:03 -07:00
9c9ab41f41 add dedicated human language backend endpoints
Introduce separate CEFR-based human language lesson APIs for create, update, and level-filtered retrieval while keeping existing non-language course hierarchy endpoints unchanged.

Made-with: Cursor
2026-04-07 05:40:15 -07:00
43f79d34ea fetch practice pagination fix 2026-04-07 03:37:19 -07:00
cd8670d5a6 content filtering adjustment 2026-04-07 03:09:44 -07:00
58a94dcd8e public URLs allowed 2026-04-07 01:18:16 -07:00
05cb8715f9 seed data clearer API 2026-03-29 01:31:43 -07:00
36134f32a2 reseed feature adjustment 2026-03-27 03:29:33 -07:00
3aca2c438d foreign key fix 2026-03-27 02:49:20 -07:00
e6fe8ab7e3 reseed directory fix 2026-03-27 02:40:49 -07:00
4b46fd60dc reseed config fix 2026-03-27 02:36:20 -07:00
0cb58b35f8 new reseed endpoint 2026-03-27 02:29:30 -07:00
8f719c2a32 .mp3 upload fix 2026-03-25 06:29:23 -07:00
e689f34212 minio .env access adjustment 2026-03-25 06:19:20 -07:00
b06b8645cf data seed + file upload handle fixes 2026-03-24 04:58:05 -07:00
94d6777c48 more seed data 2026-03-23 05:24:29 -07:00