# ZUMRI Current Backend Status Audit date: 2026-09-03 Scope: repository source, configuration, lockfile, existing documentation, safe syntax/test/dependency checks. No database, Redis, S3, email, or other external service was mutated. ## 1. Executive Summary This repository is an early modular-monolith foundation, not yet an e-commerce backend. It contains working-shaped user registration/email verification, OTP login, basic profiles, RBAC tables/controllers, notifications, activity logging, S3 upload plumbing, document generation, Redis/BullMQ workers, and one cron. Important pieces are incomplete or broken in integration. The estimated completion against the 25-module ZUMRI target is **about 12%**. No original development-plan day is fully complete. Day 1 is approximately 55%: Express, Sequelize/MySQL, Redis/BullMQ, a Dockerfile, and a health route exist, but Swagger, robust health checks, Node 22 alignment, production bootstrap/error handling, Compose/Nginx, migrations, and tests do not. Day 2 is approximately 38%; Day 3 approximately 18%; notification/job/file/document/audit foundations from later days were built early. The code still carries prior-project terminology (`Oceanic Titan`, `oceanic-db`, Oceanic demo URL) and role names that conflict with the actual user ENUM. Future work should preserve usable primitives, but first complete and secure foundation/authentication. Status terms: **COMPLETE** = end-to-end implementation is credible from source; **PARTIAL** = meaningful code exists but requirements/integration are incomplete; **STUB** = structure only; **MISSING** = no implementation; **BROKEN** = known source/integration defect. ## 2. Current Architecture - `server.js` loads `.env`, imports `app.js`, and listens on `0.0.0.0:${PORT|3070}`. - `app.js` authenticates Sequelize and calls unrestricted `sequelize.sync()` in an unawaited startup IIFE, then starts cron jobs. The HTTP listener starts independently, so requests can arrive before database readiness, and DB failure does not stop the process. - Middleware order is cookie parser, CORS, JSON parser, Morgan, `/health`, `/api`, static documentation, then Bull Board. There is no URL-encoded parser, request ID, Helmet, compression, rate limiting, global 404 handler, or global error handler. - API base path is `/api` (not versioned). Routes delegate mostly directly to Sequelize-backed controllers; there is only a permission service and activity service. - Redis connections are created at module import. One shared client is used by queues/workers, while password reset and S3 utilities create additional clients. - Workers are a separate `npm run worker` process. The server does not start them. Activity, log, and document consumers exist. - Cron runs in every API process after DB sync; there is no distributed lock, so multi-instance deployments duplicate scheduling. - Sequelize models are registered centrally and their `associate` functions are invoked. No migrations are present. - Environment keys exist locally; `.env` is ignored/untracked. `.env.sample` is tracked. No actual secret values are reproduced here. ### Bootstrap and operational findings | Concern | Status | Evidence / impact | |---|---|---| | Express start and base path | Partial | `server.js`, `app.js`; `/api` and `/health` | | JSON / cookies / CORS / logging | Partial | JSON, cookies, single-origin credentialed CORS, Morgan `dev`; no body-size configuration or URL-encoded parser | | Security middleware | Missing | No Helmet or API rate limiter | | 404/global errors | Missing | Errors depend on individual controllers; unmatched routes use Express defaults | | Database readiness | Broken | Listener is not gated on authenticate/sync; failure is logged only | | Redis readiness | Partial | Event logging exists; health endpoint never checks Redis | | BullMQ/workers | Partial | Separate process required and undocumented operationally; retries only on document jobs | | Cron initialization | Partial | Starts after DB sync, once per server process, with no leader lock | | Health check | Broken | Sends response before asynchronous DB authentication completes and hardcodes mail/Redis as OK | | Graceful shutdown | Missing | No SIGTERM/SIGINT cleanup for server, Sequelize, Redis, workers, or cron | | Process errors | Missing | No `unhandledRejection`/`uncaughtException` policy | ## 3. Existing Infrastructure | Component | Status | Files | Notes | |---|---|---|---| | Express API | Partial | `server.js`, `app.js`, `app/routes/*` | Express 5; no versioning/global errors/security middleware | | MySQL/Sequelize | Partial | `app/config/db.config.js`, `app/models/index.js` | Pool configured; runtime `sync()`, no migrations | | Redis | Partial | `redis.config.js`, `redisClient.js` | Functional client pattern; excessive clients, no shutdown/readiness | | BullMQ | Partial | `app/queues/*`, `app/workers/*` | Three queues and matching consumers; only document jobs have attempts/backoff/retention | | Bull Board | Broken/unsafe | `bullBoard.config.js`, `app.js` | Only activity queue shown; `/admin/queues` has no authentication | | Cron | Partial | `cron/*` | Transactional notification deletion; no distributed lock or retention-age policy | | Email | Partial | `mail.config.js`, `mail.util.js`, templates | SMTP/template sender exists; verifies on import, sends inline, no queue/retry/escaping | | S3 storage | Broken | `s3.config.js`, `s3Upload.utill.js` | S3 client is entirely commented out, so `s3.send` fails | | Uploads | Broken | upload middleware/controller/model | MIME/size checks exist; account guard is incompatible; no magic-byte validation/cleanup/ownership | | Documents | Partial/broken | document controller, logic, templates, queue/worker | PDF/Excel framework is substantive; S3 breaks completion; access is overly broad and role guards mismatch | | Notifications | Partial | notification models/controller/cron | In-app records only; no assignment API/service, email/FCM/preferences/delivery tracking | | Activity/audit | Partial | activity service/model/queue/worker/controller | Async append-only-shaped records; no actor/IP/change metadata, integrity/retention, or broad coverage | | Logging | Partial | console utility/log queue/worker | Local daily files; may receive sensitive payloads; no rotation/structured sink | | API docs | Partial | `Documentation/*`, docs routes | Handwritten Markdown/HTML, not Swagger/OpenAPI; docs auth is forgeable | | Tests | Missing | package script only | Jest finds zero tests; Supertest is not installed | | Docker | Partial | `Dockerfile` | Uses Node 20 instead of target Node 22; API image only; no healthcheck/non-root user | | Nginx/Compose/CI/CD | Missing | none | No reverse proxy, service orchestration, or pipeline files | | Payments/FCM/OpenAI | Missing | none | No dependencies, config, models, or consumers | Queue behavior: `document-generation` has 3 exponential attempts (2s base), completed retention, and retained failures. `activity-queue` and `logQueue` have consumers but no explicit retry/backoff/retention/dead-letter policy and are not idempotent. Re-delivery can duplicate activity rows or log lines. Queue event listeners attached to `Queue` are not a reliable substitute for `QueueEvents` for all lifecycle events. Worker failures are logged only. Document status is not reconciled on job failure/success. ## 4. Existing Database Models All models use timestamps and none uses `paranoid`. Aside from the unique flags noted below, explicit indexes are absent. | Model / table | Key and important fields | Purpose | Important relations | Status | |---|---|---|---|---| | User / `users` | PK string `id`; names, unique email, password, accountType ENUM, accountStatus ENUM, emailVerifiedAt | Identity/account | hasOne Profile; hasMany UserPermission | Partial; no role FK/`roleID` despite service/controller use, no sessions/tokenVersion/social IDs | | Profile / `profiles` | PK `profile_id`; unique `user_id`; theme, notificationsEnabled, image IDs, DOB, phone | Basic preferences/profile | belongsTo User | Partial; no gender/language/address; image IDs lack FKs | | UserActivity / `UserActivity` | integer PK; user/name/description/type/module/date/time | Activity trail | None | Partial; user FK absent, redundant time fields, no indexes | | Upload / `uploads` | integer PK; S3 path/type/size/name/use/uploaded_by | Media metadata | None | Partial; uploader/user and ownership FKs absent | | Permission / `permission` | PK `permission_id`; name/page/module/action | Permission definition | hasMany role/user grants | Partial | | Role / `roles` | PK `role_id`; name/description | Named role | hasMany role grants | Partial; User has no role association | | RolePermission / `rolePermission` | PK `rp_id`; role_id, permission_id | Role grant | belongsTo Role/Permission | Partial; no composite unique constraint | | UserPermission / `userPermission` | integer PK; user_id, permission_id | Direct additive grant | belongsTo User/Permission | Partial; no composite unique; cannot deny/expire grants | | Document / `Document` | PK `doc_id`; reference_no, doc_type, JSON data, status | Saved business documents | None | Partial; status/type unconstrained, no creator/owner/FKs/indexes | | DocumentType / `DocumentType` | integer PK; nullable name, JSON description | Document registry metadata | None | Partial; name is neither required nor unique | | ReferenceNumber / `referenceNumbers` | PK string; unique sequence_key, integer counter, last value | Atomic sequence generation | None | Reusable; transaction/row locking implemented by utility | | Notification / `notification` | PK string; headline/body, USER/ANNOUNCEMENT ENUM, active/date | In-app notification content | hasMany UserNotification as `users` | Partial | | UserNotification / `user_notification` | integer PK; user_id, notification_id, isRead | Per-user notification state | belongsTo User; belongsTo Notification | Partial; constraints disabled, no composite unique/index; include alias is inconsistent (controller asks `notification`, association defines no alias) | Association registration does execute. However, User's `roleID` is not a declared attribute or FK, notifications deliberately disable FK constraints, activities/uploads/documents have no user association, and join-table uniqueness is not enforced. `sequelize.sync()` masks the absence of schema migrations and makes production schema evolution unsafe. ## 5. Existing API Endpoints All paths below are derived from actual mounting. “Self-or-admin” is not implemented anywhere; parameterized user endpoints generally trust the requested ID after coarse account-type checks. | Method | Endpoint | Auth | Permission / guard | Status | Notes | |---|---|---|---|---|---| | GET | `/health` | No | None | Broken | Returns before DB check; Redis/mail are hardcoded OK | | GET | `/api/auth/me` | Yes | None | Partial | Returns token payload plus effective permissions | | POST | `/api/auth/req-otp` | No | None | Partial/unsafe | Password + in-memory OTP; logs OTP; enumeration; no attempts/rate limit/status check | | POST | `/api/auth/login` | No | None | Partial/unsafe | OTP to one-day access cookie; no refresh/session/rotation/status check | | POST | `/api/auth/logout` | No | None | Partial | Clears cookie only; bearer tokens remain valid | | POST | `/api/user` | No | None | Partial/bug | Registration + profile + verification; activity uses undefined `req.user` after commit | | POST | `/api/user/verify-email` | No | None | Partial | Redis one-use hashed token; no resend endpoint | | GET | `/api/user` | Yes | accountType `admin` | Partial | Paginated list | | GET | `/api/user/:id` | Yes | listed legacy types | Broken/IDOR | Most listed types cannot exist; no ownership enforcement | | PATCH | `/api/user/:id` | Yes | listed legacy types | Broken/privilege escalation | Mass updates accountType/undeclared role fields; no ownership/field validation; early returns leak transaction | | DELETE | `/api/user/:id` | Yes | `admin` | Partial | Hard delete; related profile handling depends on DB state; early return leaks transaction | | GET | `/api/activity` | Yes | `admin` | Partial | Full audit list, no pagination | | GET | `/api/activity/user/:userId` | Yes | `admin` | Partial | No paging/index | | POST | `/api/upload` | Yes | `admin` or nonexistent `staff` | Broken | S3 client undefined; DB requires `use_for`; upload not transactional | | GET | `/api/upload/signed-url/:id` | Yes | `admin` or nonexistent `staff` | Broken | S3 undefined; catch sends no response; no ownership check | | GET | `/api/document/types` | Yes | admin or nonexistent legacy types | Partial | Effectively admin-only under current ENUM | | POST | `/api/document/saved` | Yes | same | Partial | Body filter on a read operation; no owner/pagination; Sequelize `exclude` placed incorrectly | | POST | `/api/document/generate` | Yes | same | Broken | Queues correctly, but worker S3 upload fails; validation shallow | | POST | `/api/document/draft` | Yes | same | Partial | Saves arbitrary JSON; no ownership/validation | | GET | `/api/document/reference-number/:documentType` | Yes | same | Partial | Consumes sequence on GET | | GET | `/api/document/job/:jobId/status` | Yes | same | Partial/IDOR | Exposes stacktrace and any job by ID | | GET | `/api/document/download/:uuid` | Yes | same | Broken/unsafe | S3 undefined; deletes shared object after response; no ownership | | DELETE | `/api/document/job/:jobId` | Yes | same | Partial/IDOR | Any allowed user can remove any removable job | | GET | `/api/document/:docId` | Yes | same | Partial/IDOR | Arbitrary document access | | POST | `/api/docs/login` | No | Static credentials | Unsafe | Sets unsigned boolean cookie; no expiry/rate limiting | | POST | `/api/docs/logout` | No | None | Partial | Clears cookie | | GET | `/api/docs/markdown-files` | docs cookie | `docsAuth === "true"` | Unsafe | Cookie can be forged by client | | GET | `/api/docs/view/:file` | docs cookie | same | Partial | Extension/path checks; auth is weak | | POST | `/api/profile/req-reset-password` | No | None | Partial/unsafe logging | Enumeration-resistant response; raw reset token is logged | | POST | `/api/profile/reset-password` | No | None | Partial | Hashed one-use Redis token; new password is not policy-validated | | POST | `/api/profile/change-password` | Yes | legacy account types | Broken/partial | Effectively admin-only; no new-password validation/session revocation | | GET | `/api/profile/avatar/:userId` | Yes | legacy account types | Broken | S3 undefined, missing upload null check, wrong `profile.userId` property, IDOR | | GET | `/api/profile/background/:userId` | Yes | legacy account types | Broken | Same issues | | POST | `/api/notification` | Yes | admin or nonexistent `management` | Partial | Creates content only; no user assignment | | GET | `/api/notification/announcements` | Yes | legacy account types | Partial | Effectively admin-only | | GET | `/api/notification/user/:userId` | Yes | legacy account types | Broken/IDOR | Include alias mismatch likely throws; no ownership | | PATCH | `/api/notification/user/:userId/notification/:notificationId/read` | Yes | legacy account types | Broken/IDOR | No ownership; effectively admin-only | | ALL | `/admin/queues/*` | No | None | Unsafe | Bull Board exposed; only activity queue registered | | GET | `/Documentation/*` | No | Blocks `.md` only | Partial | Static HTML documentation is public | ### Defined but unreachable permission routes `app/routes/permission.routes.js` defines 18 endpoints under the intended permission router (permission CRUD/bulk; role CRUD and grants; user grants CRUD/bulk), but `app/routes/index.js` imports `permissionRoutes` and never calls `router.use(...)`. Therefore none has an actual URL and all are **BROKEN/unreachable**. If mounted as `/permission`, their paths would be `/`, `/bulk`, `/:permissionId`, `/roles`, `/roles/:roleId`, `/roles/:roleId/permissions`, `/roles/permissions/bulk`, `/users/:userId/permissions`, `/users/permissions`, `/users/permissions/bulk`, and `/users/permissions/:upId` with the methods declared in that file. Read endpoints require authentication; mutations require accountType exactly `admin`. Controllers are substantial CRUD logic, but integration, uniqueness, cache invalidation, validation, and transactions are inconsistent. ## 6. Development Plan Status | Module | Completion | Status | Evidence | Remaining Work | |---|---:|---|---|---| | 01 Authentication & Authorization | 38% | Partial | Password hashing, register/verify, OTP access JWT, middleware, RBAC structures | Refresh/session lifecycle, OAuth/Apple, durable OTP/limits, status enforcement, role linkage, mount/fix RBAC | | 02 Customer Profile & Address Management | 22% | Foundation | User/Profile with phone, DOB, images/preferences | Self-service ownership, addresses/default, gender/language, deactivation, robust image flow | | 03 Product Catalogue Management | 0% | Missing | No models/routes | Full catalogue/category/variant/review/SEO model and APIs | | 04 Multi-Language Content | 0% | Missing | No content translation system | Locale strategy and translated content | | 05 Inventory Management | 0% | Missing | No inventory entities | Stock, reservations, warehouses, adjustments | | 06 Cart & Wishlist | 0% | Missing | None | Entire module | | 07 Promotions, Coupons & Banners | 0% | Missing | None | Entire module | | 08 Checkout | 0% | Missing | None | Pricing/shipping/tax/transaction orchestration | | 09 Order Management | 0% | Missing | Document names are not commerce orders | Full order state machine and returns | | 10 Payment Management | 0% | Missing | No provider code/dependencies | PayHere/Stripe, webhooks, idempotency, refunds | | 11 Delivery & Rider Management | 2% | Foundation only | `rider` account ENUM; document templates named delivery/dispatch | Rider profiles, assignments, tracking, zones/rates | | 12 Loyalty, Reward Points & Membership | 0% | Missing | None | Ledger, tiers, generic earn rules, rewards/vouchers | | 13 Wholesale / Business Accounts | 2% | Foundation only | `business_customer` ENUM only | Approval/profile/pricing/MOQ/tiers/credit/settlements/invoices/analytics | | 14 Notification System | 28% | Partial | Notification/user join models, CRUD/read endpoints, cleanup cron, mail utility | Fix aliases/ownership; assignment and preferences; FCM/email jobs/templates/status | | 15 Support Ticket System | 0% | Missing | None | Tickets, messages, SLA/escalation/help center | | 16 AI Customer Support Chatbot | 0% | Missing | No OpenAI integration | Conversations, tools, safety, human escalation | | 17 Product Recommendations | 0% | Missing | None | Events and recommendation service | | 18 Admin Dashboard & Analytics | 1% | Foundation | Admin user type and raw activity endpoint | Metrics, aggregation, secured dashboard APIs | | 19 File & Media Management | 25% | Broken foundation | Multer, Upload model, S3/presigned utilities | Restore/configure client, ownership, object validation/lifecycle, media transformations | | 20 Audit Logging & System Configuration | 22% | Partial | Async activity records/log queue | Full audit schema/coverage, immutability, config models, secure structured logging | | 21 Background Jobs & Queues | 35% | Partial | Redis, 3 queues/consumers, worker entry, document retry | Idempotency, policies for every queue, monitoring auth, graceful shutdown, scheduler topology | | 22 Security | 15% | Weak foundation | bcrypt, JWT verification, HttpOnly cookie, basic MIME limits | Findings in §10; headers, throttles, validation, authorization, secrets/token discipline | | 23 Testing & Quality Assurance | 2% | Missing | Jest dependency/script only | Tests, Supertest, fixtures, lint/type/static checks, CI | | 24 API Documentation | 18% | Partial | Handwritten endpoint Markdown/HTML | OpenAPI/Swagger, synchronization, schemas/security/error contracts | | 25 Deployment & Infrastructure | 18% | Partial | Dockerfile | Node 22, Compose, Nginx, healthcheck, non-root, migrations, CI/CD, observability | ## 7. Original 15-Day Plan Status | Day | Intended Scope | Completion | Notes | |---|---|---:|---| | 1 | Foundation | 55% | Express/Sequelize/MySQL/Redis/BullMQ/Docker present; health broken; Swagger/Compose/migrations/production lifecycle missing | | 2 | Authentication | 38% | Basic verified registration and OTP access JWT; core session/OAuth/security requirements incomplete | | 3 | Customer + business accounts | 18% | Basic user/profile and enum only; no addresses/business domain | | 4 | Products/categories/variants | 0% | Missing | | 5 | Inventory/admin products | 0% | Missing | | 6 | Cart/wishlist | 0% | Missing | | 7 | Promotions/checkout | 0% | Missing | | 8 | Orders | 0% | Missing | | 9 | Payments | 0% | Missing | | 10 | Delivery/rider | 2% | Rider enum and unrelated document templates only | | 11 | Loyalty | 0% | Missing | | 12 | Notifications/support | 16% | Partial in-app notification foundation; support absent | | 13 | AI/recommendations | 0% | Missing | | 14 | Analytics/security | 8% | Raw activities and scattered security controls only | | 15 | QA/production | 5% | Dockerfile only; no tests/CI/Nginx/production hardening | **Last genuinely complete day: none.** Development reached partway through Day 1 and Day 2, with selected infrastructure from Days 12, 14, and 15 implemented early. ## 8. Demo Website Requirement Gaps | Feature | Present on Demo | Present Backend | Original Plan | Action Needed | |---|---|---|---|---| | Email/password login | Yes | Partial (password then email OTP) | Auth | Clarify desired login flow; secure OTP/session lifecycle | | Remember me | Yes | No | Auth | Add session-specific lifetime safely | | Forgot/reset password | Yes | Partial | Auth | Stop token logging, validate password, revoke sessions | | Google sign-in | Yes | No | Auth | Add provider verification/linking | | Apple sign-in | Yes | No | Potential added requirement | Add to auth scope explicitly | | Account overview/recent orders/counts | Yes | No | Customer/orders | Aggregate dashboard endpoint after domain models | | Points/vouchers/membership/progress | Yes | No | Loyalty | Ledger, tier/rule/reward architecture | | Default address/profile/addresses | Yes | Profile partial; addresses absent | Customer | Ownership-safe profile and address CRUD/default constraint | | Wishlist/order history/sign out | Yes | Sign-out cookie only; rest absent | Cart/orders/auth | Implement modules and true session revocation | | Silver/Gold/Platinum tiers/benefits | Yes | No | Loyalty | Configurable tiers; do not hardcode demo examples | | Point transaction history | Yes | No | Loyalty | Immutable ledger | | Purchases/reviews/referrals/birthdays earning | Yes | No | Loyalty/reviews | Generic earn-source rules with idempotency | | Reward redemption/vouchers/shipping rewards | Yes | No | Loyalty/promotions | Reward definitions, redemption transaction, vouchers | | Business approval/Partner ID/tier | Yes | Account enum only | Wholesale | Business profile and approval workflow | | Monthly/history/discount/top buyers/orders | Yes | No | Wholesale/analytics | Wholesale aggregates and reporting | | Credit limit/available/utilization | Yes | No | Wholesale | Credit account/ledger and authorization rules | | Settlement terms/dates/invoices | Yes | No | Wholesale/payment | Terms, statements, invoice/payment lifecycle | | Wholesale catalogue/MOQ/pricing tiers/bulk | Yes | No | Wholesale/catalogue | Customer-segment pricing and volume tiers | | Featured inventory/reorder | Yes | No | Inventory/wholesale | Stock and reorder workflows | | Shipping thresholds/methods/zones/fees | Yes | No | Checkout/delivery | Configurable rate engine | | International shipping/duties display | Yes | No | Delivery/checkout | Destination rules and duty estimate representation | | Order tracking | Yes | No | Orders/delivery | Shipment event timeline | | 30-day return/eligibility/reason/status | Yes | No | Orders (gap detail) | Configurable returns/RMA state machine | | Pickup/refund/exchange | Yes | No | Delivery/payment/orders | Integrate RMA, courier, payment refund, exchange order | | Help center/FAQs/sizing/payment help | Yes | No | Support/content | CMS/help content APIs | | Email support/tickets | Yes | No | Support | Ticket/conversation/SLA module | | AI Style Assistant/human escalation | Yes | No | AI/support | AI conversation with ticket/advisor handoff | | Newsletter consent lifecycle | Yes | No | Demo gap | Dedicated subscriber consent/status/source/language model; not profile notification preference | | New/featured/sale products | Yes | No | Catalogue/promotions | Merchandising fields/rules | | Category/editorial collections | Yes | No | Catalogue/content | Collections and ordered merchandising | | Related products | Yes | No | Recommendations/catalogue | Explicit and computed relations | | Reviews/verified purchase reviews | Yes | No | Catalogue/recommendations | Review moderation and verified-order link | | Size guides | Yes | No | Catalogue/content | Structured, category/product-linked guides | | Product SEO | Yes | No | Catalogue | Slugs/meta/canonical data | | Banners | Yes | No | Promotions | Placement, locale, schedule, targeting | | Multiple languages | Yes | No | Multi-language | Localized product/content model | Current order/delivery architecture cannot support shipping or returns: no commerce Order, OrderItem, Shipment, Address, Return, Refund, or state-transition entities exist. The similarly named generated documents are generic JSON documents and should not be treated as domain substitutes. ## 9. Technical Debt ### CRITICAL - Restore a valid S3 client before any upload/document endpoint can work. - Align authorization vocabulary and enforce ownership; current legacy guards, IDORs, and accountType mutation enable denial of access or privilege escalation. - Remove raw OTP/reset-token and decoded-auth logging; rotate any credentials if operational logs captured them. - Replace production `sequelize.sync()` with migrations and gate server readiness on required services. - Implement a real access/refresh session model with rotation, revocation, account-status enforcement, and secure logout. ### HIGH - Mount and repair permission routes; add User-role linkage and grant uniqueness/cache invalidation. - Add validation schemas and centralized error handling; prevent arbitrary field updates. - Protect Bull Board and documentation sessions. - Fix notification association alias and user ownership checks. - Add rate limits for login, OTP, verification, reset, docs login, and general API traffic. - Add tests for auth/authorization, transactions, uploads/jobs, and failure paths. - Fix transaction leaks on early returns in user update/delete. ### MEDIUM - Standardize response/error formats and status codes; stop returning internal error messages/stack traces. - Consolidate Redis connections and add lifecycle/readiness handling. - Make jobs idempotent and add retry/backoff/retention/dead-letter/alert policies. - Move email to a job and add retry/delivery tracking and safe template escaping. - Add pagination/indexes to activity, notification, document, and user queries. - Remove legacy Oceanic naming and reconcile API versioning. ### LOW - Correct mojibake in source/log messages, inconsistent singular/plural table names, and `*.utill.js` spelling. - Remove unused imports/constants and dead/commented code. - Split giant permission controller and move business logic into services after behavior is tested. ## 10. Security Findings - No tracked `.env` was detected. `.env.sample` is tracked. Potential secret-bearing configuration exists in local `.env`; values were not inspected/reproduced. If this file has ever been shared or committed elsewhere, rotate credentials. - JWT falls back to a public placeholder secret if configuration is missing. There is no issuer/audience/session ID/tokenVersion or refresh-token revocation. - Login OTP uses `Math.random`, process memory, and no attempt/rate limit; it fails across instances/restarts and is logged in plaintext. - Password reset token is logged in plaintext. Reset/change paths do not validate the new password policy or revoke existing access tokens. - Login does not reject pending, suspended, or deactivated accounts. - User update allows coarse-authorized callers to target arbitrary IDs and set `accountType`, a privilege-escalation and IDOR risk. Many profile/notification/document endpoints have the same ownership defect. - Bull Board is public. Docs protection is an unsigned client cookie equal to `true`; credentials are brute-forceable without rate limiting. - CORS is a single credentialed origin and cookie flags are reasonable for cross-site production, but CSRF protection/origin validation is absent for cookie-authenticated mutations. - Multer limits size and declared MIME, but image wildcard acceptance lacks content sniffing, image decompression safeguards, antivirus scanning, extension normalization policy, and object lifecycle cleanup. - S3 `PutObject` sets no ACL (good default if bucket blocks public access), but actual bucket policy/encryption cannot be verified. Signed URLs are cached; authorization is checked only before URL issuance and ownership is not checked. - Controllers expose `error.message`; job status exposes stack traces. Production Sequelize logging is inverted to `true`, which can leak query data. - Request validation is handwritten and sparse; mass assignment exists in user update. Sequelize query values are generally parameterized, so no direct raw-SQL injection was found. - Foreign-key constraints are disabled for notification joins; missing uniqueness and transactions create races/duplicates in grants and notifications. - No Helmet, API rate limiting, CSRF strategy, audit integrity, session revocation, or centralized security error policy exists. ## 11. Broken / Suspicious Implementations - `app/config/s3.config.js`: the entire client/export is commented; every S3 caller receives `{}`. - `app/routes/index.js`: imports `permissionRoutes` but never mounts it. - `app/utils/documentJob.util.js`: requires nonexistent `../queues/pdf.queue`; currently appears orphaned. - `app/services/permission.service.js#getEffectivePermissions`: queries `user.roleID`, which is not a User model attribute; role grants cannot reliably apply. - `app/routes/{user,profile,document,notification}.routes.js`: guards use `management`, `team_head`, `user`, or `staff`, none of which is in the User ENUM. Valid `manager`, `customer`, `business_customer`, `rider`, `support_agent`, and `superadmin` are largely excluded. - `user.controller#createNewUser`: calls `logActivity({user: req.user})` on a public route, causing a post-commit exception after the account has been created; client may receive 500 and retry. - `user.controller#updateUser`: accepts accountType and undeclared role/department fields; does not update email despite destructuring it; opens transaction before lookups and does not roll back early 404 responses. - `user.controller#deleteUser`: early 404 does not roll back; hard delete may conflict with Profile because cascade is unspecified. - `profile.controller#getProfileAvatar/getProfileBackgroundImage`: assumes upload exists, uses wrong `profile.userId` response property, lacks ownership, and reaches broken S3. - `upload.controller#getFileUrl`: empty catch block can leave requests hanging. - `notification.controller#getUserNotifications`: requests association alias `notification`, but `belongsTo` defines no alias; likely Sequelize eager-loading error. - `notification.controller`: USER notifications are created but never assigned to users through an endpoint/service. - `app.js#/health`: asynchronous DB result races with response; reports `N/A`/hardcoded OK rather than real readiness. - `app.js` bootstrap: server listens before DB boot finishes; DB errors are swallowed; each instance starts cron. - `app/middleware/permission.middleware.js`: unused `hasPermission`; admin bypass only recognizes `admin`, not `superadmin`; wildcard logic differs between helper and actual check. - `docsSession.middleware.js`: trusts an unsigned, client-set boolean cookie. - `document.controller#getSavedDocuments`: `exclude` is not nested under `attributes`, so JSON data may still be fetched; filter is in POST body despite message saying query parameter. - `document.controller#downloadDocument`: destructive read deletes the object after delivery and lacks job/user ownership. - `app/logic/documents/registry.js`: catches module load failure but still registers undefined functions, deferring failure to runtime. - `consoleLog.utill.js` and auth/reset utilities: log pipelines may persist secrets and full error objects. - Production DB logging is enabled while non-production logging is disabled, likely inverted. Orphaned or unused-looking code includes `documentJob.util.js`, `notification.utill.js` (empty), `logic/documents/engine/pdf.engine.js` (generation uses `pdfGenerator.js`), several Excel/id/vendor/calendar/basis utilities not referenced by mounted features, `Assets` in upload controller (unregistered), imported `PERMISSIONS`/`checkPermission` in routes where checks are absent/commented, and unused dependencies likely including `pdfmake` and `nodeman`. `nodemon` is incorrectly a production dependency. Static analysis cannot prove every dynamic/template use; confirm before removal. ## 12. Reusable Existing Components - Sequelize model registry/association convention can be extended after migrations replace runtime sync. - User/Profile registration transaction, bcrypt utility, hashed one-use email verification token, and hashed password-reset-token concepts are sound foundations once error/logging/session issues are fixed. - Cookie-or-Bearer authentication middleware structure is reusable after it loads current user/session/status and applies token claims. - Permission, role, role-grant, and user-grant models/controllers/service are worth repairing rather than rebuilding; add role linkage, constraints, mounting, validation, and cache invalidation. - Shared Redis factory/client and permission/user cache helpers can be consolidated and retained. - Activity queue/service/worker is a useful async audit foundation; extend its schema and coverage. - BullMQ worker entry pattern and document queue retry/backoff settings are reusable; standardize them across queues. - Upload metadata model, Multer memory-storage limits, S3 key generation, and presigned URL caching are reusable after the S3 client and authorization/content validation are fixed. - Document registry, PDF/Excel generators, templates, queue/worker, Document/DocumentType models, and atomic reference-number generator are substantive reusable subsystems. They are auxiliary business-document infrastructure, not order/payment replacements. - Notification/UserNotification models, read-state concept, announcement query, and transactional cleanup cron can be repaired and extended for channel delivery. - Email transport/template system and existing verification/reset/welcome templates can be moved behind an email queue. ## 13. Recommended Next Development Phase Continue with a **Foundation, security, and authentication completion phase** before starting catalogue work. First make startup deterministic and production-safe: Node 22 alignment, validated environment configuration, migrations, real readiness/liveness checks, global 404/errors, Helmet/rate limits, protected operations dashboards, graceful shutdown, and a test harness. Then complete identity: Redis-backed cryptographic OTP with limits, account-status checks, access/refresh sessions with rotation/revocation, secure logout/reset, validation, ownership rules, and a repaired/mounted role-permission system. Repair S3 only as part of restoring already-promised profile/media/document behavior. After that baseline passes integration tests, finish customer/business profile and address primitives, reusing User/Profile, auth middleware, Redis, permission service, upload system, activity logger, email templates, queues, and reference-number utility. Only then begin catalogue/product models. ## 14. Recommended Updated Roadmap 1. **Phase 0 — Stabilize foundation:** Node 22, env validation, migrations, startup/readiness, global errors/security middleware, graceful shutdown, protected Bull Board, baseline Jest/Supertest and CI. 2. **Phase 1 — Complete identity and authorization:** OTP/session/refresh rotation, status checks, logout/revocation, password recovery hardening, OAuth Google/Apple, ownership rules, repaired roles/permissions. 3. **Phase 2 — Repair existing cross-cutting services:** S3/media, email jobs, notification aliases/assignment, queue reliability/idempotency, audit schema, document ownership and job lifecycle. 4. **Phase 3 — Customer and business foundations:** Profile completion, addresses/defaults, preferences/deactivation, business approval/partner identity/credit and settlement primitives. 5. **Phase 4 — Catalogue/content:** Categories, products, variants, media, localized content, SEO, size guides, collections, reviews. 6. **Phase 5 — Inventory and merchandising:** Warehouses/stock/reservations, wholesale pricing/MOQ/volume tiers, banners/promotions/coupons. 7. **Phase 6 — Shopping and checkout:** Cart, wishlist, pricing, shipping zones/rates/duties, checkout transactions. 8. **Phase 7 — Orders/payments:** Order state machine, PayHere/Stripe webhook idempotency, invoices, refunds, returns/exchanges. 9. **Phase 8 — Delivery/rider:** Assignments, tracking events, pickup/return logistics. 10. **Phase 9 — Loyalty and wholesale completion:** Generic earn ledger, tiers, rewards/vouchers/referrals; credit utilization/settlements/analytics. 11. **Phase 10 — Support/AI/recommendations:** Help content, tickets/SLA, advisor escalation, AI assistant, recommendation events/services. 12. **Phase 11 — Analytics and production QA:** Dashboards, security testing, load/integration/e2e tests, observability, Nginx/Compose/deployment/runbooks. ## 15. Do Not Rebuild List Preserve and extend these concepts/files after adding tests: centralized Sequelize registration; User/Profile base tables; bcrypt helper; Redis connection/cache helpers; email verification/password-reset token hashing; auth middleware extraction of cookie/Bearer tokens; RBAC model/controller foundation; activity queue/service/worker; document registry/generators/templates/queue/worker; reference-number sequencing; Upload metadata/Multer limits/S3 utility interface; Notification/UserNotification read-state model; cleanup cron transaction; mail templates/transport interface; Docker Chromium setup for Puppeteer. ## Verification and Dependency Audit - `node --check` passed for every repository JavaScript file. - `npm test -- --runInBand` failed because Jest found **0 tests**. - `npm ls --depth=0` completed without reporting missing installed top-level packages. - `npm audit --omit=dev` reported **28 production dependency vulnerabilities**: 19 high, 8 moderate, 1 low, 0 critical. Dependency upgrades were intentionally not performed. - Broken local import scan found active-looking `documentJob.util.js -> ../queues/pdf.queue`; the commented future `email.worker` reference is not an active defect. - Targeted dependency observations: Supertest, Swagger/OpenAPI tooling, Helmet, rate limiting, FCM, payment SDKs, and OpenAI SDK are missing. `nodemon` should be dev-only; `nodeman` and `pdfmake` appear unused. Confirm with runtime coverage before removal.