feat: implement 8 features across full stack

- Leaderboard: rank-based percentile tiers (champion/gold/silver/bronze),
    deterministic tie-breaking (xp DESC, user_id ASC)
  - Mentor chat: md: breakpoints, safe-area-inset-bottom padding
  - Learning progress: server-side progressPct, curriculum expansion safety
  - Physical orders: hard-disabled with 410 Gone
  - Certificate approval: pending/issued flow, admin issue/revoke endpoints,
    certificate_requires_approval setting (migration 0031)
  - Draft/publish: is_published on lessons and chapters, admin publish UI
    (migration 0030)
  - Video panel: static thumbnails (no preload), client-side pagination
  - Rich editor: TipTap + tiptap-markdown for lesson descriptions,
    marked + DOMPurify for SafeMarkdown rendering
This commit is contained in:
ahp
2026-10-18 10:14:22 +03:30
parent 75e2892e36
commit 03610bc3d3
23 changed files with 1641 additions and 474 deletions
+5
View File
@@ -101,6 +101,9 @@ func newRouter(s *Server) http.Handler {
mux.HandleFunc("POST /api/admin/users/{id}/reset-password", admin(s.handleAdminResetPassword))
mux.HandleFunc("GET /api/admin/physical-orders", admin(s.handleAdminListPhysicalOrders))
mux.HandleFunc("PUT /api/admin/physical-orders/{id}", admin(s.handleAdminUpdatePhysicalOrder))
mux.HandleFunc("GET /api/admin/certificates/pending", staff(s.handleAdminListPendingCertificates))
mux.HandleFunc("POST /api/admin/users/{id}/certificate/issue", staff(s.handleAdminIssueCertificate))
mux.HandleFunc("POST /api/admin/users/{id}/certificate/revoke", staff(s.handleAdminRevokeCertificate))
mux.HandleFunc("GET /api/admin/settings", admin(s.handleAdminGetSettings))
mux.HandleFunc("PUT /api/admin/settings", admin(s.handleAdminPutSettings))
mux.HandleFunc("GET /api/admin/chat-export", admin(s.handleAdminChatExport))
@@ -127,11 +130,13 @@ func newRouter(s *Server) http.Handler {
mux.HandleFunc("POST /api/admin/chapters", staff(s.handleAdminCreateChapter))
mux.HandleFunc("PUT /api/admin/chapters/{id}", staff(s.handleAdminUpdateChapter))
mux.HandleFunc("DELETE /api/admin/chapters/{id}", staff(s.handleAdminDeleteChapter))
mux.HandleFunc("POST /api/admin/chapters/{id}/publish", staff(s.handleAdminPublishChapter))
mux.HandleFunc("GET /api/admin/lessons", staff(s.handleAdminListLessons))
mux.HandleFunc("POST /api/admin/lessons", staff(s.handleAdminCreateLesson))
mux.HandleFunc("PUT /api/admin/lessons/{id}", staff(s.handleAdminUpdateLesson))
mux.HandleFunc("DELETE /api/admin/lessons/{id}", staff(s.handleAdminDeleteLesson))
mux.HandleFunc("POST /api/admin/lessons/{id}/publish", staff(s.handleAdminPublishLesson))
mux.HandleFunc("GET /api/admin/lessons/{id}/questions", staff(s.handleAdminListQuestions))
mux.HandleFunc("POST /api/admin/lessons/{id}/questions", staff(s.handleAdminCreateQuestion))
mux.HandleFunc("PUT /api/admin/questions/{id}", staff(s.handleAdminUpdateQuestion))