feat: Implement Phase 2 cross-cutting services with email and notification enhancements

- Refactor email verification and password reset utilities to use new email service.
- Introduce email delivery queue and notification delivery model for better tracking.
- Enhance file validation and storage services for improved security and ownership management.
- Add cron job for cleaning inactive notifications with retention policy.
- Update document worker to handle document generation and storage more efficiently.
- Implement logging improvements in activity and log workers.
- Create comprehensive documentation for new API endpoints and services.
- Add unit tests for file validation and notification policies to ensure robustness.
This commit is contained in:
Sathira Sri Sathara
2026-09-03 14:22:34 +05:30
parent 9d3d431416
commit b6b345f245
54 changed files with 593 additions and 1248 deletions
+2 -1
View File
@@ -16,13 +16,14 @@ const { BullMQAdapter } = require("@bull-board/api/bullMQAdapter");
const activityQueue = require("../queues/activity.queue");
const documentQueue = require("../queues/document.queue");
const logQueue = require("../queues/log.queue");
const emailQueue = require("../queues/email.queue");
const serverAdapter = new ExpressAdapter();
serverAdapter.setBasePath("/admin/queues");
const { addQueue, removeQueue, setQueues, replaceQueues } =
createBullBoard({
queues: [activityQueue, documentQueue, logQueue].map((queue) => new BullMQAdapter(queue)),
queues: [activityQueue, documentQueue, logQueue, emailQueue].map((queue) => new BullMQAdapter(queue)),
serverAdapter,
});
+7
View File
@@ -38,6 +38,13 @@ const envSchema = z.object({
MAIL_PASS: z.string().optional(), MAIL_FROM: z.string().optional(),
AWS_REGION: z.string().optional(), AWS_ACCESS_KEY_ID: z.string().optional(),
AWS_SECRET_ACCESS_KEY: z.string().optional(), AWS_S3_BUCKET_NAME: z.string().optional(),
S3_ENDPOINT: z.string().url().optional(), S3_FORCE_PATH_STYLE: booleanString,
S3_SIGNED_URL_TTL_SECONDS: z.coerce.number().int().min(60).max(86400).default(900),
S3_MAX_UPLOAD_BYTES: z.coerce.number().int().positive().default(5242880),
EMAIL_QUEUE_CONCURRENCY: z.coerce.number().int().positive().default(5),
DOCUMENT_QUEUE_CONCURRENCY: z.coerce.number().int().positive().default(2),
NOTIFICATION_RETENTION_DAYS: z.coerce.number().int().positive().default(90),
LOG_RETENTION_DAYS: z.coerce.number().int().positive().default(30),
DOCS_USER: z.string().optional(), DOCS_PASS: z.string().optional(),
GOOGLE_CLIENT_ID: z.string().optional(), APPLE_CLIENT_ID: z.string().optional(),
}).superRefine((env, context) => {
+2 -1
View File
@@ -1,9 +1,10 @@
const activityQueue = require("../queues/activity.queue");
const documentQueue = require("../queues/document.queue");
const logQueue = require("../queues/log.queue");
const emailQueue = require("../queues/email.queue");
const closeQueues = async () => {
await Promise.allSettled([activityQueue.close(), documentQueue.close(), logQueue.close()]);
await Promise.allSettled([activityQueue.close(), documentQueue.close(), logQueue.close(), emailQueue.close()]);
};
module.exports = { closeQueues };
+2
View File
@@ -7,5 +7,7 @@ module.exports = process.env.ENABLE_S3 === "true"
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
},
...(process.env.S3_ENDPOINT ? { endpoint: process.env.S3_ENDPOINT } : {}),
forcePathStyle: process.env.S3_FORCE_PATH_STYLE === "true",
})
: { send: async () => { throw new Error("S3 functionality is not enabled"); } };