feat: Implement Phase 10 support and recommendations features
CI / test (push) Successful in 10m22s
CI / test (pull_request) Successful in 10m53s

- Added models for support messages, SLA policies, tickets, ticket events, and ticket links.
- Created routes for help, help admin, newsletter, recommendations, and support for both customer and admin.
- Developed services for help, marketing (newsletter), and recommendations.
- Introduced support service for ticket management, including creation, replies, transitions, and attachments.
- Added validation schemas for support recommendations and ticket management.
- Implemented a cron job for support reconciliation and recommendation cleanup.
- Created migration for new support and recommendation database tables.
- Added unit tests for validation and policy checks related to Phase 10 features.
This commit is contained in:
Sathira Sri Sathara
2026-09-09 16:07:31 +05:30
parent abb760cc19
commit f920ca8920
46 changed files with 251 additions and 2 deletions
+1
View File
@@ -0,0 +1 @@
const r=require("express").Router(),c=require("../controllers/help.controller"),{sensitiveLimiter}=require("../middleware/rateLimit.middleware");r.get("/help/categories",c.categories);r.get("/help/categories/:slug",c.category);r.get("/help/articles",c.articles);r.get("/help/articles/:slug",c.article);r.get("/help/search",sensitiveLimiter,c.search);module.exports=r;
+1
View File
@@ -0,0 +1 @@
const r=require("express").Router(),c=require("../controllers/helpAdmin.controller"),{authenticate}=require("../middleware/auth.middleware"),{checkPermission}=require("../middleware/permission.middleware"),validate=require("../middleware/validate.middleware"),s=require("../validation/supportRecommendation.schemas");r.use(authenticate);r.get("/help/categories",checkPermission("help.read",{custom:true}),c.categories);r.post("/help/categories",checkPermission("help.manage",{custom:true}),validate(s.helpCategory),c.createCategory);r.get("/help/articles",checkPermission("help.read",{custom:true}),c.articles);r.post("/help/articles",checkPermission("help.manage",{custom:true}),validate(s.helpArticle),c.createArticle);r.post("/help/articles/:id/publish",checkPermission("help.publish",{custom:true}),c.publish("PUBLISHED"));r.post("/help/articles/:id/archive",checkPermission("help.publish",{custom:true}),c.publish("ARCHIVED"));module.exports=r;
+12
View File
@@ -43,6 +43,12 @@ const loyaltyCustomerRoutes = require("./loyalty/customer.routes");
const loyaltyAdminRoutes = require("./loyalty/admin.routes");
const wholesaleCustomerRoutes = require("./wholesale/customer.routes");
const wholesaleAdminRoutes = require("./wholesale/admin.routes");
const supportCustomerRoutes = require("./support/customer.routes");
const supportAdminRoutes = require("./support/admin.routes");
const helpRoutes = require("./help.routes");
const helpAdminRoutes = require("./helpAdmin.routes");
const newsletterRoutes = require("./newsletter.routes");
const recommendationRoutes = require("./recommendation.routes");
const router = express.Router();
@@ -78,5 +84,11 @@ router.use("/", loyaltyCustomerRoutes);
router.use("/admin", loyaltyAdminRoutes);
router.use("/", wholesaleCustomerRoutes);
router.use("/admin", wholesaleAdminRoutes);
router.use("/", supportCustomerRoutes);
router.use("/admin", supportAdminRoutes);
router.use("/", helpRoutes);
router.use("/admin", helpAdminRoutes);
router.use("/", newsletterRoutes);
router.use("/", recommendationRoutes);
module.exports = router;
+1
View File
@@ -0,0 +1 @@
const r=require("express").Router(),c=require("../controllers/newsletter.controller"),{authenticate}=require("../middleware/auth.middleware"),{checkPermission}=require("../middleware/permission.middleware"),validate=require("../middleware/validate.middleware"),s=require("../validation/supportRecommendation.schemas"),{sensitiveLimiter}=require("../middleware/rateLimit.middleware");r.post("/newsletter/subscribe",sensitiveLimiter,validate(s.newsletter),c.subscribe);r.post("/newsletter/unsubscribe/:token",sensitiveLimiter,c.unsubscribe);r.get("/newsletter/me",authenticate,c.mine);r.get("/admin/newsletter/subscribers",authenticate,checkPermission("newsletter.subscribers.read",{custom:true}),c.list);module.exports=r;
+1
View File
@@ -0,0 +1 @@
const r=require("express").Router(),c=require("../controllers/recommendation.controller"),{authenticate}=require("../middleware/auth.middleware"),validate=require("../middleware/validate.middleware"),s=require("../validation/supportRecommendation.schemas"),{sensitiveLimiter}=require("../middleware/rateLimit.middleware");r.post("/recommendations/events",authenticate,sensitiveLimiter,validate(s.viewEvent),c.event);r.get("/products/:productId/recommendations/related",c.related);r.get("/recommendations/trending",c.trending);r.get("/recommendations/popular",c.popular);r.get("/recommendations/recently-viewed",authenticate,c.recent);r.get("/recommendations/for-you",authenticate,c.forYou);module.exports=r;
+1
View File
@@ -0,0 +1 @@
const r=require("express").Router(),c=require("../../controllers/support/admin.controller"),{authenticate}=require("../../middleware/auth.middleware"),{checkPermission}=require("../../middleware/permission.middleware"),validate=require("../../middleware/validate.middleware"),s=require("../../validation/supportRecommendation.schemas");r.use(authenticate);r.get("/support/tickets",checkPermission("support.tickets.read",{custom:true}),c.list);r.get("/support/tickets/:id",checkPermission("support.tickets.read",{custom:true}),c.detail);r.post("/support/tickets/:id/assign",checkPermission("support.tickets.assign",{custom:true}),validate(s.assign),c.assign);r.post("/support/tickets/:id/claim",checkPermission("support.tickets.assign",{custom:true}),c.claim);r.post("/support/tickets/:id/messages",checkPermission("support.tickets.reply",{custom:true}),validate(s.message),c.reply);r.post("/support/tickets/:id/internal-notes",checkPermission("support.tickets.internal_notes",{custom:true}),validate(s.internalNote),c.note);r.post("/support/tickets/:id/resolve",checkPermission("support.tickets.status",{custom:true}),c.action("RESOLVED"));r.post("/support/tickets/:id/reopen",checkPermission("support.tickets.status",{custom:true}),c.action("WAITING_FOR_SUPPORT"));r.post("/support/tickets/:id/close",checkPermission("support.tickets.status",{custom:true}),c.action("CLOSED"));r.patch("/support/tickets/:id/priority",checkPermission("support.tickets.priority",{custom:true}),validate(s.priority),c.priority);r.get("/support/tickets/:id/attachments/:attachmentId",checkPermission("support.tickets.read",{custom:true}),c.attachment);module.exports=r;
+1
View File
@@ -0,0 +1 @@
const r=require("express").Router(),c=require("../../controllers/support/customer.controller"),{authenticate}=require("../../middleware/auth.middleware"),validate=require("../../middleware/validate.middleware"),s=require("../../validation/supportRecommendation.schemas"),{sensitiveLimiter}=require("../../middleware/rateLimit.middleware");r.use(authenticate);r.get("/support/tickets",c.list);r.post("/support/tickets",sensitiveLimiter,validate(s.ticketCreate),c.create);r.get("/support/tickets/:id",c.detail);r.post("/support/tickets/:id/messages",sensitiveLimiter,validate(s.message),c.reply);r.post("/support/tickets/:id/close",c.close);r.get("/support/tickets/:id/attachments/:attachmentId",c.attachment);module.exports=r;