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>
Add Chapa checkout, verify, webhook, and callback flows so subscriptions activate only after confirmed payment. Route subscription checkout through Chapa while keeping ArifPay for direct payments. Include integration docs and a Postman collection.
Co-authored-by: Cursor <cursoragent@cursor.com>
Repair multiline PEM inside private_key before Firebase init; add unit test; use normalized JSON for credentials.
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>
Remove omitempty on LmsPersona.profile_picture so list/get return null when unset. Add LMS-Personas Postman collection matching current API.
Co-authored-by: Cursor <cursoragent@cursor.com>
Insert ids 1-3 catalog rows and sync sequence on up; delete seed ids on down before dropping lms_personas.
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>
Migration 000061 inserts the RBAC role and demo user (openlearner@yimaru.com). STUDENT keeps sequential ApplyAccess and practice ordering; OPEN_LEARNER shares learner permissions and customer flows. Document the role in Swagger and point initial seed SQL at the migration for the demo account.
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>
Admin bulk deactivate/reactivate accepts decimal path segments matching GET /rbac/roles IDs, resolving RoleRecord.name to the platform key. Document 404 when id is unknown. Add Cursor rule: on push, commit dirty tree first without secrets.
Co-authored-by: Cursor <cursoragent@cursor.com>
Platform ADMIN callers no longer hit 403 on these endpoints; bulk changes to platform users.role ADMIN remain restricted to SUPER_ADMIN, while team_members.team_role ADMIN is still eligible under path ADMIN.
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
Clean up docker-compose by dropping commented env_file entries that were only used during temporary runtime-env debugging.
Co-authored-by: Cursor <cursoragent@cursor.com>
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>
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>
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>
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>
Allow builder-native response kinds like OPTION to resolve to DYNAMIC so schema-driven definition creation succeeds.
Co-authored-by: Cursor <cursoragent@cursor.com>