Skip to content

feat: course prerequisites, announcements, admin dashboard, course import - #450

Merged
DeFiVC merged 2 commits into
ChainLearnOfficial:mainfrom
codemagician1949:feat/prerequisites-announcements-dashboard-import-354-353-367-366
Aug 31, 2026
Merged

feat: course prerequisites, announcements, admin dashboard, course import#450
DeFiVC merged 2 commits into
ChainLearnOfficial:mainfrom
codemagician1949:feat/prerequisites-announcements-dashboard-import-354-353-367-366

Conversation

@codemagician1949

Copy link
Copy Markdown
Contributor

Heads up: based on the build-fix branch

This branch is based on #444 (main currently fails to build — 3 syntax errors from a recent merge, unrelated to this batch). Until #444 merges, this PR's diff will also show those 3 files (course.routes.ts, user.routes.ts, admin-users.service.ts) — that's the build fix, not this feature work. Once #444 merges and this branch is rebased/main is pulled in, that noise will disappear from the diff.

#354GET /api/v1/courses/:id/prerequisites

  • courses.prerequisites: new jsonb string[] column (migration 0020), admin-configurable via the existing POST/PUT /admin/courses (a course can't be its own prerequisite — filtered on update).
  • getCoursePrerequisites() resolves the configured prerequisite courses and annotates each with the caller's completion status (enrollments.completedAt IS NOT NULL), plus an overall met flag. Anonymous callers see every prerequisite as incomplete.

#353 — Announcements

  • New announcements table (migration 0021): title, message, priority (normal/high/urgent), active, createdAt, expiresAt.
  • New module (src/modules/announcements/): full admin CRUD (POST/GET/PUT/DELETE /admin/announcements, admin-guarded) plus a public GET /announcements filtered to active && (no expiry || expiry in the future).

#367GET /api/v1/admin/dashboard

  • New module (src/modules/admin/dashboard.*): total users, new users (today/week/month), total enrollments, quiz completion rate (graded ÷ total submissions), total credentials, total rewards claimed (SUM(rewardAmount) where claimed), plus week-over-week trend comparisons for new users and enrollments. Cached 5 minutes via the existing cache/index.ts helpers. Admin only.

#366 — Course import

  • POST /api/v1/admin/courses/import — multipart/form-data with one JSON file part (reuses the already-registered @fastify/multipart), validated against a Zod schema (core course fields + an optional modules array), creates the course via the existing createCourse() path, then creates each module via the existing createModule() so IDs/locking/audit/cache-invalidation all match a manually-created module. Returns { courseId, modulesCreated }.

    Deviation from the issue, flagging explicitly: the issue's literal route is /admin/courses/:id/import, but its own scope and acceptance criteria describe creating a new course from the file ("creates the course... returns the created course ID") — a target :id doesn't fit that (there's no existing course to import into). Implemented as the collection-level /admin/courses/import instead, matching the actual described behavior. Happy to add a path param back if the real intent was importing additional content into an existing course — wasn't sure which was meant, said so rather than guessing silently.

Verification

  • npm run build (tsc) is clean.
  • No new automated tests for these four endpoints — flagging honestly rather than claiming coverage that isn't there. Ran out of runway to write and verify the DB-mock-based unit tests this repo's existing suite uses (tests/unit/courses/*.test.ts pattern). The new logic (prerequisite resolution, announcement active-filtering, dashboard aggregates, import parsing) has no dedicated test coverage yet — worth adding before/as part of review.

Closes #354
Closes #353
Closes #367
Closes #366

…port

ChainLearnOfficial#354 — GET /api/v1/courses/:id/prerequisites
- courses.prerequisites: jsonb string[] column (migration 0020),
  admin-configurable via existing POST/PUT /admin/courses (self-reference
  filtered out on update)
- CourseService.getCoursePrerequisites(): resolves configured prerequisite
  courses, annotates each with the caller's completion status
  (enrollments.completedAt IS NOT NULL), returns an overall met flag.
  Anonymous callers see every prerequisite as incomplete.

ChainLearnOfficial#353 — POST/GET/PUT/DELETE /api/v1/admin/announcements + GET /api/v1/announcements
- New announcements table (migration 0021): title, message,
  priority (normal/high/urgent), active, createdAt, expiresAt
- New module (src/modules/announcements/): full admin CRUD
  (authGuard+adminGuard) plus a public GET that filters to
  active && (no expiry || expiry in the future)

ChainLearnOfficial#367 — GET /api/v1/admin/dashboard
- New module (src/modules/admin/dashboard.*): total users, new users
  (today/week/month), total enrollments, quiz completion rate (graded /
  total submissions), total credentials, total rewards claimed
  (SUM(rewardAmount) where claimed), plus week-over-week trend
  comparisons for new users and enrollments. Cached 5 minutes via the
  existing cache/index.ts helpers. Admin only.

ChainLearnOfficial#366 — POST /api/v1/admin/courses/import
- Accepts multipart/form-data with one JSON file part (reuses the
  already-registered @fastify/multipart), validates against a Zod schema
  (core course fields + an optional modules array), creates the course via
  the existing createCourse() path, then creates each module via the
  existing createModule() so IDs/locking/audit/cache-invalidation all
  match a manually-created module. Returns { courseId, modulesCreated }.
  Note: the issue's literal route was /admin/courses/:id/import, but its
  own scope/acceptance-criteria describe creating a *new* course from the
  file ("creates the course... returns the created course ID") — a
  target :id doesn't fit that, so implemented as the collection-level
  /admin/courses/import instead. Flagged for review below.

Also included: a standalone build fix (see PR ChainLearnOfficial#444) this branch is based
on top of, since course.routes.ts (one of the files ChainLearnOfficial#354/ChainLearnOfficial#366 touch) had
a syntax error blocking the whole build.

Verification: npm run build (tsc) is clean. Did not add new automated
tests for these four endpoints given time constraints — flagging that
honestly rather than claiming coverage that isn't there. Existing
courses/admin test suites still reference the same service methods
these changes extend (createCourse, createModule, toAdminCourse), so a
schema/behavior regression there would likely surface on the existing
suite even without new tests, but the new logic itself (prerequisite
resolution, announcement active-filtering, dashboard aggregates, import
parsing) has no dedicated coverage yet.

Closes ChainLearnOfficial#354
Closes ChainLearnOfficial#353
Closes ChainLearnOfficial#367
Closes ChainLearnOfficial#366
@drips-wave

drips-wave Bot commented Aug 31, 2026

Copy link
Copy Markdown

@codemagician1949 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@DeFiVC
DeFiVC merged commit 0357638 into ChainLearnOfficial:main Aug 31, 2026
3 of 5 checks passed
DeFiVC pushed a commit that referenced this pull request Sep 1, 2026
main currently fails to typecheck: PR #450 left two files with mangled
code — a stray semicolon splitting the AuditEvent union type in half
(silently dropping "webhook.*" from the union), and a duplicated/
garbled fragment inside CourseService.updateCourse (two overlapping
function bodies spliced together). Neither is related to #328-331;
both are one-off syntax repairs, not behavior changes.

This does not fix every pre-existing error on main — course.service.ts,
course.controller.ts, course.routes.ts, and admin-course.controller.ts
still reference several missing schema tables (courseShares,
courseReviews) and controller methods (recommended, resolveShare,
batchEnroll, reviews, share, archiveCourse, publishCourse,
duplicateCourse) from the same bad merge. That's a separate, larger
repair this PR intentionally does not attempt — see the PR description.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants