Count only children that have published practices at module and above for LMS and exam prep; keep lesson at 100% after one practice and module at 100% after direct module practice.
Co-authored-by: Cursor <cursoragent@cursor.com>
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>
Strip disallowed characters from customization title and description so subscription payments pass Chapa validation.
Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve payments by nonce or session_id in webhook/verify processing so status checks can complete and activate subscriptions even when ArifPay verify responses omit nonce.
Co-authored-by: Cursor <cursoragent@cursor.com>
Switch lesson accessibility gating from deprecated lesson-complete records to published practice completion of the previous lesson so unlocking follows /progress/practices completion flow.
Co-authored-by: Cursor <cursoragent@cursor.com>
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>
Preserve the underlying Google token validation failure and log safe request context so ID token issues are easier to debug.
Co-authored-by: Cursor <cursoragent@cursor.com>
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>
Require the client to choose CHAPA or ARIFPAY in the subscription checkout request body and route payment initiation and verification through the matching provider.
Co-authored-by: Cursor <cursoragent@cursor.com>
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>
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>
Keeps the same response shape as STUDENT while skipping sequential locks; progress fields are still populated for completion UI.
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>
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>
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>
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>
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>
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>
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>
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>
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>
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
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
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